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

WTL 可调整大小的对话框、表单视图和属性表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (9投票s)

2001年5月20日

6分钟阅读

viewsIcon

176756

downloadIcon

2769

WTL 可调整大小的对话框、表单视图和属性表的实现

Resizable Form View

引言

这些类提供了一种简单的方法,可以在 WTL 中实现可调整大小的窗口,并进行子窗口的布局管理。支持以下内容:
  • 表单视图
  • 对话框
  • 属性表和属性页
此外,还支持将属性表用作子窗口。

如何在您的 WTL 应用程序中使用这些类

可调整大小的表单视图

  • 在您的对话框类的头文件中包含 LayoutMgr.h 文件,并将 LayoutMgr.cpp 文件添加到您的项目中。
  • 将您的表单视图类从 CResizableFormViewImpl 派生,而不是从 CDialogImpl 派生。
  • 在您自己的消息处理程序之前添加 CResizableFormViewImpl 的消息映射。
  • 覆盖 DefineLayout 方法以 设置布局约束
  • 定义数组 _controlsToClip,该数组定义了 在绘制对话框时应剪裁的控件
您的类应该如下所示
class MyFormView : public CResizableFormViewImpl<MyFormView>
{
public:
	typedef CResizableFormViewImpl<MyFormView> dlgBase;
	...
	BEGIN_MSG_MAP(MyFormView)
		CHAIN_MSG_MAP(dlgBase)
		...
	END_MSG_MAP()
	...
	virtual void DefineLayout();
	static const UINT _controlsToClip[];
};	

可调整大小的对话框

  • 在您的对话框类的头文件中包含 LayoutMgr.h 文件,并将 LayoutMgr.cpp 文件添加到您的项目中。
  • 将您的对话框类从 CResizableDialogImpl 派生,而不是从 CDialogImpl 派生。
  • 在您自己的消息处理程序之前添加 CResizableDialogImpl 的消息映射。
  • 覆盖 DefineLayout 方法以 设置布局约束
  • 定义数组 _controlsToClip,该数组定义了 在绘制对话框时应剪裁的控件
  • 在调用 CResizableDialogImpl 构造函数时,您可以更改标志 useHandle 的值。如果此标志设置为 true(默认值),则会在对话框的右下角显示一个调整大小的抓手。
  • 您的类应该如下所示
    class MyDialog : public CResizableDialogImpl<MyDialog>
    {
    public:
    	typedef CResizableDialogImpl<MyDialog> dlgBase;
    	...
    	BEGIN_MSG_MAP(MyDialog)
    		CHAIN_MSG_MAP(dlgBase)
    		...
    	END_MSG_MAP()
    	...
    	virtual void DefineLayout();
    	static const UINT _controlsToClip[];
    };	
    

    可调整大小的属性表

    • 在您的属性表和属性页类的头文件中包含 LayoutMgr.h 文件,并将 LayoutMgr.cpp 文件添加到您的项目中。
    • 对于属性表
      • 如果您想使用您的属性表
        • 作为弹出窗口
          • 将您的属性表类从 CPopupResizablePropertySheetImpl 派生,而不是从 CPropertySheetImpl 派生。
          • 在调用 CPopupResizablePropertySheetImpl 构造函数时,您可以更改标志 useHandle 的值。如果此标志设置为 true(默认值),则会在属性表的右下角显示一个调整大小的抓手。
        • 作为子窗口
          • 将您的属性表从 CChildResizablePropertySheetImpl 派生,而不是从 CPropertySheetImpl 派生。
          • 将用作属性表占位符的控件的 ID 传递给 CChildResizablePropertySheetImpl 构造函数的调用。
          • 在父窗口中调用 Create 方法来创建属性表。
      • 在您自己的消息处理程序之前添加 CPopupResizablePropertySheetImplCChildResizablePropertySheetImpl 的消息映射。
    • 对于属性页
    • 属性表不会接收任何 WM_INITDIALOG 消息。如果您想在属性表初始化后立即执行某些操作,可以覆盖 OnInitDialog 方法。
    您的属性表类应该如下所示
    class MyPropertySheet : public CPopupResizablePropertySheetImpl<MyPropertySheet>
    {
    public:
    	typedef CPopupResizablePropertySheetImpl<MyPropertySheet> dlgBase;
    	...
    	BEGIN_MSG_MAP(MyPropertySheet)
    		CHAIN_MSG_MAP(dlgBase)
    		...
    	END_MSG_MAP()
    	...
    };	
    
    您的属性页类应该如下所示
    class MyPropertyPage : public CResizablePropertyPageImpl<MyPropertyPage>
    {
    public:
    	typedef CResizablePropertyPageImpl<MyPropertyPage> dlgBase;
    	...
    	BEGIN_MSG_MAP(MyPropertyPage)
    		CHAIN_MSG_MAP(dlgBase)
    		...
    	END_MSG_MAP()
    	...
    	virtual void DefineLayout();
    	static const UINT _controlsToClip[];
    };	
    

    设置布局约束

    为了在对话框调整大小时布局子窗口,您必须覆盖 DefineLayout 方法。该方法在对话框初始化期间被调用,并允许定义子窗口之间的几何关系,从而可以按照所需的方式移动和调整它们的大小。

    设置布局约束的方式受到 Motif 的 XmForm 小部件方法的启发(非常老的东西……)。这有点繁琐,但非常简单高效。

    约束通过将子窗口的边附加到另一个子窗口的边或父窗口的某个边来定义。

    • 默认情况下,子窗口的所有边都没有约束AttachNone 方法)。这意味着当对话框调整大小时,子窗口既不会被调整大小也不会被移动。

      No constraints

    • 子窗口的边可以附加到父窗口的同一边AttachForm 方法)。例如,以下代码
      	AttachForm(IDC_1, ATTACH_RIGHT);
      
      将产生以下效果

      AttachForm(ATTACH_RIGHT)

      而以下代码
      	AttachForm(IDC_1, ATTACH_LEFT);
      	AttachForm(IDC_1, ATTACH_RIGHT);
      
      将产生以下效果

      AttachForm(ATTACH_LEFT & ATTACH_RIGHT)

      子窗口的水平或垂直中心可以附加到父窗口。例如,以下代码
      	AttachForm(IDC_1, ATTACH_HCENTER);
      
      将产生以下效果

      AttachForm(ATTACH_HCENTER)

    • 子窗口的边可以附加到父窗口的相反边AttachOppositeForm 方法)。例如,以下代码
      	AttachOppositeForm(IDC_1, ATTACH_LEFT);
      
      将产生以下效果

      AttachOppositeForm(ATTACH_LEFT)

    • 子窗口的边可以附加到另一个子窗口的相反边AttachWidget 方法)。例如,以下代码
      	AttachForm(IDC_1, ATTACH_HCENTER);
      	AttachWidget(IDC_2, ATTACH_LEFT, IDC_1);
      
      将产生以下效果

      AttachWidget

    • 子窗口的边可以附加到另一个子窗口的同一边AttachOppositeWidget 方法)。例如,以下代码
      	AttachForm(IDC_1, ATTACH_LEFT);
      	AttachForm(IDC_1, ATTACH_RIGHT);
      	AttachOppositeWidget(IDC_2, ATTACH_LEFT, IDC_1);
      	AttachOppositeWidget(IDC_2, ATTACH_RIGHT, IDC_1);
      
      将产生以下效果

      AttachOppositeWidget

      子窗口的水平或垂直中心可以附加到另一个子窗口的同一边。例如,以下代码
      	AttachForm(IDC_1, ATTACH_LEFT);
      	AttachForm(IDC_1, ATTACH_RIGHT);
      	AttachOppositeWidget(IDC_2, ATTACH_HCENTER, IDC_1);
      
      将产生以下效果

      AttachOppositeWidget(ATTACH_HCENTER)

    • 子窗口的边可以附加到一个随父窗口一起调整大小的不可见网格AttachPosition 方法)。例如,以下代码
      	SetNPositions(3);
      	AttachPosition(IDC_1, ATTACH_LEFT, 0);
      	AttachPosition(IDC_1, ATTACH_RIGHT, 1);
      	AttachPosition(IDC_2, ATTACH_LEFT, 1);
      	AttachPosition(IDC_2, ATTACH_RIGHT, 2);
      	AttachPosition(IDC_3, ATTACH_LEFT, 2);
      	AttachPosition(IDC_3, ATTACH_RIGHT, 3);
      
      将产生以下效果

      AttachPosition

    避免屏幕闪烁

    当对话框调整大小时,整个客户区域会用背景色填充,然后再绘制子窗口。这会导致屏幕闪烁。

    需要做的是在绘制对话框背景之前剪裁子窗口。对话框可以具有 WS_CLIPCHILDREN 窗口样式,这可以确保在绘制之前剪裁所有对话框子窗口。但大多数情况下,无法使用此样式,因为像静态控件这样的控件不会自己绘制背景。

    为了避免这种情况,所有 CResizableXXXImpl 类都处理 WM_ERASEBKGND 消息。这些类会从用于绘制背景的 DC 中排除 ID 包含在 _controlsToClip 数组中的所有控件。因此,为了避免屏幕闪烁,您只需“覆盖” _controlsToClip 数组即可。

    您的类应该如下所示

    class MyDialog : public CResizableDialogImpl<MyDialog>
    {
    	...
    	static const UINT _controlsToClip[];
    };	
    
    const UINT MyDialog::_controlsToClip[] = 
    {
    	IDC_IMG,
    	IDOK,
    	...
    	0
    };
    

    注意

    当前的 Gode 在使用 Windows XP 主题时,对某些控件(选项卡控件和滚动窗口出现问题)的剪裁处理不正确。因此,在使用 Windows XP 时,禁止自动剪裁子控件。

    托管 ActiveX 控件

    如果您的对话框托管 ActiveX 控件,请使用

    • CAxResizableDialogImpl 而不是 CResizableDialogImpl
    • CAxResizableFormViewImpl 而不是 CResizableFormViewImpl
    • CAxResizablePropertyPageImpl 而不是 CResizablePropertyPageImpl

    对话框的最小尺寸

    为了避免处理 10x10 像素的对话框,为对话框和表单视图设置了最小尺寸。

    • 对于对话框,最小尺寸是对话框模板的大小(在对话框编辑器中设置的大小)。用户无法将对话框窗口调整到小于此最小尺寸。
    • 对于表单视图,最小尺寸是对话框模板的大小(在对话框编辑器中设置的大小)。如果用户将视图调整到小于此最小尺寸,将显示滚动条。
    • 对于“弹出”属性表,最小尺寸是属性表创建后的尺寸。此尺寸应该是属性页对话框模板的最大尺寸。

    最新更新

    • 2002年7月9日
      • 修复了使用 WTL7 和 ATL7 时出现的某些类名冲突
      • 根据 Daniel Bowen 的建议,用标准滚动条替换了 SizeGrip 窗口
      • 添加了 Unattach 方法,用于从布局管理器管理窗口列表中移除控件
      • 添加了最大尺寸。最大尺寸信息仅在 _maxWindowSize.cx 或 _maxWindowSize.cy 大于 0 时使用
      • 实现了对 ATL7 错误(阻止在 CAxPropertySheetImpl 中初始化 ActiveX 控件)的修复
      • 在处理 Windows XP 时禁用了剪裁代码
    • 2001年9月7日
      • 添加了对托管 ActiveX 控件的支持。
      • 将用户消息从任意常量更改为已注册的消息
    • 2001年5月22日
      • 修复了表单视图中最小尺寸和滚动条的处理方式

    Serge
    © . All rights reserved.