1、对话框 |
---|
对话框是一种特殊的窗口,通常包含各种子窗口控件。特殊的地方在于,它的窗口过程属于windows,程序员拥有的被称作"对话框过程",windows窗口过程内部会调用对话框过程,把一些消息交给程序员处理。
2、设计对话框 |
---|
可以在资源管理界面中设计对话框,把各种子窗口控件布局在对话框中。需要注意的是,对话框设计中使用的坐标值和尺寸并不是以像素为单位,它们的大小基于对话框当前使用的字体大小:
- x坐标和宽度以字符平均宽度的1/4为单位
- y坐标和高度以字符高度的1/8为单位
3、对话框过程 |
---|
对话框过程不是真正的窗口过程,但对于许多消息窗口过程会调用对话框过程。对话框过程声明如下:
INT_PTR (CALLBACK* DLGPROC)(HWND, UINT, WPARAM, LPARAM);
通常,如果对话框过程处理了消息,应该返回TRUE
,否则返回FALSE
。如果对话框过程返回FALSE
,窗口过程会对消息进行默认处理。所以,对话框过程不应该调用DefWindowProc
,应该把默认操作交给窗口过程负责。
但是,也有一些例外情况。比如WM_INITDIALOG
消息,如果对话框过程返回TRUE
,窗口过程会把焦点设置在wParam
参数指定的控件。如果需要自己设定获取焦点的控件,则应该返回FALSE
。
对话框过程最常处理的是子窗口控件的WM_COMMAND
消息。
4、模态对话框和非模态对话框 |
---|
当显示一个模态对话框时,用户无法切换到该程序的其他窗口,只能对模态对话框进行输入,可以使用DialogBox
函数创建显示模态对话框。DialogBox
会阻塞当前线程,直到对话框被关闭。可以使用EndDialog
来关闭对话框,其第二个参数作为DialogBox
的返回值。模态对话框有内建的消息循环,不使用程序的消息循环。如果想传递额外参数到模态对话框的对话框过程,可以使用DialogBoxParam
,其最后一个传参作为WM_INITDIALOG
的lParam
参数传递到对话框过程。
当显示一个非模态对话框时,用户可以切换到该程序的其他窗口,可以使用CreateDialog
函数创建非模态对话框,CreateDialog
会立即返回,不会阻塞线程。当不在需要对话框时,使用DestroyWindow
来关闭非模态对话框。如果想传递额外参数到非模态对话框的对话框过程,可以使用CreateDialogParam
,其最后一个传参作为WM_INITDIALOG
的lParam
参数传递到对话框过程。
5、模态对话框键盘接口 |
---|
模态对话框提供了一些默认的键盘接口,比如按下tab
键时把输入焦点切换到下一个控件,按下方向键时在同组控件内移动输入焦点等。非模态对话框没有这些键盘接口,但只要修改消息循环代码段,就可以为非模态对话框提供相同的键盘接口:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
关键在于IsDialogMessage
函数,IsDialogMessage
通过向子窗口控件发送WM_GETDLGCODE
消息来判断是否处理当前按键消息。如果子窗口控件没有处理当前按键消息,IsDialogMessage
就提供默认功能,并返回0
,消息循环不应该再把该消息发送出去,否则,IsDialogMessage
不处理按键消息,返回1
,消息循环把消息发送出去让对应控件处理消息。
子窗口控件会响应WM_GETDLGCODE
消息,它的返回值反应了子窗口控件会处理的按键消息。比如edit
控件处理WM_GETDLGCODE
消息的返回值带有DLGC_WANTCHAR
,也就是edit
控件会处理字符消息。可以利用子类化和IsDialogMessage
,让edit
控件无法处理字符消息:
// 对话框过程中子类化edit控件
case WM_INITDIALOG:
SetWindowSubclass(GetDlgItem(hDlg, IDC_EDIT1), SubClassProc, 0, 0);
break;
LRESULT CALLBACK SubClassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwData)
{
switch (message)
{
case WM_GETDLGCODE:
return DefSubclassProc(hwnd, message, wParam, lParam) & !DLGC_WANTCHARS;
}
return DefSubclassProc(hwnd, message, wParam, lParam);
}