学了更多底层的消息机制,先简单总结一下这一个小任务:从当一个按钮按下,从窗口的某个小控件(对系统来说,是一个小/子窗口)获取文本并处理后输出到另一个文本中(以做乘法为例子)。
首先定义全局的控件ID,唯一标识某个控件。这里用一个枚举类,省一点赋值的功夫。
并且声明一些全局的HWND句柄,用来标记我们创建出来的控件
(当然后文会介绍不用声明全局句柄的方法,直接用ID标识码获得小控件)
HWND hMainWnd, hwndPush, hwndDefPush, hwndRadio, hwndEdit1, hwndEdit2, hwndEdit3, hwndStatic1, hwndStatic2, hwndStatic3;
接下来在WndProc处理WM_CREATE消息时(说明正在内存中创建主窗口),
添加自定义处理,用来绘制一个按钮、三个编辑框、三个静态字符文本,绘制接口可以套用:
case WM_CREATE: {
int X = 100, Y = 200;
int wid = 80, hit = 20;
hwndPush = CreateWindow("BUTTON", "计算", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
X+80, Y-20, 240, 25, hWnd, (HMENU)BS_PUSHBUTTON1, hInst, NULL);
hwndEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
"EDIT", "0", WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,
X + wid, Y + hit, wid, hit, hWnd, (HMENU)ID_EDIT1, hInst, NULL);
hwndEdit2 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
"EDIT", "0", WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,
X + wid*2, Y + hit, wid, hit, hWnd, (HMENU)ID_EDIT2, hInst, NULL);
hwndEdit3 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
"EDIT", "0", WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,
X + wid*3, Y + hit, wid, hit, hWnd, (HMENU)ID_EDIT3, hInst, NULL);
hwndStatic1 = CreateWindow("STATIC", "乘数",
WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY,
X + wid, Y + hit*3,
wid, hit,
hWnd, (HMENU)ID_STATIC1, hInst, NULL);
hwndStatic2 = CreateWindow("STATIC", "乘数",
WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY,
X + wid*2, Y + hit * 3,
wid, hit,
hWnd, (HMENU)ID_STATIC2, hInst, NULL);
hwndStatic3 = CreateWindow("STATIC", "答案",
WS_CHILD | WS_VISIBLE | WS_BORDER | SS_NOTIFY,
X + wid*3, Y + hit * 3,
wid, hit,
hWnd, (HMENU)ID_STATIC3, hInst, NULL);
}break;
运行看看效果
(黏贴中文字符串可能会爆红线,在属性里改成多字节字符集)
成功。
这里要介绍WndProc中的WM_COMMOND机制,点击菜单, 点击加速键,点击子窗口按钮,点击工具栏按钮,这些时候都有command消息产生。
所以我们在WndProc中对WM_COMMOND添加消息处理即可:
Case BS_PUSHBUTTON 就是我们自定义的消息处理,其中包含了从窗口控件中读取文本和输入文本的接口使用,可以套用。
case BS_PUSHBUTTON1:
{
char num1[10], num2[10]; char num3[10];
GetWindowText(hwndEdit1, num1, 10);
GetWindowText(hwndEdit2, num2, 10);
int x, y, z;
x = atoi(num1);
y = atoi(num2);
z = x * y;
wsprintf(num3, "%d", z);
SetWindowText(hwndEdit3, num3);
}break;
下面我们想通过主窗口的消息处理,动态新建一个新对话框,在这个对话框里面实现上述功能。
我们不妨先研究一下VS帮我们自动生成的About窗口。
它在主程序的WndProc的WM_COMMAND命令下由DialogBox接口创建出来。
注意最后一个参数About是回调函数指针,表示这个窗口用的消息机制是About()函数:
这个函数很简单,只有WM_COMMAND命令指定了,当wParam参数(也就是按下等操作触发的控件ID)是IDOK或IDCANCEL(自动生成的对话框就只有这俩按钮,右上角红叉叉也是)时,调用关闭Dialog的函数。
因此知道工作流程后,我们进入资源编辑窗口,用(视图-工具箱Ctrl-ALT-x)工具箱对“关于”对话框做一点修改:
三个EditCtrl两个静态文本一个按钮
各自在属性中指定一个唯一的ID标识码。为按钮也指定一个。
接下来回到About函数中进行编辑:
这里红线是误报,我们自己知道能对应上就可以,表示按下了ID_ACOMFIRM的按钮
在里面添加代码:
else if (LOWORD(wParam) == ID_ACOMFIRM) {
char num1[10], num2[10]; char num3[10];
HWND tmp = GetActiveWindow();
HWND hEdit1 = GetDlgItem(tmp, ID_AEDIT1);
HWND hEdit2 = GetDlgItem(tmp, ID_AEDIT2);
HWND hEdit3 = GetDlgItem(tmp, ID_AEDIT3);
GetWindowText(hEdit1, num1, 10);
GetWindowText(hEdit2, num2, 10);
int x, y, z;
x = atoi(num1);
y = atoi(num2);
z = x + y;
wsprintf(num3, "%d", z);
SetWindowText(hEdit3, num3);
}
我们用GetActiveWindos()得到我们目前在活动中的窗口,也就是我们焦点锁定的“关于”对话框。
这里用到了GetDlgItem函数,第一个参数指定一个大窗口,第二个参数指定从这个大窗口中寻找ID等于这个参数的小控件(也就是一个小窗口)。
两者结合就可以获得“关于”对话框窗口中的控件啦。
然后做一些业务逻辑。
运行,成功
至此,已经基本上懂得了的窗口和小控件、各自的消息队列“WndProc”之间的关系,之后想自己写不同窗口,使用不同的消息队列都可以仿照着来自定义自己的“WndProc”了。