对话框的一般形式时包含多种子窗口控件的弹出式窗口。这些控件的大小与位置在程序的资源叙述文件的对话框模板中指定。
当程序呼叫一句模板建立的对话框时,Windows负责建立弹出式对话框窗口和子窗口控件,并提供处理对话框消息(包括所有的键盘和鼠标输入)的窗口消息处理程序。有时候称呼完成这些功能的Windows内部程序代码为“对话框管理器”。
windows的内部对话框窗口消息处理函数所处理的许多消息也传递给自己程序中的函数,这个函数即是所谓的对话框程序。
对话框程序与普通的窗口消息处理程序类似。除了在建立对话框时初始化子窗口控件,处理来自子窗口控件的消息以及结束对话框之外,不需要再给对话框程序增加其它功能。对话程序通常不处理WM_PAINT消息,也不直接处理键盘和鼠标输入
对话框分为模态与非模态的,其中模态对话框最普通。当程序显示一个模态对话框时,使用者不能在对话框与同一个程序中的另一个窗口之间进行切换。使用者必须主动结束该对话框,通过按下OK或CANCEL键来完成。不过,显示模态对话框时,使用者通常可以从目前的程序切换到另一个程序。
对话框及其模板
要把一个对话框添加到Visual C++ Developer Studio已有的应用程序上,可以先从Insert菜单中选择 Resource,然后选择Dialog Box。现在一个对话框出现在您的眼前,该对话框带有标题列、标题(Dialog)以及 OK和Cancel按钮。Controls工具列允许您在对话框中插入不同的控件。
Developer Studio将对话框的ID设为标准的IDD_DIALOG1。可以在此名称上(或者在对话框本身)单击右键,然后从菜单中选择 Properties。
对话框程序
程序内的对话框程序处理传送给对话框的消息。尽管看起来很像是窗口消息处理程序,但是它并不是真实的窗口消息处理程序。对话框的窗口消息处理程序在Windows内部定义,这个窗口过程调用您编写的对话框程序,把它所接收到的许多消息作为参数。
该函数的参数与常规窗口消息处理程序的参数相同,与窗口消息处理程序类似,对话框程序都必须定义为一个CALLBACK(callback)函数。这个函数与一般窗口消息处理程序的区别:
- 窗口消息处理程序传回一个LRESULT。对话框传回一个BOOL,它在Windows表头文件中定义为int型态。
- 如果窗口消息处理程序不处理某个特定的消息,那么它将呼叫DefWindowProc。如果对话框程序处理一个消息,那么它传回TRUE(非0),如果不处理,则传回FALSE(0)。
- 对话框程序不需要处理WM_PAINT或WM_DESTROY消息。对话框程序不接收WM_CREAT消息,而是在特殊的WM_INITDIALOG消息处理期间,对话框程序执行初始化操作。
对话框程序只处理WM_COMMAND消息。这是当按键被鼠标点中,或者在按钮具有输入焦点的情况下按下空格键时,按键控件发送给其父窗口的消息。这个控件的ID(我们在对话框模板中将其设定为IDOK)在wParam的低字组中。对于所有其它消息,对话框程序传回FALSE,并告诉Windows内部的对话框窗口消息处理程序:我们的对话框程序不处理这些消息。
模态对话框的消息不通过您程序的消息队列,所以不必担心对话框中键盘快捷键的影响。
在对话框上画图
对话框模板内,使用位置和大小为我们想要画图的区域定义了一块空白文字控件:
LTEXT "" IDC_PAINT, 114, 67, 72, 72
这个区域为18个字符宽和9个字符高。由于这个控件没有文字,所以窗口消息处理程序为「静态」类别所做的工作,只是在必须重绘这个子窗口控件时清除其背景。
void PaintTheBlock (HWND hCtrl, int iColor, int iFigure)
{
InvalidateRect (hCtrl, NULL, TRUE) ;
UpdateWindow (hCtrl) ;
PaintWindow (hCtrl, iColor, iFigure) ;
}
这个函数使得子窗口控件无效,并为控件窗口消息处理程序产生一个WM_PAINT消息,然后呼叫另一个函数PaintWindow 。
void PaintWindow (HWND hwnd, int iColor, int iFigure)
{
static COLORREF crColor[8] = { RGB ( 0, 0, 0), RGB ( 0, 0, 255),
RGB ( 0, 255, 0), RGB ( 0, 255, 255),
RGB (255, 0, 0), RGB (255, 0, 255),
RGB (255, 255, 0), RGB (255, 255, 255) } ;
HBRUSH hBrush ;
HDC hdc ;
RECT rect ;
hdc = GetDC (hwnd) ;
GetClientRect (hwnd, &rect) ;
hBrush = CreateSolidBrush (crColor[iColor - IDC_BLACK]) ;
hBrush = (HBRUSH) SelectObject (hdc, hBrush) ;
if (iFigure == IDC_RECT)
Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
else
Ellipse (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
DeleteObject (SelectObject (hdc, hBrush)) ;
ReleaseDC (hwnd, hdc) ;
}
非模态对话框允许使用者在对话框与其它程序之间进行切换,又可以在对话框与建立对话框的窗口之间进行切换。因此,非模态对话框与使用者程序常见的普通弹出式窗口可能更为相似。
态对话框是用DialogBox来建立的。只有在清除对话框之后,函数才会传回值。在对话框程序内使用EndDialog呼叫来终止对话框,DialogBox传回的是该呼叫的第二个参数的值。
非模态对话框是使用CreateDialog来建立的,该函数所使用的参数与DialogBox相同。
hDlgModeless = CreateDialog ( hInstance, szTemplate, hwndParent, DialogProc) ;
区别是CreateDialog函数立即传回对话框的窗口句柄,并通常将这个窗口句柄存放到整体变量中。
与模态对话框和消息框的消息不同,非模态对话框的消息要经过程序式的消息队列。要将这些消息传送给对话框窗口消息处理程序,则必须改变消息队列。
一项重要的区别:使用DestroyWindow而不是EndDialog来结束非模态对话框。当您呼叫DestroyWindow后,将hDlgModeless整体变量设定为0。
两个窗口句柄之间的区别:DestroyWindow的hDlg参数是传递给对话框程序的参数;hDlgModeless是从CreateDialog传回的整体变量,程序在消息循环内检验它。