“关于”对话框

有许多函数、消息和预定义控件可帮助创建和管理对话框,从而更轻松地开发应用程序的用户界面。 本概述介绍对话框函数和消息,并说明如何使用它们来创建和使用对话框。

本概述包括以下主题:

有关通用对话框的详细信息,请参阅 通用对话框库

何时使用对话框

大多数应用程序使用对话框来提示输入需要用户输入的菜单项的其他信息。 使用对话框是应用程序检索输入的唯一建议方法。 例如,典型的 “打开 ”菜单项需要打开文件的名称,因此应用程序应使用对话框提示用户输入名称。 在这种情况下,当用户单击菜单项并在用户提供信息后立即销毁对话框时,应用程序会创建对话框。

当用户在另一个窗口中工作时,许多应用程序还使用对话框来显示信息或选项。 例如,字处理应用程序通常使用带有文本搜索选项的对话框。 当应用程序搜索文本时,对话框将保留在屏幕上。 然后,用户可以返回到对话框并再次搜索同一个单词:或用户可以更改对话框中的条目并搜索新单词。 以这种方式使用对话框的应用程序通常在用户单击菜单项时创建一个,并且只要应用程序运行,或用户显式关闭该对话框,它将继续显示。

为了支持应用程序使用对话框的不同方式,有两种类型的对话框:模式对话框和无模式对话框。 模式对话框要求用户在允许应用程序继续之前提供信息或取消对话框。 应用程序将模式对话框与需要其他信息才能继续的菜单项结合使用。 无模式对话框允许用户提供信息并返回到上一个任务,而无需关闭对话框。 模式对话框比无模式对话框更易于管理,因为它们是创建、执行其任务并通过调用单个函数销毁的。

若要创建模式对话框或无模式对话框,应用程序必须提供对话框模板来描述对话框样式和内容;应用程序还必须提供对话框过程才能执行任务。 对话框模板是对话框及其包含的控件的二进制说明。 开发人员可以将此模板创建为要从应用程序的可执行文件加载的资源,或在应用程序运行时在内存中创建。 对话框过程是应用程序定义的回调函数,当系统具有对话框的输入或对话框要执行的任务时,系统会调用该回调函数。尽管对话框过程类似于窗口过程,但它不具有相同的责任。

应用程序通常使用 DialogBoxCreateDialog 函数创建对话框。 DialogBox 创建模式对话框; CreateDialog 创建无模式对话框。 这两个函数从应用程序的可执行文件加载对话框模板,并创建与模板规范匹配的弹出窗口。 还有其他函数使用内存中的模板创建对话框;在创建对话框时,它们会将其他信息传递给对话框过程。

对话框通常属于预定义的独占窗口类。 系统将此窗口类及其相应的窗口过程用于模式对话框和无模式对话框。 调用函数时,它会为对话框创建窗口以及对话框中控件的窗口,然后将所选消息发送到对话框过程。 虽然对话框可见,但预定义的窗口过程管理所有消息,处理一些消息,并将其他消息传递到对话框过程,以便该过程可以执行任务。 应用程序不直接访问预定义的窗口类或窗口过程,但它们可以使用对话框模板和对话框过程来修改对话框的样式和行为。

对话框所有者窗口

大多数对话框都有一个所有者窗口, (或更简单地说,所有者) 。 创建对话框时,应用程序通过指定所有者的窗口句柄来设置所有者。 系统使用所有者来确定对话框在 Z 顺序中的位置,以便对话框始终位于其所有者上方。 此外,系统还可以向所有者的窗口过程发送消息,通知其对话框中的事件。

每当其所有者被隐藏或销毁时,系统都会自动隐藏或销毁对话框。 这意味着对话框过程不需要特殊处理来检测对所有者窗口状态的更改。

由于典型对话框与菜单项一起使用,因此所有者窗口通常是包含菜单的窗口。 虽然可以创建没有所有者的对话框,但不建议这样做。 例如,当模式对话框没有所有者时,系统不会禁用应用程序的任何其他窗口,并且允许用户继续在其他窗口中执行工作,从而破坏模式对话框的目的。

当无模式对话框没有所有者时,当应用程序中的其他窗口被隐藏或销毁时,系统既不会隐藏也不销毁对话框。 尽管这不会破坏无模式对话框的目的,但它要求应用程序执行特殊处理,以确保对话框在适当时间被隐藏和销毁。

消息框

消息框是应用程序可用于显示消息和提示简单输入的特殊对话框。 消息框通常包含一条短信和一个或多个按钮。 应用程序使用 MessageBoxMessageBoxEx 函数创建消息框,指定要显示的文本以及按钮的数量和类型。 请注意,目前 MessageBoxMessageBoxEx 的工作方式没有区别。

尽管消息框是一个对话框,但系统会完全控制消息框的创建和管理。 这意味着应用程序不提供对话框模板和对话框过程。 系统基于为消息框指定的文本和按钮创建自己的模板,并提供自己的对话框过程。

消息框是模式对话框,系统使用 DialogBox 使用的相同内部函数创建它。 如果应用程序在调用 MessageBoxMessageBoxEx 时指定所有者窗口,系统会禁用所有者。 应用程序还可以指示系统通过在创建对话框时指定 MB_TASKMODAL 值来禁用属于当前线程的所有顶级窗口。

系统可以向所有者发送消息,例如 WM_CANCELMODEWM_ENABLE,就像创建模式对话框时一样。 所有者窗口应执行这些消息请求的任何操作。

模式对话框应该是具有窗口菜单、标题栏和粗边框的弹出窗口;也就是说,对话框模板应指定 WS_POPUPWS_SYSMENUWS_CAPTIONDS_MODALFRAME 样式。 尽管应用程序可以指定 WS_VISIBLE 样式,但无论对话框模板是否指定 WS_VISIBLE 样式,系统始终显示模式对话框。 应用程序不得创建具有 WS_CHILD 样式的模式对话框。 具有此样式的模式对话框会禁用自身,从而阻止任何后续输入到达应用程序。

应用程序使用 DialogBoxDialogBoxIndirect 函数创建模式对话框。 DialogBox 需要包含对话框模板的资源的名称或标识符; DialogBoxIndirect 需要包含对话框模板的内存对象的句柄。 DialogBoxParamDialogBoxIndirectParam 函数也创建模式对话框;它们与前面提到的函数相同,但在创建对话框时将指定的参数传递给对话框过程。

创建模式对话框时,系统会将其设置为活动窗口。 对话框保持活动状态,直到对话框过程调用 EndDialog 函数或系统激活另一个应用程序中的窗口。 在模式对话框被销毁之前,用户和应用程序都不能使所有者窗口处于活动状态。

当所有者窗口尚未禁用时,系统会在创建模式对话框时自动禁用该窗口及其所属的任何子窗口。 在销毁对话框之前,所有者窗口将保持禁用状态。 尽管对话框过程可能随时启用所有者窗口,但启用所有者会破坏模式对话框的用途,不建议这样做。 销毁对话框过程时,系统会再次启用所有者窗口,但前提是模式对话框导致所有者被禁用。

当系统创建模式对话框时,它会将 WM_CANCELMODE 消息发送到窗口 ((如果当前捕获鼠标输入的任何) )。 接收此消息的应用程序应释放鼠标捕获,以便用户可以在模式对话框中移动鼠标。 由于系统禁用所有者窗口,因此如果所有者在收到此消息时无法释放鼠标,则所有鼠标输入都将丢失。

为了处理模式对话框的消息,系统会启动自己的消息循环,临时控制整个应用程序的消息队列。 当系统检索到未显式显示对话框的消息时,它会将消息调度到相应的窗口。 如果检索WM_QUIT消息,则会将消息发回到应用程序消息队列,以便应用程序的main消息循环最终可以检索该消息。

每当应用程序消息队列为空时,系统会将 WM_ENTERIDLE 消息发送到所有者窗口。 当对话框保留在屏幕上时,应用程序可以使用此消息来执行后台任务。 当应用程序以这种方式使用消息时,应用程序必须频繁地产生控制 (例如,通过使用 PeekMessage 函数) ,以便模式对话框可以接收任何用户输入。 若要防止模式对话框发送 WM_ENTERIDLE 消息,应用程序可以在创建对话框时指定DS_NOIDLEMSG样式。

应用程序使用 EndDialog 函数销毁模式对话框。 在大多数情况下,当用户从对话框的窗口菜单中单击“关闭”或单击对话框中的“确定”或“取消”按钮时,对话框过程将调用 EndDialog。 对话框可以通过 DialogBox 函数 (或通过调用 EndDialog 函数时指定值来) 其他创建函数返回值。 销毁对话框后,系统会返回此值。 大多数应用程序使用此返回值来确定对话框是成功完成其任务还是被用户取消。 在对话框过程调用 EndDialog 函数之前,系统不会从创建对话框的函数返回控件。

无模式对话框

无模式对话框应该是具有窗口菜单、标题栏和细边框的弹出窗口;也就是说,对话框模板应指定 WS_POPUPWS_CAPTIONWS_BORDERWS_SYSMENU 样式。 除非模板指定 WS_VISIBLE 样式,否则系统不会自动显示对话框。

应用程序使用 CreateDialogCreateDialogIndirect 函数创建无模式对话框。 CreateDialog 需要包含对话框模板的资源的名称或标识符; CreateDialogIndirect 需要包含对话框模板的内存对象的句柄。 另外两个函数 CreateDialogParamCreateDialogIndirectParam 也创建无模式对话框:创建对话框时,它们会将指定的参数传递给对话框过程。

CreateDialog 和其他创建函数将窗口句柄返回到对话框。 应用程序和对话框过程可以使用此句柄来管理对话框。 例如,如果未在对话框模板中指定 WS_VISIBLE ,则应用程序可以通过将窗口句柄传递给 ShowWindow 函数来显示对话框。

无模式对话框既不禁用所有者窗口,也不向该窗口发送消息。 创建对话框时,系统会将其设置为活动窗口,但用户或应用程序可以随时更改活动窗口。 如果对话框变为非活动状态,则即使所有者窗口处于活动状态,它仍以 Z 顺序保留在所有者窗口上方。

应用程序负责检索输入消息并将其调度到对话框中。 大多数应用程序为此使用main消息循环。 但是,若要允许用户使用键盘移动到控件并选择控件,应用程序必须调用 IsDialogMessage 函数。 有关此函数的详细信息,请参阅 对话框键盘接口

无模式对话框无法像模式对话框那样向应用程序返回值,但对话框过程可以使用 SendMessage 函数将信息发送到所有者窗口。

应用程序必须在终止之前销毁所有无模式对话框。 它可以使用 DestroyWindow 函数销毁无模式对话框。 在大多数情况下,对话框过程调用 DestroyWindow 以响应用户输入,例如单击“ 取消 ”按钮。 如果用户从未以这种方式关闭对话框,则应用程序必须调用 DestroyWindow

DestroyWindow 使对话框的窗口句柄失效,因此对使用该句柄的函数的任何后续调用都会返回错误值。 为防止错误,对话框过程应通知所有者对话框已被销毁。 许多应用程序维护一个全局变量,其中包含对话框的句柄。 当对话框过程销毁对话框时,它还会将全局变量设置为 NULL,表示对话框不再有效。

对话框过程不得调用 EndDialog 函数来销毁无模式对话框。

对话框模板

对话框模板是描述对话框的二进制数据,用于定义对话框的高度、宽度、样式及其包含的控件。 若要创建对话框,系统会从应用程序的可执行文件中的资源加载对话框模板,或使用应用程序在全局内存中传递给它的模板。 在任一情况下,应用程序在创建对话框时都必须提供模板。

开发人员使用资源编译器或对话框编辑器创建模板资源。 资源编译器将文本说明转换为二进制资源,对话框编辑器将交互式构造的对话框保存为二进制资源。

注意

有关如何创建模板资源并将其添加到应用程序的可执行文件的说明超出了本概述的范围。 有关创建模板资源并将其添加到可执行文件的详细信息,请参阅应用程序开发工具随附的文档。

 

若要在不使用模板资源的情况下创建对话框,必须在内存中创建一个模板,并将其传递到 CreateDialogIndirectParamDialogBoxIndirectParam 函数,或 CreateDialogIndirectDialogBoxIndirect 宏。

内存中的对话框模板由描述对话框的标头组成,后跟描述对话框中每个控件的一个或多个附加数据块。 模板可以使用标准格式或扩展格式。 在标准模板中, 标头是一个 DLGTEMPLATE 结构,后跟其他可变长度数组;和 每个控件的数据由 DLGITEMTEMPLATE 结构以及附加的可变长度数组组成。 在扩展对话框模板中,标头使用 DLGTEMPLATEEX 格式,控件定义使用 DLGITEMTEMPLATEEX 格式。

可以通过分配全局内存对象并使用标准或扩展标头和控件定义填充它来创建内存模板。 内存模板在形式和内容上与模板资源相同。 许多使用内存模板的应用程序首先使用 LoadResource 函数将模板资源加载到内存中,然后修改加载的资源以创建新的内存模板。 有关在内存中创建对话框模板的详细信息,请参阅 内存中的模板

以下部分介绍对话框模板中使用的样式、度量值和其他值。

对话框模板样式

每个对话框模板指定用于定义对话框外观和功能的样式值的组合。 样式值可以是窗口样式(如 WS_POPUPWS_SYSMENU)和对话框样式(如 DS_MODALFRAME)。 模板样式的数量和类型取决于对话框的类型和用途。 有关值的列表,请参阅 对话框样式

创建对话框时,系统会将模板中指定的所有窗口样式传递到 CreateWindowEx 函数。 系统可能会传递一个或多个扩展样式,具体取决于指定的对话框样式。 例如,当模板指定 DS_MODALFRAME时,系统会在创建对话框时使用 WS_EX_DLGMODALFRAME

大多数对话框都是具有窗口菜单和标题栏的弹出窗口。 因此,典型模板指定 WS_POPUPWS_SYSMENUWS_CAPTION 样式。 该模板还指定边框样式:无模式对话框 的WS_BORDER ,模式对话框 的DS_MODALFRAME 。 如果模板创建自定义窗口而不是对话框,则模板可以指定弹出窗口 (以外的窗口类型,例如 WS_OVERLAPPED) 。

无论是否指定 了WS_VISIBLE 样式,系统始终显示模式对话框。 当无模式对话框的模板指定 WS_VISIBLE 样式时,系统会在创建对话框时自动显示该对话框。 否则,应用程序负责使用 ShowWindow 函数显示对话框。

对话框度量

每个对话框模板都包含度量值,这些度量值指定对话框的位置、宽度和高度及其包含的控件。 这些度量与设备无关,因此应用程序可以使用单个模板为所有类型的显示设备创建相同的对话框。 这可确保对话框在所有屏幕上具有相同的比例和外观,尽管屏幕之间的分辨率和纵横比不同。

对话框模板中的度量值按对话框模板单位指定。 若要将度量值从对话框模板单位转换为屏幕单位 (像素) ,请使用 MapDialogRect 函数,该函数会考虑对话框使用的字体,并将对话框模板单位中的矩形正确转换为像素。 对于使用系统字体的对话框,可以使用 GetDialogBaseUnits 函数自行执行转换计算,不过使用 MapDialogRect 更简单。

模板必须指定对话框左上角的初始坐标。 通常,坐标相对于所有者窗口工作区的左上角。 当模板指定DS_ABSALIGN样式或对话框没有所有者时,该位置相对于屏幕的左上角。 系统在创建对话框时设置此初始位置,但允许应用程序在显示对话框之前调整位置。 例如,应用程序可以检索所有者窗口的维度,计算在所有者窗口中将对话框居中的新位置,然后使用 SetWindowPos 函数设置位置。

模板应指定不超过屏幕宽度和高度的对话框宽度和高度,并确保所有控件都在对话框的工作区内。 虽然系统允许对话框大小为任意大小,但创建一个太小或太大的对话框可能会阻止用户提供输入,从而破坏对话框的用途。 存在大量控件时,许多应用程序使用多个对话框。 在这种情况下,初始对话框通常包含一个或多个按钮,用户可以选择这些按钮来显示下一个对话框。

对话框控件

模板指定对话框中每个控件的位置、宽度、高度、样式、标识符和窗口类。 系统通过将此数据传递到 CreateWindowEx 函数来创建每个控件。 控件的创建顺序与在模板中指定的顺序一样。 模板应指定控件的适当数量、类型和顺序,以确保用户可以输入完成与对话框关联的任务所需的输入。

对于每个控件,模板指定用于定义控件的外观和操作的样式值。 每个控件都是子窗口,因此必须具有 WS_CHILD 样式。 若要确保在显示对话框时控件可见,每个控件还必须具有 WS_VISIBLE 样式。 其他常用的窗口样式包括 WS_BORDER 具有可选边框的控件, WS_DISABLED 在最初创建对话框时应禁用的控件,以及可以使用键盘访问的控件 的WS_TABSTOPWS_GROUPWS_TABSTOPWS_GROUP样式与本主题后面介绍的对话键盘界面结合使用。

该模板还可以指定特定于控件的窗口类的控件样式。 例如,指定按钮控件的模板必须提供按钮控件样式,例如 BS_PUSHBUTTONBS_CHECKBOX。 系统通过 WM_CREATE 消息将控件样式传递给控件窗口过程,使过程能够调整控件的外观和操作。

系统将位置坐标以及宽度和高度度量值从对话基单位转换为像素,然后将这些度量值传递给 CreateWindowEx。 当系统创建控件时,它会将对话框指定为父窗口。 这意味着系统始终将控件的位置坐标解释为相对于对话框工作区左上角的客户端坐标。

模板为每个控件指定窗口类。 典型的对话框包含属于预定义控件窗口类的控件,例如按钮和编辑控件窗口类。 在这种情况下,模板通过为类提供相应的预定义原子值来指定窗口类。 当对话框包含属于自定义控件窗口类的控件时,模板会提供该注册的窗口类的名称或当前与该名称关联的 atom 值。

对话框中的每个控件都必须具有唯一标识符,以将其与其他控件区分开来。 控件通过 WM_COMMAND 消息将信息发送到对话框过程,因此控件标识符对于确定哪个控件发送了指定消息的过程至关重要。 此规则的唯一例外是静态控件的控件标识符。 静态控件不需要唯一标识符,因为它们不发送 WM_COMMAND 消息。

若要允许用户关闭对话框,模板应至少指定一个按钮,并为其指定控件标识符 IDCANCEL。 若要允许用户选择完成或取消与对话框关联的任务,模板应指定两个按钮,分别标记为 “确定 ”和“ 取消”,控制标识符为 IDOKIDCANCEL

模板还指定控件的可选文本和创建数据。 文本通常为按钮控件提供标签,或指定静态文本控件的初始内容。 创建数据是系统在创建控件时传递给控件窗口过程的一个或多个字节数据。 对于需要与其初始内容或样式相比其他数据所指定的详细信息的控件,创建数据非常有用。 例如,应用程序可以使用创建数据来设置滚动条控件的初始设置和范围。

对话框窗口菜单

当模板指定WS_SYSMENU样式时,系统会为对话框提供 窗口 菜单。 为防止输入不当,系统会自动禁用菜单中除 “移动 ”和 “关闭”之外的所有项。 用户可以单击“ 移动 ”来移动对话框。 当用户单击“ 关闭”时,系统会向对话框过程发送 WM_COMMAND 消息,其中 wParam 参数设置为 IDCANCEL。 这与用户单击“ 取消 ”按钮时发送的消息相同。 此消息的建议操作是关闭对话框并取消请求的任务。

尽管不建议使用对话框中的其他菜单,但对话框模板可以通过提供菜单资源的标识符或名称来指定菜单。 在这种情况下,系统将加载资源并创建对话框的菜单。 使用模板创建自定义窗口而不是对话框时,应用程序通常使用模板中的菜单标识符或名称。

对话框字体

系统使用对话框字体的平均字符宽度来计算对话框的位置和尺寸。 默认情况下,系统会使用 SYSTEM_FONT 字体绘制对话框中的所有文本。

若要为非默认对话框指定字体,必须使用对话框模板创建对话框。 在模板资源中,使用 FONT 语句。 在对话框模板中,设置 DS_SETFONTDS_SHELLFONT 样式,并指定点大小和字样名称。 即使对话框模板以这种方式指定字体,系统也始终使用系统字体作为对话框标题和对话框菜单。

当对话框具有 DS_SETFONTDS_SHELLFONT 样式时,系统会在创建控件时向对话框过程和每个控件发送 WM_SETFONT 消息。 对话框过程负责保存随 WM_SETFONT 消息一起传递的字体句柄,并在将文本写入窗口时选择该句柄进入显示设备上下文。 默认情况下,预定义控件执行此操作。

系统字体可能因不同版本的 Windows 而异。 若要使应用程序无论在哪个系统上运行,都使用系统字体,请将 DS_SHELLFONT 与字样 MS Shell Dlg 一起使用,并使用 DIALOGEX 资源 而不是 DIALOG 资源。 系统映射此字样,以便对话框将使用 Tahoma 字体。 请注意,如果字样不是 MS Shell Dlg, 则DS_SHELLFONT 无效。

内存中的模板

内存中的对话框模板由描述对话框的标头组成,后跟描述对话框中每个控件的一个或多个其他数据块。 模板可以使用标准格式或扩展格式。 在标准模板中, 标头是后跟其他可变长度数组的 DLGTEMPLATE 结构。 每个控件的数据由 DLGITEMTEMPLATE 结构后跟其他可变长度数组组成。 在扩展对话框模板中, 标头使用 DLGTEMPLATEEX 格式,控件定义使用 DLGITEMTEMPLATEEX 格式。

若要区分标准模板和扩展模板,检查对话框模板的前 16 位。 在扩展模板中,第一个 WORD 0xFFFF;任何其他值指示标准模板。

如果在内存中创建对话框模板,必须确保每个 DLGITEMTEMPLATEDLGITEMTEMPLATEEX 控件定义在 DWORD 边界上对齐。 此外,控件定义后面的任何创建数据都必须在 DWORD 边界上对齐。 对话框模板中的所有其他可变长度数组必须在 WORD 边界上对齐。

模板标头

在对话框的标准模板和扩展模板中, 标头包含以下常规信息:

  • 对话框的位置和尺寸
  • 对话框的窗口和对话框样式
  • 对话框中的控件数。 此值确定模板中 DLGITEMTEMPLATEDLGITEMTEMPLATEEX 控件定义的数目。
  • 对话框的可选菜单资源。 模板可以指示对话框没有菜单,也可以指定标识可执行文件中的菜单资源的序号值或以 null 结尾的 Unicode 字符串。
  • 对话框的窗口类。 这可以是预定义的对话框类,也可以是标识已注册窗口类的序号值或以 null 结尾的 Unicode 字符串。
  • 以 null 结尾的 Unicode 字符串,指定对话框窗口的标题。 如果字符串为空,则对话框的标题栏为空。 如果对话框没有 WS_CAPTION 样式,系统将标题设置为指定的字符串,但不显示它。
  • 如果对话框具有 DS_SETFONT 样式,则标题将指定要用于工作区和对话框控件中的文本的字体的点大小和字体名称。

在扩展模板中, DLGTEMPLATEEX 标头还指定以下附加信息:

  • 系统发送 WM_HELP 消息时对话框窗口的帮助上下文标识符。
  • 如果对话框具有 DS_SETFONTDS_SHELLFONT 样式,则标题指定字体粗细并指示字体是否为斜体。

控件定义

模板标头后面的是描述对话框控件的一个或多个控件定义。 在标准和扩展模板中,对话框标头都有一个 成员,该成员指示模板中的控件定义数。 在标准模板中,每个控件定义都包含 一个 DLGITEMTEMPLATE 结构,后跟其他可变长度数组。 在扩展模板中,控件定义使用 DLGITEMTEMPLATEEX 格式。

在标准和扩展模板中,控件定义包括以下信息:

  • 控件的位置和尺寸。
  • 控件的窗口和控件样式。
  • 控件标识符。
  • 控件的窗口类。 这可以是预定义系统类的序号值,也可以是指定已注册窗口类名称的以 null 结尾的 Unicode 字符串。
  • 以 null 结尾的 Unicode 字符串,指定控件的初始文本,或标识可执行文件中的资源(如图标)的序号值。
  • 可选的可变长度创建数据块。 当系统创建控件时,它会在发送到控件的WM_CREATE消息的 lParam 参数中传递指向此数据的指针。

在扩展模板中,当系统发送 WM_HELP 消息时,控件定义还为控件指定帮助上下文标识符。