WTL 中的对话框大小调整:Paolo Messina 的 MFC ResizableLib 移植。






4.23/5 (11投票s)
一篇关于如何使用 WTL 制作可调整大小的对话框的文章。
引言
首先,关于窗口大小调整的问题。例如,我们有一个对话框窗口,其中包含一些子控件(图 1)。
图 1
我们希望实现以下行为:当对话框大小改变时,一些子控件的大小也必须改变。在这个例子中,标有“Static”的 GroupBox 必须与窗口的左、上、右、下边缘保持相同的间距,而 ListBox 的行为应与 GroupBox 相同。“OK”按钮应保持在窗口的左下角,“About...”按钮应保持在右下角,而“Cancel”按钮应保持在窗口的中心。调整大小后的对话框显示在下一张图片中(图 2)。
图 2
要使子控件如上所述进行调整大小,并没有简单的方法。最简单的方法是处理 WM_SIZE
消息,并在消息处理程序中设置每个控件的位置。当控件数量不是很多时,这种方法是可行的。如果我们有更复杂的对话框,那么我们需要一些标准方法来描述控件的重新定位行为。
很久以前,我为 MFC 找到了一个出色的库,可以帮助设计可调整大小的对话框,该对话框没有闪烁,并且具有非常简单的调整大小行为描述。该库名为 ResizableLib。它由 Paolo Messina 创建,您可以在此处找到它。我决定将其移植到 WTL,这就是这项工作的结果。
WTL 也实现了大小调整:CDialogResize<>
模板,但 ResizableLib 具有更多功能。
- 对大多数控件提供抗闪烁支持。
- 支持任何窗口的 MinMaxInfo。
- 支持保存/恢复窗口大小和位置。
- 支持可调整大小的属性表和向导。
- 可以将大小调整机制附加到任何窗口(不仅仅是对话框)。
- 简单的控件行为描述。
- 使对话框可调整大小所需的最小代码。
库内容
此库中包含的文件。 | |
ResizableDialog.h |
可调整大小的对话框实现。 |
ResizableGrip.h | 可调整大小的抓手控件实现以及拥有抓手的窗口模板。 |
ResizableLayout.h | 调整布局管理器实现。处理大小调整、子控件剪裁等。 |
ResizableMinMax.h | 最小和最大窗口大小支持。 |
ResizablePage.h | 可调整大小的属性页实现。 |
ResizableSheet.h | 可调整大小的属性表实现。 |
ResizableState.h | 支持大小和位置存储。 |
ResizableMsgSupport.h | 对于自定义控件,我们可以使用消息来确定如何剪裁和刷新它。 |
ResizableVersion.h | 支持文件,用于正确确定 Windows 和 shell 版本。 |
RegisteredMsg.h | 用户注册消息的支持文件。 |
ResizableLib.h | 此文件包含以上所有内容。 |
使用代码
如果您想使用 WTL ResizableLib,则必须完成以下步骤:
- 将库提取到一个名为 ResizableLib 或任何其他名称的文件夹中。
- 在您的项目中,将库路径添加到 include 搜索路径。
- 在您的 stdafx.h 中插入
#include "ResizableLib.h"
。 - 请参阅本文的下一个示例,以简化大小调整。
这里有一个使用 ResizableLib 和 WTL 对话框的小代码示例,如上文所述。
#pragma once
#include <ResizableLib.h>
// MainDlg class
class CMainDlg:
public CResizableDialogImpl<CMainDlg>,
// Your inherited classes
public CUpdateUI<CMainDlg>,
public CMessageFilter,
public CIdleHandler
{
typedef CResizableDialogImpl<CMainDlg> baseClass;
public:
enum { IDD = IDD_MAINDLG };
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL OnIdle();
BEGIN_UPDATE_UI_MAP(CMainDlg)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainDlg)
CHAIN_MSG_MAP(baseClass) // First hadle messages
// in base class message map
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/,
LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/,
HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID,
HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID,
HWND /*hWndCtl*/, BOOL& /*bHandled*/);
// Your methods here
};
在 OnInitDialog
的实现中,您必须添加以下行:
// GrouBox behavior
AddAnchor(IDC_S1, TOP_LEFT, BOTTOM_RIGHT);
// ListBox behavior
AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT);
// OK Button behavior
AddAnchor(IDOK, BOTTOM_LEFT);
// Cancel Button behavior
AddAnchor(IDCANCEL, BOTTOM_CENTER);
// About Button behavior
AddAnchor(ID_APP_ABOUT, BOTTOM_RIGHT);
最后一步:如果您想保存和恢复对话框的大小和位置,您必须添加以下行:
EnableSaveRestore(HKEY_CURRENT_USER, "Software\\AlexTheBoss\\Settings\\",
PLACEMENT_ENT, "MainDlg");
// HKEY_CURRENT_USER: registry root key
// Software\\AlexTheBoss\\Settings\\: your application registry key
// PLACEMENT_ENT: define for windowplacment subkey
// MainDlg: your dialog name for storing placement in registry
这就是让您的对话框可调整大小所需的一切!
限制和问题
- 由于 WTL 的架构,您必须在对话框模板中手动设置
WS_THICKFRAME
。 - Groupboxes 在带主题的 WinXP 对话框中仍然会闪烁。
- 启用 XP 主题后,如果主题窗口框架不是矩形,您可能会在调整大小时看到无效的窗口框架。
下载次数
要构建演示项目,请创建一个新文件夹并将两个存档解压到该文件夹中,然后打开 ResizeTest.sln 并进行构建。简单的演示项目包含一个非常简单的对话框大小调整示例,您可以在上面的屏幕截图中看到。
在完整的演示中,您可以看到 ResizableLib 的最强大功能。
- 具有比例缩放的可调整大小的对话框。
- 可调整大小的属性表和向导。
- 带对话框的分割窗口位于其右侧窗格中。
- 主框架包含窗口位置的加载和保存。
- 主框架处理 MinMaxInfo。
历史
- 2005 年 2 月 18 日
- 首次公开发布。
- 2005 年 2 月 24 日
- 修复了
CResizableLayout<T>
中WM_NCCALCSIZE
处理程序的错误。 - 添加了新的大型示例。
- 文章已更新。
- 修复了