65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 DialogBox() 和对话框资源调整 Win32 对话框大小

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (16投票s)

2011年1月2日

公共领域

5分钟阅读

viewsIcon

70557

downloadIcon

2197

演示如何通过资源标记,以最小的更改来调整对话框上的控件大小,同时保持现有的 Win32 代码不变

引言

用户普遍感到沮丧的一个问题是对话框无法调整大小。尽管有许多方法可以解决此问题,但大多数方法都侧重于可以围绕调整大小进行设计的代码。这使得现有的对话框无法调整大小。本文介绍了一种允许轻松地将调整大小功能重新应用到 Win32 对话框的方法。请注意,此处所说的对话框特指在资源脚本中定义、使用 DialogBox()(或类似)Win32 函数实例化的对话框。

背景

传统的 Win32 对话框在资源脚本中定义,用于定义对话框中控件的存在和位置。然而,实现调整大小的典型方法是编写代码来修改资源脚本定义的布局。遵循当代的编程实践,本文建议使用资源脚本来定义调整大小约定,尽量少修改代码本身。主要目标是对现有代码进行最小的更改,使改造尽可能简单。

调整大小可能给开发人员和设计师带来许多潜在问题。对话框不仅要在预设大小下运行良好,还必须在所有可能的大小下进行测试。为了尽量减少测试需求,本文提出的方法涉及将对话框设计为其最小尺寸,并在此最小尺寸下创建对话框,但用户保留放大对话框的选项。此调整大小操作产生的新空间将根据资源模板中的标记分配给控件。

此外,还可以选择性地对调整大小操作施加约束。这可以防止对话框无限放大,或者防止对话框在特定方向上被调整大小(例如,对话框可以垂直调整大小,但不能水平调整大小)。

Using the Code

  1. #include "ResizeDialog.h" 包含到包含对话框定义所在的资源脚本中。
  2. 在对话框的 DialogProc() 函数内部,调用提供的 resizer 函数 ResizeDialogProc()。这将处理标记中与调整大小相关的消息。
  3. 在实例化任何可调整大小的对话框之前,必须注册模板使用的自定义控件。这是通过在应用程序初始化时调用 ResizeDialogInitialize() 来完成的。
  4. 修改对话框样式(在资源脚本中)以支持调整大小。例如,将对话框的样式从
    STYLE WS_POPUPWINDOW | WS_CAPTION

    to

    STYLE WS_OVERLAPPED | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU
  5. 通过在每个控件之前添加 DIALOGRESIZECONTROL 辅助标记,来定义如何将新空间分配给对话框中的各个控件。此标记包含四个介于 0 到 100 之间的整数值,分别定义了用于将对象向左移动、向下移动、使其变宽和使其变高的百分比。例如,如果一个对象应该与其调整大小的对话框大小成比例增长,则值为 { 0, 0, 100, 100 }。一个顶部左对齐且大小不变的对象将是 { 0, 0, 0, 0 }。一个底部右对齐且大小不变的对象将是 { 100, 100, 0, 0 }。
  6. 如果需要对对话框的调整大小方式施加约束,请在对话框的开头添加一个单独的 DIALOGRESIZE 辅助标记。此标记包含两个整数值,可以是 0(表示无限制),或者大于等于 100(表示对话框可以从原始尺寸增大的最大百分比)。例如,要定义一个可以水平无限增长,但垂直只能增长 25% 的对话框,请使用 { 0, 125 }。

为了说明所需的更改,请考虑以下不可调整大小的对话框资源。

ResizeDialog_SampleDialog.png

TESTDIALOG4A DIALOGEX 10, 10, 140, 165
STYLE WS_POPUPWINDOW | WS_CAPTION
FONT 8, "MS Shell Dlg"
CAPTION "TestDialog4"
{
LTEXT "Description of &first list:", 1,  5, 5,   130, 10
LISTBOX 2,                               5, 15,  130, 60, WS_TABSTOP
LTEXT "Description of &second list:", 3, 5, 75,  130, 10
LISTBOX 4,                               5, 85,  130, 60, WS_TABSTOP
DEFPUSHBUTTON "&Close", 5,               5, 145, 60,  15, WS_TABSTOP
}

此对话框定义了两个列表,垂直分隔,并在对话框底部有一个按钮。当更改为将新空间分配给这些列表,并根据分配给第一个列表的新空间来重新定位第二个列表时,可调整大小的对话框资源看起来像

TESTDIALOG4B DIALOGEX 10, 10, 140, 165
STYLE WS_OVERLAPPED | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU
FONT 8, "MS Shell Dlg"
CAPTION "TestDialog4"
{
LTEXT "Description of &first list:", 1,  5, 5,   130, 10
DIALOGRESIZECONTROL { 0, 0, 100, 50 }
LISTBOX 2,                               5, 15,  130, 60, WS_TABSTOP
DIALOGRESIZECONTROL { 0, 50, 0, 0 }
LTEXT "Description of &second list:", 3, 5, 75,  130, 10
DIALOGRESIZECONTROL { 0, 50, 100, 50 }
LISTBOX 4,                               5, 85,  130, 60, WS_TABSTOP
DIALOGRESIZECONTROL { 0, 100, 0, 0 }
DEFPUSHBUTTON "&Close", 5,               5, 145, 60,  15, WS_TABSTOP
}

此外,必须对对话框回调函数进行最小的修改以处理调整大小。下面的 pResizeState 值是 resizer 对话框模块分配和维护的内存,用于记录控件的初始状态以及如何处理它们。

PVOID pResizeState = NULL;

BOOL CALLBACK
TestDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        ResizeDialogProc( hDlg, uMsg, wParam, lParam, &pResizeState );
        ...

最后,模块必须在调用对话框之前进行初始化

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
        ResizeDialogInitialize( hInst );

        DialogBox( hInst, MAKEINTRESOURCE(TESTDIALOG4B), NULL, TestDialogProc );
        ...

关注点

为了实现标记,扩展数据被记录在自定义控件内部。此数据的格式已经定义了很长时间,但是

  1. Windows 95 及其后续版本不支持此扩展信息,因此本文提出的方法在这些系统上将无法工作,并且仅限于基于 Windows NT 的系统。代码会尝试检测此情况并阻止在不支持的情况下进行调整大小。
  2. 尽管 Microsoft 的资源编译器支持此语法,但其他资源编译器(特别是 GNU 的 windres)不支持。
  3. 此语法仅在 DIALOGEX 资源上可用。它会在 DIALOG 资源上生成资源编译错误。在尝试使用此代码之前,请务必将任何 DIALOG 资源转换为 DIALOGEX

该代码通过处理发送到对话框的 WM_SIZE 消息,并枚举对话框上的所有控件来查找对话框调整大小辅助控件的实例。每个辅助控件都会收到一个 WM_RESIZEPARENT 消息,指示它需要调整大小。辅助控件会找到对话框上的紧邻的下一个控件(“伙伴”控件),并根据附加到调整大小辅助控件的数据对其进行适当的转换。

由于所有值都是百分比,因此代码还必须捕获对话框的初始大小,以及将要调整大小的每个控件的初始大小。这些值分别在创建对话框时和处理第一个 WM_SIZE 消息时捕获。然后将这些值与百分比值进行计算,以生成对话框调整大小时控件的最终大小。

历史

  • 2011 年 1 月 2 日 - 初始创建
© . All rights reserved.