一、Windows模态对话框—不同的主题
虽然Visual C++ Developer Studio中的对话框编辑器和其它资源编辑器,使我们几乎不用考虑资源描述的写作问题,但是学习一些资源描述的语法还是有用的。尤其对于对话框模板来说,知道了语法,您就可以近一步了解对话框的范围和限制。甚至当它不能满足您的需要时,您还可以自己建立一个对话框模板(就像本章后面的HEXCALC程序)。资源编译器和资源描述语法的文件位于/Platform SDK/Windows Programming Guidelines/Platform SDK Tools/Compiling/Using the Resource Compiler。
在Developer Studio的「Properties」对话框中指定了对话框的窗口样式,它翻译成对话框模板中的STYLE叙述。对于ABOUT1,我们使用模态对话框最常用的样式;
STYLE WS_POPUP | DS_MODALFRAME
然而,您也可以尝试其它样式。有些对话框有标题列,标题列用于指出对话框的用途,并允许使用者通过鼠标在显示屏上移动对话框。此样式为WS_CAPTION。如果您使用WS_CAPTION,那么DIALOG叙述中所指定的x坐标和y坐标是对话框显示区域的坐标,并相对于父窗口显示区域的左上角。标题列将在y坐标之上显示。
如果使用了标题列,那么您可以用CAPTION叙述将文字放入标题中。在对话框模板中,CAPTION叙述在STYLE叙述的后面:
CAPTION "Dialog Box Caption"
另外,在对话框程序处理WM_INITDIALOG消息处理期间,您还可以呼叫:
SetWindowText (hDlg, TEXT ("Dialog Box Caption")) ;
如果您使用WS_CAPTION样式,也可以添加一个WS_SYSMENU样式的系统菜单按钮。此样式允许使用者从系统菜单中选择 Move或Close。
从Properties对话框的Border清单方块中选择 Resizing(相同于样式WS_THICKFRAME),允许使用者缩放对话框,仅管此操作并不常用。如果您不介意更特殊一点的话,还可以着为此对话框样式添加最大化方块。
您甚至可以给对话框添加一个菜单。这时对话框模板将包括下面的叙述:
MENU menu-name
其参数不是菜单的名称,就是资源描述中的菜单号。模态对话框很少使用菜单。如果使用了菜单,那么您必须确保菜单和对话框控件中的所有ID都是唯一的;或者不是唯一的,却表达了相同的命令。
FONT叙述使您可以设定非系统字体,以供对话框文字使用。这在过去的对话框中不常用,但现在却非常普遍。事实上,在内定情况下,Developer Studio为您建立的每一个对话框都选用8点的MS Sans Serif字体。一个Windows程序能把自己外观打点得非常与众不同,这只需为程序的对话框及其它文字输出单独准备一种字体即可。
尽管对话框窗口消息处理程序通常位于Windows内部,但是您也可以使用自己编写的窗口消息处理程序来处理对话框消息。要这样做,您必须在对话框模板中指定一个窗口类别名:
CLASS "class-name"
这种用法很少见,但是在本章后面所示的HEXCALC程序中我们将用到它。
当您使用对话框模板的名称来呼叫DialogBox时,Windows通过呼叫普通的CreateWindow函数来完成建立弹出式窗口所需要完成的一切操作。Windows从对话框模板中取得窗口的坐标、大小、窗口样式、标题和菜单,从DialogBox的参数中获得执行实体句柄和父窗口句柄。它所需要的唯一其它信息是一个窗口类别(假设对话框模板不指定窗口类别的话)。Windows为对话框注册一个专用的窗口类别,这个窗口类别的窗口消息处理程序可以存取对话框程序地址(该地址是您在DialogBox呼叫中指定的),所以它可以使程序获得该弹出式窗口所接收的消息。当然,您可以通过自己建立弹出式窗口来建立和维护自己的对话框。不过,使用DialogBox则更简单。
也许您希望受益于Windows对话框管理器,但不希望(或者能够)在资源描述中定义对话框模板,也可能您希望程序在执行时可以动态地建立对话框。这时可以完成这种功能的函数是DialogBoxIndirect,此函数用数据结构来定义模板。
在ABOUT1.RC的对话框模板中,我们使用缩写CTEXT、ICON和DEFPUSHBUTTON来定义对话框所需要的三种型态的子窗口控件。您还可以使用其它型态,每种型态都隐含一个特定的预先定义窗口类别和一种窗口样式。下表显示了与一些控件型态相同的窗口类别和窗口样式:
控件型态 |
窗口类别 |
窗口样式 |
PUSHBUTTON |
按钮 |
BS_PUSHBUTTON | WS_TABSTOP |
DEFPUSHBUTTON |
按钮 |
BS_DEFPUSHBUTTON | WS_TABSTOP |
CHECKBOX |
按钮 |
BS_CHECKBOX | WS_TABSTOP |
RADIOBUTTON |
按钮 |
BS_RADIOBUTTON | WS_TABSTOP |
GROUPBOX |
按钮 |
BS_GROUPBOX | WS_TABSTOP |
LTEXT |
静态文字 |
SS_LEFT | WS_GROUP |
CTEXT |
静态文字 |
SS_CENTER | WS_GROUP |
RTEXT |
静态文字 |
SS_RIGHT | WS_GROUP |
ICON |
静态图标 |
SS_ICON |
EDITTEXT |
编辑 |
ES_LEFT | WS_BORDER | WS_TABSTOP |
SCROLLBAR |
滚动条 |
SBS_HORZ |
LISTBOX |
清单方块 |
LBS_NOTIFY | WS_BORDER | WS_VSCROLL |
COMBOBOX |
下拉式清单方块 |
CBS_SIMPLE | WS_TABSTOP |
资源编译器是唯一能够识别这些缩写的程序。除了表中所示的窗口样式外,每个控件还具有下面的样式:
WS_CHILD | WS_VISIBLE
对于这些控件型态,除了EDITTEXT、SCROLLBAR、LISTBOX和COMBOBOX之外,控件叙述的格式为:
control-type "text", id, xPos, yPos, xWidth, yHeight, iStyle
对于EDITTEXT、SCROLLBAR、LISTBOX和COMBOBOX,其格式为:
control-type id, xPos, yPos, xWidth, yHeight, iStyle
其中没有文字字段。在这两种叙述中,iStyle参数都是选择性的。
在第九章,我讨论了确定预先定义子窗口的宽度和高度的规则。您可能需要回到第九章去参考这些规则,这时请记住:对话框模板中指定大小的单位为平均字符宽度的1/4,及平均字符高度的1/8。
控件叙述的style字段是可选的。它允许您包含其它窗口样式标识符。例如,如果您想建立在正方形框左边包含文字的复选框,那么可以使用:
CHECKBOX "text", id, xPos, yPos, xWidth, yHeight, BS_LEFTTEXT
注意,控件型态EDITTEXT会自动添加一个边框。如果您想建立一个没有边框的子窗口编辑控件,您可以使用:
EDITTEXT id, xPos, yPos, xWidth, yHeight, NOT WS_BORDER
资源编译器也承认与下面叙述类似的专用控件叙述:
CONTROL "text", id, "class", iStyle, xPos, yPos, xWidth, yHeight
此叙述允许您通过指定窗口类别和完整的窗口样式,来建立任意型态的子窗口控件。例如,要取代:
PUSHBUTTON "OK", IDOK, 10, 20, 32, 14
您可以使用:
CONTROL "OK", IDOK, "button", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP, 10, 20, 32, 14
当编译资源描述档时,这两条叙述在.RES和.EXE文件中的编码是相同的。在Developer Studio中,您可以使用Controls工具列中的Custom Control选项来建立此叙述。在ABOUT3程序中,我向您展示了如何用此选项建立一个控件,且在您的程序中已定义了该控件的窗口类别。
当您在对话框模板中使用CONTROL叙述时,不必包含WS_CHILD和WS_VISIBLE样式。在建立子窗口时,Windows已经包含了这些窗口样式。CONTROL叙述的格式也说明Windows对话框管理器在建立对话框时就完成了此项操作。首先,就像我前面所讨论的,它建立一个弹出式窗口,其父窗口句柄在DialogBox函数中提供。然后,对话框管理器为对话框模板中的每个控件建立一个子窗口。所有这些控件的父窗口均是这个弹出式对话框。上面给出的CONTROL叙述被转换成一个CreateWindow呼叫,形式如下所示:
hCtrl =CreateWindow (TEXT ("button"), TEXT ("OK"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, 10 * cxChar / 4, 20 * cyChar / 8, 32 * cxChar / 4, 14 * cyChar / 8, hDlg, IDOK, hInstance, NULL) ;
其中,cxChar和cyChar是系统字体字符的宽度和高度,以图素为单位。hDlg参数是从建立该对话框窗口的CreateWindow呼叫传回的值;hInstance参数是从DialogBox呼叫获得的。