Windows 编程/对话框
人们熟悉对话框。它们是 Windows 系统上弹出显示消息并允许用户设置参数的灰色窗口。对话框有三种类型:无模式、模态和系统模态。
- 模态
- 模态对话框通常用于程序内部,用于显示消息和设置程序参数。模态对话框会出现在屏幕最前面,在模态对话框打开时,您无法使用程序。要继续使用程序,必须关闭模态对话框。
- 系统模态
- 系统模态对话框与模态对话框类似,但它们会覆盖整个桌面区域。当系统模态对话框打开时,屏幕上其他任何内容都无法单击或选择。
- 无模式
- 无模式对话框可以取消选择,并且可以将控制权从无模式对话框转移到其他窗口。无模式对话框通常用作创建窗口的快速简便方法,无需注册窗口类。无模式对话框在 Windows 控制面板中很常见。
MessageBox
[edit | edit source]最简单的对话框类型是 MessageBox 函数。MessageBox 函数接受 5 个参数:父窗口句柄、消息、标题和选项。如果父窗口句柄为 NULL,则消息框为无模式的。如果您为父窗口提供句柄,则 MessageBox 可以变为父窗口的模态窗口。
MessageBox 对话框有多种不同的选项可以指定:按钮类型、图标、模态(模态/无模式)和文本对齐方式。这些选项被指定为位标志,可以使用按位 OR 运算符将它们组合在一起。
按钮
[edit | edit source]消息框可以具有标准的“确定”或“取消”按钮,也可以具有“是、否、取消”配置或许多衍生配置。每个消息框只能使用一种主要按钮方案
- MB_ABORTRETRYIGNORE: 消息框包含三个按钮:中止、重试和忽略。
- MB_CANCELTRYCONTINUE: 与 MB_ABORTRETRYIGNORE 相同,但在 Windows 2000/XP 上更常用。
- MB_OK: 消息框包含一个“确定”按钮。这是默认值。
- MB_OKCANCEL: 消息框包含两个按钮:“确定”和“取消”。
- MB_RETRYCANCEL: 消息框包含两个按钮:“重试”和“取消”。
- MB_YESNO: 消息框包含两个按钮:“是”和“否”。
- MB_YESNOCANCEL: 消息框包含三个按钮:“是”、“否”和“取消”。
要在消息框中显示图标,请指定以下值之一。此外,消息框可以通过指定“MB_HELP”标志添加额外的“帮助”按钮。“默认按钮”是一个概念,我们将在本章中经常看到,它是对话框打开时自动选择的按钮。Windows 提供了使用 MB_DEFBUTTONx 宏将默认按钮设置为消息框上的任何按钮的能力。以下是一个示例
MessageBox(NULL, "This is a Test", "Test", MB_OKCANCEL|MB_HELP|MB_DEFBUTTON2);
这将有一个带有“确定”、“取消”和“帮助”按钮的消息框,并且“取消”按钮将自动被选中。
图标
[edit | edit source]消息框可能没有图标,也可能只有一个图标。您不应指定消息框具有多个图标。根据 MSDN,不同的图标是
- MB_ICONEXCLAMATION: 消息框中会出现一个感叹号图标。
- MB_ICONWARNING: 消息框中会出现一个感叹号图标。
- MB_ICONINFORMATION: 消息框中会出现一个包含小写字母 i 的圆圈图标。
- MB_ICONASTERISK: 消息框中会出现一个包含小写字母 i 的圆圈图标。
- MB_ICONQUESTION: 消息框中会出现一个问号图标。
问号消息图标不再推荐使用,因为它不能清楚地表示特定类型的消息,并且将消息作为问题来措辞可能适用于任何类型的消息。此外,用户可能会将消息符号问号与帮助信息混淆。因此,不要在您的消息框中使用此问号消息符号。系统继续支持其包含只是为了向后兼容。 - MB_ICONSTOP: 消息框中会出现一个停止标志图标。
- MB_ICONERROR: 消息框中会出现一个停止标志图标。
- MB_ICONHAND: 消息框中会出现一个停止标志图标。
模态
[edit | edit source]最后,MessageBox 可以通过使用另一个标识符定义为模态、无模式或系统模态:MB_APPLMODAL、MB_SYSTEMMODAL 或 MB_TASKMODAL。MB_APPLMODAL 是默认值,并且只有在为函数指定了父窗口句柄时才有效。还有许多其他选项可用,请查看 MSDN 了解详细信息。
对话框过程
[edit | edit source]对话框过程与窗口过程略有不同。具体来说,它们返回 BOOL 值,而不是 LRESULT 值。此外,对话框没有默认的消息处理函数,因为消息并不总是需要处理。具体来说,Windows 管理对话框,Windows 将处理未使用的消息。如果对话框处理了某个消息,它应该返回 TRUE。如果消息未处理,该函数应该返回 FALSE。此外,对话框不会收到 WM_CREATE 消息,而是收到 WM_INITDIALOG 消息。此外,当对话框完成其工作时,它应该调用 EndDialog 函数。
以下是一个对话框函数的骨架示例
BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_INITDIALOG: return TRUE; case WM_DESTROY: EndDialog(hDlg, 0); return TRUE; } return FALSE; }
创建模态对话框
[edit | edit source]定义对话框过程后,可以通过调用 DialogBox 或 DialogBoxParam 函数创建对话框。这些函数返回一个 NRESULT 值,该值是传递给对话框过程中 EndDialog 函数的整数。
DialogBox 函数在对话框关闭之前不会返回。这意味着,从本质上讲,程序会冻结,直到我们关闭对话框。DialogBox 函数需要 2 个句柄:模块实例句柄和父窗口句柄。此外,DialogBox 函数要求传递一个字符串来命名定义对话框的资源。DialogBox 的最后一个参数是指向您已经定义的对话框过程函数的指针。
要将参数传递给对话框,可以使用 DialogBoxParam 函数。DialogBoxParam 具有与常规版本相同的参数,除了它接受第五个参数作为 32 位指针。这个 32 位值将作为 WM_INITDIALOG 消息的 LPARAM 元素传递。
DialogBox 和 DialogBoxParam 都要求对话框在资源中定义。但是,如果您想在运行时创建对话框,您可以使用 **DialogBoxIndirect** 或 **DialogBoxIndirectParam** 函数。在间接定义对话框时,我们需要填充 DLGTEMPLATE 结构,并将指向该结构的指针传递给函数,以代替资源标识符。DLGTEMPLATE 包含用于确定对话框某些特征的字段,例如尺寸和屏幕位置。
DLGITEMTEMPLATE 结构用于定义单个对话框项。有关此主题的更多信息,请搜索 MSDN。
无模式对话框是不同类型的东西,更像窗口而不是对话框。首先,我们需要修改消息循环,以确保对话框消息被正确路由。
while(GetMessage(&msg, NULL, 0, 0)) { if(!IsDialogMessage(hDlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
现在,我们有两种方法可以在资源脚本中定义消息框,有类或无类。我们将依次讨论每种方法。
我们可以在资源脚本中使用 DIALOG 关键字定义对话框。资源将有一个与其关联的 ID(数字或字符串),并且此 ID 可以直接传递给 CreateDialog 函数。
如果我们想在窗口类的基础上定义一个无模式对话框,我们可以使用一些额外的功能来简化工作。首先,我们创建一个 WNDCLASS 结构,其中包含有关对话框的信息。但是,有一点不同,我们必须将 cbWndExtra 字段设置为 DLGWINDOWEXTRA 值。
wnd.cbWndExtra = DLGWINDOWEXTRA;
然后,我们像往常一样注册类。由于我们像注册普通窗口一样注册窗口类,因此无模式对话框使用常规窗口过程,而不是对话框过程,这一点并不奇怪。现在,Windows 按名称识别类,因此我们应该记住类的名称。假设我们给我们的类命名为“MyDlgClass”。我们可以像这样创建一个对话框资源
MYDLGCLASS DIALOG DISCARDABLE 100, 100, 200, 200 CAPTION "My Dialog Box" CLASS "MyDlgClass" FONT 8, "MS Sans Serif" BEGIN ... END
请注意名为“CLASS”的字段?这与我们在 WNDCLASS 结构中用于命名类的字符串相同。重要的是这两个字符串必须相同,因为 Windows 需要此字符串将 WNDCLASS 和对话框资源链接起来。还要注意,我们使用字符串“MYDLGCLASS”来标识对话框资源。这不是强制性的,但它确实在以后使事情变得更方便。
现在,我们将调用更易于使用的函数 **CreateDialog**,而不是调用 CreateWindow。我们不使用 DialogBox 函数,因为 CreateDialog 会立即返回,并且不会停止程序执行。
这是一个例子
HWND hDlg; hDlg = CreateDialog(hInst, "MyDlgClass", hwndParent, MyDlgProc);
在这里,我们说“hInst”是应用程序的实例句柄,而“hwndParent”是对话框父窗口的句柄。如果 hwndParent 参数为 NULL,则对话框将没有父窗口。当无模式对话框完成时,它会调用“DestroyWindow”,而不是像模态对话框那样调用“EndDialog”。
**通用对话框** 是一个函数库,它可以自动生成 Windows 中一些最常见的对话框。这是一种努力,旨在使不同程序之间具有一定程度的连续性,这样,每个不同的程序就不会创建自己的专有“打开文件”对话框,例如。
每个通用对话框通常都有一个函数,该函数接受指向结构的指针。此结构专门针对每个不同的控件进行定义。可以通过包含 <commdlg.h> 头文件并将链接到 **comdlg32.dll** 库来将通用控件添加到项目中。
通过此库提供的一些通用控件包括“选择字体”对话框、“打开文件”和“保存文件”框以及“颜色调色板”对话框。
**ChooseColor** 函数会调出颜色调色板窗口,并向您的程序返回一个 32 位颜色值。
BOOL ChooseColor(LPCHOOSECOLOR lpcc);
ChooseColor 接受一个参数,它以指向 CHOOSECOLOR 结构的指针的形式出现。此结构用各种值初始化,当函数返回时,CHOOSECOLOR 结构将包含颜色值代码。
这两个函数会调出在几乎所有 Windows 应用程序中都熟悉的打开文件和保存文件对话框。
BOOL GetOpenFileName(LPOPENFILENAME lpofn); BOOL GetSaveFileName(LPOPENFILENAME lpofn);
这两个函数都接受指向 OPENFILENAME 结构的指针。此结构控制诸如可以加载的文件扩展名以及要查找的起始路径等内容。当函数返回时,该结构将包含所选文件的名称。一旦您的程序获得了此信息,您就可以使用文件 I/O API 来访问该文件。
ChooseFont 函数会调出一个熟悉的对话框,允许用户选择字体和各种字体属性,例如大小、下划线/粗体/斜体、颜色等。此函数接受指向 CHOOSEFONT 结构的指针。
BOOL ChooseFont(LPCHOOSEFONT lpcf);
对话框可以在资源脚本中指定,以处理创建对话框可能包含的所有不同子窗口(按钮和编辑框等)的繁琐任务。此过程在附录中的资源脚本参考中详细描述。在这里,我们将讨论使用资源脚本定义对话框的一些基础知识。
对话框资源使用 **DIALOG**(必须全部大写)关键字指定。DIALOG 关键字在资源标识符之前,后面跟着一系列尺寸值。
ID_DLGBOX DIALOG X, Y, CX, CY
X 和 Y 是对话框左上角相对于屏幕左上角的位置坐标。请记住,所有坐标都从左上角的 (0,0) 开始。下一组数字 CX 和 CY 是对话框的尺寸。这些尺寸不包括标题栏(如果有),因此将您的 Y 值设置为 0 将创建一个只有标题栏的对话框。
+---------------> X ["DialogBox" [_][O][x]] + | | | | | | | | | | | | | | | | | v | | Y | | | | | | | | +-----------------------+
在 DIALOG 声明之后,可以填写许多其他字段,以提供有关对话框的信息
ID_DLGBOX DIALOG 100, 100, 200, 150 STYLE WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE CAPTION "Title Bar Text" FONT 8, "MS Sans Serif"
STYLE 声明包含您将在 WNDCLASS 结构中或 CreateWindow 函数的 style 字段中使用的所有窗口样式,它们以按位或运算符连接。所有相同的值都可用。CAPTION 是对话框的标题。FONT 是在对话框的所有表面上使用的磅值和 TrueType 字体。可以指定任何字体和大小,但如果字体太大,您的对话框会非常烦人。
现在,一旦我们按我们想要的方式调整了对话框的大小和形状,我们就可以开始用控制按钮、编辑框以及各种其他好东西来填充它。首先,我们使用 BEGIN 和 END 标记
ID_DLGBOX DIALOG 100, 100, 200, 150 STYLE WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE CAPTION "Title Bar Text" FONT 8, "MS Sans Serif" BEGIN ... END
接下来,我们可以开始使用以下格式用按钮、复选框或任何我们想要的东西填充对话框
ID_DLGBOX DIALOG 100, 100, 200, 150 STYLE WS_OVERLAPPED | WS_CAPTION | WS_VISIBLE CAPTION "Title Bar Text" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "OK", IDOK, 10, 10, 50, 15, WS_TABSTOP CHECKBOX "Box 1", IDC_CB1, 10, 30, 50, 15, WS_TABSTOP EDITTEXT IDC_EDIT1, 10, 50, 100, 100 END
在声明之后,您可以选择包括一个或多个样式标志,以指定您希望特定控件的外观。WS_TABSTOP 标识符指定当您在键盘上按 TAB 键时,哪些控件可以被选中。当您按 TAB 键时,控件会在对话框控件之间切换,顺序与它们在资源脚本中指定的顺序相同(从上到下)。