Windows编程原理及自己动手写计算器

本文介绍了Windows编程中的消息机制,通过实例展示了如何响应用户操作,并探讨了如何使用控件进行简单计算。

 板书:
1、在编写控制台程序的时候一切流程都是有先后关系、并行的,而且所有函数都是由我们来调用的,比如下面的实例性代码:
printf("确定请输入y,取消输入n");
char c = getchar();
if(c=='y')
{

///

}
else if(c=='n')
{

///

}

我们可以用getchar来等待用户输入一个值。但是到了Windows编程中就不一样了,同一时刻用户即可能点击【OK】按钮,又可能点击【Cancel】按钮,又可能在文本框中输入几个字,还可能在窗口上双击几下,这样就无法同时等待用户的这些动作。为了解决这个问题,Windows引入了消息机制(也可以叫做回调机制或者事件机制)。在程序启动的时候把函数func1要响应【OK】按钮1的点击动作、函数func2要响应【Cancel】按钮的点击动作、函数func3要响应窗口的双击动作等等这些信息告诉Windows,然后当用户执行相应操作的时候Windows就会来主动调用你注册的函数,主动通知你。不再是程序调用操作系统的函数,而是操作系统反过来调用你的函数。Don't call me ,I'll call you!(也被人称为“好莱坞法则”)。
2、关于上面的这个问题要慢慢来理解,下面就来通过第一个例子来初步理解这个Don't call me ,I'll call you!
创建一个对话框程序,然后来分析代码。看Main_OnCommand方法,初探windows的消息机制。
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{

switch(id)


{


case IDC_OK:


MessageBox(hwnd,"You click OK!","Test003",MB_OK);


EndDialog(hwnd, id);


break;


case IDC_CANCEL:


MessageBox(hwnd,"You click Cancel!","Test003",MB_OK);


EndDialog(hwnd, id);


break;


default:break;


}

}
按钮被按下的时候Main_OnCommand方法被调用,hwnd是对话框句柄(什么是句柄后面讲,通俗的说就是通过它能够操纵对话框),id是控件的id,后两个参数暂时不关心。
Main_OnCommand方法中根据id,也就是被点击按钮的名字来决定不同的动作,EndDialog用来关闭对话框。
3、定制自己的对话框,向世界问好
首先打开资源编辑器并且打开对话框IDD_MAIN,然后删除对话框上的两个按钮和标签,同时删除main.cpp中的两个Case语句变成:
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{

switch(id)


{


default:break;


}

}
然后重新添加一个自己的按钮,在属性中修改Name属性为IDC_BTNHELLO
控件名字的潜规则:所有控件的Name都以“IDC_”开头,然后后边跟着控件类型的简称(按钮简称BTN、文本框简称EDT等等),最后才是控件的真正的名字。修改按钮的Caption属性(也就是按钮上显示的文字)为“问好”。

在代码中怎么得到IDC_BTNHELLO呢?刚才被删掉的IDC_OK是什么东东呢?回忆配置ResEd的时候配置的“名称输出格式”和“默认输出文件名”以及“保存时自动输出”。每次保存对话框的时候ResEd都会帮我们把控件的名字输出到rsrc.inc文件中,打开工程文件夹下的rsrc.inc,内容如下:
#define IDC_BTNHELLO
1001


Dialog编辑器会自动递增id的取值。然后生成rsrc.inc,其实就是h头文件,取这些定义的时候要先include这个inc文件。可以看到rsrc.inc文件中就是这些控件名字的定义,使用的时候只要include这些文件就可以。“rsrc.inc”和头文件一样。因此首先在main.cpp中添加“#include "rsrc.inc"

编辑Main_OnCommand方法:
void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{

switch(id)


{



case IDC_BTNHELLO:



MessageBox(NULL,TEXT("
世界你好"),TEXT("问好"),MB_OK);


break;


default:break;


}

}

运行程序,点击“问好”按钮,咱们第一个响应按钮动作的程序就做好了。
4、自己动手写计算器1.0
1)、得到控件中用户输入的文本
GetDlgItemText(hwnd,IDC_EDTNAME,str,sizeof(str));
第一个参数是对话框的句柄;第二参数就是控件的idname);第三个参数就是字符串数组的指针;
疑问:为什么不能像MessageBox一样把字符串做为返回值返回呢???
这就涉及到C语言中函数返回指针的问题了
int i=20;
char cStr[3];
itoa(i,cStr,10);

char* f1()
{

return "adsfadsfasd";

}

在函数内部返回函数内构建的指针有可能出现数据混乱.
f1函数在执行的时候,这段内存是被占用的,一旦函数返回,那么内存就标记为可以被其他人、函数占用。
如果你把这段内存中的指针返回了,那么一旦其他地方用了这段内存,那么你引用的就是错误的数据了。
GetWindowTextGetDlgItemText的时候为什么要传数组名呢?复习:数组名就是指针,函数只有得到指针,才能直接操作数组中的数据。
2c语言中字符串连接:strcat(name,"你好");
但是在编写windows程序的时候最好使用lstrcat代替strcat
lstrcat(name,"你好");
同样代替的有:strlenlstrlenstrcmplstrcmp
3)向用户问好


TCHAR name[256];



GetDlgItemText(hwnd,IDC_EDTNAME,name,sizeof(name)/sizeof(TCHAR));



lstrcat(name,"
你好");


MessageBox(NULL,name,TEXT("
问好"),MB_OK);
4
C语言里边字符串转换为数字:atoiascii to int
5

编写windows程序的时候最好用TCHAR来代替char,可以避免中文的问题


case IDC_BTNHELLO:



TCHAR name[256];



GetDlgItemText(hwnd,IDC_EDTNAME,name,sizeof(name)/sizeof(TCHAR));



int i = atoi(name);



int j=i*2;



TCHAR result[256];



itoa(j,result,10);






MessageBox(NULL,result,TEXT("
问好"),MB_OK);
6GetSet:配对的,设置对话框的值用SetDlgItemText
代码:


case IDC_BTNADD:



//
取第一个文本框的字符串,然后得到整数表示

//
取第二个文本框的字符串,然后得到整数表示

//
计算两个整数的和

//
把和重新转换成字符串,然后Messagebox出来。

TCHAR cNumber1[256];


GetDlgItemText(hwnd,IDC_EDTNUM1,cNumber1,sizeof(cNumber1)/sizeof(TCHAR));


int n1 = atoi(cNumber1);


TCHAR cNumber2[256];


GetDlgItemText(hwnd,IDC_EDTNUM2,cNumber2,sizeof(cNumber2)/sizeof(TCHAR));


int n2 = atoi(cNumber2);


int n3 = n1+n2;


TCHAR cResult[256];


itoa(n3,cResult,10);


SetDlgItemText(hwnd,IDC_EDTRESULT, cResult);



break;

7代码中有UINTTCHARLRESULTHWND之类的新的数据类型,其实它们只是一些类型的别名而已,可以通过宏定义看出来。但是考虑到可移植性,尽量不要使用它们的真实类型
8)思考:这个计算两个数的和程序有什么缺陷?没有阻止用户输入非数字
9)作业:做一个面积计算器,用户输入半径,在另外一个文本框中显示面积。
5、得到系统中有哪些逻辑驱动器
DWORD GetLogicalDrives(VOID);
返回值的二进制位标志着存在哪些驱动器。其中,位0设为1表示驱动器A存在于系统中;位1设为1表示存在B驱动器;以次类推。
比如:
00001100:有C盘,D
000011100cde
1101A(软驱)、CD
1)写程序中的错误排除
"dwDrives"was not declared in the scope
declare:声明;scope:范围
"dwDrives"没有被声明在这个范围内。
2)以二进制显示GetLogicalDrives的返回值:

stdlib.h



DWORD ds = GetLogicalDrives();


char str[33];


itoa(ds,str,2);


MessageBox(NULL,str,"",MB_OK);


DWORD
是什么类型?在DWORD上点击右键,选择“转到DWORD的定义”,其实DWORD是“unsigned long”。因此str定义成33位(还有最后一位的“/0”)。
3)课后习题:判断是否存在D盘。
4)课后习题:依次显示系统中所有的盘符。比如显示出“CDEF”。
5)课后习题:显示系统中有多少个逻辑驱动器。
这三道课后作业都是在锻炼位运算。一定要重视,不要一位没啥意思,很多公司的笔试面试都会考查这一点,这也是继续深入研究C和其他语言的基础。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值