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

使用 WTL 内置的对话框调整大小类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (28投票s)

2001 年 6 月 25 日

5分钟阅读

viewsIcon

397081

downloadIcon

2727

如何使用 WTL 对可调整大小对话框的内置支持

引言

最近我一直在学习 WTL,偶然发现了一个似乎没有被提及过的相当有趣的类:CDialogResize。鉴于 MFC 中有大量实现可调整大小对话框的示例,WTL 提供自己的类真是太好了,这样您只需学习一个类和一种指定哪些控件需要调整大小的方法。在本文中,我将概述 WTL 的缩放支持,并提供一个示例程序来说明其中一些功能。您应该已经熟悉 WTL 以及如何安装它。如果您需要这方面的帮助,WTL 部分有相关的文章。

使用 CDialogResize

基础知识

与许多其他 WTL 功能一样,您首先需要将 CDialogResize 添加到对话框类的继承列表中。因此,如果您使用 WTL AppWizard 创建一个基于对话框的应用程序,则需要在红色显示的行中添加此处列出的代码:

class CMainDlg : public CAxDialogImpl<CMainDlg>,
                 public CDialogResize<CMainDlg>

CDialogResize 声明在 atlframe.h 中,因此如果您的头文件中还没有,请添加该头文件。

下一步是在对话框的 OnInitDialog 处理程序中初始化 CDialogResize 代码:

    LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        // Init the CDialogResize code

        DlgResize_Init();
    ...
    }

DlgResize_Init() 有几个可选参数,我稍后会介绍。

接下来,在对话框的消息映射中添加一个条目,将缩放消息传递给 CDialogResize

    BEGIN_MSG_MAP(CMainDlg)
        MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
        ...
        CHAIN_MSG_MAP(CDialogResize<CMainDlg>)
    END_MSG_MAP()

最后,在对话框类中添加一个新的映射,列出对话框中哪些控件将要被缩放:

class CMainDlg : public CAxDialogImpl<CMainDlg>, public CDialogResize<CMainDlg>
{
...
public:
    BEGIN_DLGRESIZE_MAP(CMainDlg)
    END_DLGRESIZE_MAP()
...
};

我将在“设置缩放映射”部分介绍如何填充此映射。

初始化 CDialogResize

CDialogResize 通过调用 DlgResize_Init() 进行初始化。其原型为:

void CDialogResize::DlgResize_Init (
    bool bAddGripper = true,
    bool bUseMinTrackSize = true,
    DWORD dwForceStyle = WS_THICKFRAME | WS_CLIPCHILDREN );

参数如下:

  • bAddGripper:此参数控制 CDialogResize 是否在对话框的右下角添加一个大小调整手柄。传递 true 添加大小调整手柄,传递 false 则不添加。
  • bUseMinTrackSize:此参数控制 CDialogResize 是否限制对话框的最小尺寸。如果传递 true,则不允许将对话框缩小到小于其初始尺寸(如资源文件中所示)。如果不希望限制对话框的最小尺寸,请传递 false
  • dwForceStyle:指定应用于对话框的窗口样式。默认值通常就足够了。

设置缩放映射

对话框缩放映射告诉 CDialogResize 要移动或缩放哪些控件。一个条目的格式如下:

    DLGRESIZE_CONTROL(ControlID, Flags)

ControlID 是对话框控件的 ID。可能的标志及其含义如下:

  • DLSZ_SIZE_X:当对话框水平缩放时,调整控件的宽度。
  • DLSZ_SIZE_Y:当对话框垂直缩放时,调整控件的高度。
  • DLSZ_MOVE_X:当对话框水平缩放时,水平移动控件。
  • DLSZ_MOVE_Y:当对话框垂直缩放时,垂直移动控件。
  • DLSZ_REPAINT:每次移动/缩放后使控件无效,以便它每次都重绘。

请注意,您不能在同一维度上移动和缩放控件。例如,如果同时指定 DLSZ_MOVE_XDLSZ_SIZE_X,则尺寸标志将被忽略。

您还可以将控件分组,使它们能够相对于彼此成比例地移动和缩放。我稍后将介绍此主题。

示例项目

本文附带的示例项目是一个简单的基于对话框的应用程序,它充当浏览器(使用 WebBrowser ActiveX 控件)。控件 ID 如下所示;当讨论移动和缩放这些控件时,您应该参考此图。

 [Dlg control IDs - 17K]

控件将按照以下规则移动和缩放:

  • Location 编辑框将水平缩放。
  • GoExitAbout 按钮将水平移动。
  • BackForwardStopRefresh 按钮将作为一个组水平缩放。
  • 浏览器控件将水平和垂直缩放。

浏览器控件的 OnInitDialog() 函数如下初始化 CDialogResize

    LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, 
                         BOOL& /*bHandled*/)
    {
        // Init the CDialogResize code

        DlgResize_Init();
        ...
    }

这使用了 DlgResize_Init() 的默认参数,这会导致添加一个大小调整手柄。此外,对话框不能缩小到小于其初始尺寸。对话框启动时的样子如下:

 [Main dialog - 28K] \

这是缩放映射,列出了控件的移动和缩放行为。请注意新的宏 - BEGIN_DLGRESIZE_GROUP()END_DLGRESIZE_GROUP() - 将四个浏览器控件按钮放入一个缩放组中。

    BEGIN_DLGRESIZE_MAP(CMainDlg)
        // Location edit box

        DLGRESIZE_CONTROL(IDC_URL, DLSZ_SIZE_X)

        // Go, Exit, About buttons

        DLGRESIZE_CONTROL(IDC_GO, DLSZ_MOVE_X)
        DLGRESIZE_CONTROL(IDC_EXIT, DLSZ_MOVE_X)
        DLGRESIZE_CONTROL(ID_APP_ABOUT, DLSZ_MOVE_X)

        // IE control buttons

        BEGIN_DLGRESIZE_GROUP()
            DLGRESIZE_CONTROL(IDC_BACK, DLSZ_SIZE_X)
            DLGRESIZE_CONTROL(IDC_FORWARD, DLSZ_SIZE_X)
            DLGRESIZE_CONTROL(IDC_STOP, DLSZ_SIZE_X)
            DLGRESIZE_CONTROL(IDC_REFRESH, DLSZ_SIZE_X)
        END_DLGRESIZE_GROUP()

        // WebBrowser control

        DLGRESIZE_CONTROL(IDC_BROWSER, DLSZ_SIZE_X|DLSZ_SIZE_Y)
    END_DLGRESIZE_MAP()

缩放后的对话框如下:

 [Bigger dialog - 61K]

请注意,编辑框更宽,浏览器控件更宽更高。这四个分组按钮的行为有点难以用言语形容,WTL 代码几乎没有提供指导,因为注释很少。但基本思想是:想象一个围绕所有四个按钮的边界矩形。该矩形像任何其他控件一样缩放,所有按钮都按比例缩放,以保持在边界矩形内。如果按钮被移动而不是缩放,它们将被放置在彼此之间均匀间隔的位置。请注意,组中的所有控件应具有相同的 DLSZ_* 标志以产生有意义的行为。

CDialogResize 的错误和问题

到目前为止,我只遇到两个问题。一个问题是似乎存在一个偏移一像素的错误,因为第一次缩放对话框时,一些控件会朝着错误的方向偏移一像素。另一个更严重的问题是 WTL AppWizard 中的一个错误,当您将 CDialogResize 添加为对话框的基类时,该错误会暴露出来。AppWizard 生成的显示对话框的代码如下所示:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, 
                     LPTSTR lpstrCmdLine, int nCmdShow)
{
    // ...

    CMainDlg dlgMain;
    int nRet = dlgMain.DoModal();

    _Module.Term();
    ::CoUninitialize();

    return nRet;
}

问题在于 CMainDlg 的析构函数在 _Module.Term() 之后被调用。如果在定义了 _ATL_MIN_CRT 符号的情况下构建 release 版本,这会导致崩溃。解决方案是将 CMainDlg 对象放在一个包含块中:

int nRet;

    {
    CMainDlg dlgMain;
    nRet = dlgMain.DoModal();
    }
© . All rights reserved.