WTLVisual Studio .NET 2002Visual Studio 6Visual C++ 7.0Windows 2000Visual C++ 6.0IntermediateDevVisual StudioWindowsC++
WTL 可调整大小的对话框、表单视图和属性表






4.79/5 (9投票s)
2001年5月20日
6分钟阅读

176756

2769
WTL 可调整大小的对话框、表单视图和属性表的实现
引言
这些类提供了一种简单的方法,可以在 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
方法来创建属性表。
- 将您的属性表从
- 作为弹出窗口
- 在您自己的消息处理程序之前添加
CPopupResizablePropertySheetImpl
或CChildResizablePropertySheetImpl
的消息映射。
- 如果您想使用您的属性表
- 对于属性页
- 将您的属性页类从
CResizablePropertyPageImpl
派生,而不是从CPropertyPageImpl
派生。 - 覆盖
DefineLayout
方法以 设置布局约束。 - 定义数组
_controlsToClip
,该数组定义了 在绘制对话框时应剪裁的控件。
- 将您的属性页类从
- 属性表不会接收任何
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
方法)。这意味着当对话框调整大小时,子窗口既不会被调整大小也不会被移动。 -
子窗口的边可以附加到父窗口的同一边(
AttachForm
方法)。例如,以下代码AttachForm(IDC_1, ATTACH_RIGHT);
将产生以下效果
而以下代码AttachForm(IDC_1, ATTACH_LEFT); AttachForm(IDC_1, ATTACH_RIGHT);
将产生以下效果
子窗口的水平或垂直中心可以附加到父窗口。例如,以下代码AttachForm(IDC_1, ATTACH_HCENTER);
将产生以下效果 -
子窗口的边可以附加到父窗口的相反边(
AttachOppositeForm
方法)。例如,以下代码AttachOppositeForm(IDC_1, ATTACH_LEFT);
将产生以下效果 -
子窗口的边可以附加到另一个子窗口的相反边(
AttachWidget
方法)。例如,以下代码AttachForm(IDC_1, ATTACH_HCENTER); AttachWidget(IDC_2, ATTACH_LEFT, IDC_1);
将产生以下效果 -
子窗口的边可以附加到另一个子窗口的同一边(
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);
将产生以下效果
子窗口的水平或垂直中心可以附加到另一个子窗口的同一边。例如,以下代码AttachForm(IDC_1, ATTACH_LEFT); AttachForm(IDC_1, ATTACH_RIGHT); AttachOppositeWidget(IDC_2, ATTACH_HCENTER, IDC_1);
将产生以下效果
子窗口的边可以附加到一个随父窗口一起调整大小的不可见网格(
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);
将产生以下效果
避免屏幕闪烁
当对话框调整大小时,整个客户区域会用背景色填充,然后再绘制子窗口。这会导致屏幕闪烁。
需要做的是在绘制对话框背景之前剪裁子窗口。对话框可以具有 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日
- 修复了表单视图中最小尺寸和滚动条的处理方式
