WTL CPropertySheet 作为可调整大小的视图






4.92/5 (8投票s)
2002年4月1日
4分钟阅读

103591

3263
如何将 WTL 的 CPropertySheet 实现用作可调整大小的视图,


引言
本文介绍如何在可调整大小的视图中使用 WTL 的 CPropertySheetImpl
模板。重写的 PropSheetCallback
更改属性表的样式,以便将其用作视图。属性表的标签控件的子类处理属性页的调整大小。属性表和属性页使用 CDialogResize
来处理控件的调整大小。CPropertySheetImpl
位于 atldlgs.h
头文件中,而 CDialogResize
位于 atlframe.h
中。
属性表
我们新的属性表类 CPropView
继承自 CPropertySheetImpl
和 CDialogResize
,以获得其期望的行为。属性表模板封装了标准的 Windows 属性表控件,而调整大小模板则提供了移动或调整子控件大小的机制。
然而,标准的属性表被设计为模态或非模态对话框窗口,而不是视图。为了克服默认行为,请重写回调过程并添加预创建消息处理程序来更改窗口样式,如下所示。
static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) { // dialog template is available and changeable pre-creation if(uMsg == PSCB_PRECREATE) { LPDLGTEMPLATE lpDT = (LPDLGTEMPLATE)lParam; // remove dialog border styles lpDT->style -= DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU; // add child window and clipping styles lpDT->style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; return 0; } else // call inherited method to handle PSCB_INITIALIZED return CPropertySheetImpl< CPropView >::PropSheetCallback(hWnd, uMsg, lParam); }
还需要进行一项样式更改才能从独立对话框转换为视图,但这存在两个障碍。第一个障碍是样式是扩展样式,无法在预创建中更改扩展样式。其次,属性表模板不处理 WM_INITDIALOG
消息,而通常可以在此更改扩展样式。
因此,我们创建了一个初始化方法。此方法 _Init
通过设置 WS_EX_CLIENTEDGE
来修改属性表的扩展样式设置。它还初始化对话框调整大小代码并对属性表的标签控件进行子类化。_Init
在视图创建后不久由主框架的 OnCreate()
处理程序调用。
Tab Control
Windows 属性表使用普通的标签控件来承载属性页。标签控件的标识符是 ATL_IDC_TAB_CONTROL
。为了调整标签控件的大小,进而调整其属性页的大小,请将其作为可调整大小的控件添加到属性表的调整大小映射中。属性表按钮(如下面的示例中未显示)也作为可移动控件添加到调整大小映射中。
BEGIN_DLGRESIZE_MAP(CPropView) DLGRESIZE_CONTROL(ATL_IDC_TAB_CONTROL, DLSZ_SIZE_X | DLSZ_SIZE_Y) END_DLGRESIZE_MAP()
一旦标签控件被放入调整大小映射中,它将从对话框调整大小代码接收大小调整消息。但是,还需要一个额外的步骤,因为消息不会中继到属性页。这通过一个提供 WM_WINDOWPOSCHANGED
消息处理的标签控件模板来实现。在属性类 CPropView
的 _Init
方法中对标签控件进行子类化。
这是位置更改消息的处理程序
LRESULT OnWindowPosChanged(UINT, WPARAM, LPARAM lParam, BOOL&) { // get window position structure from lParam LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam; // initialize a property sheet variable with the parent's handle CPropertySheet m_sheet; m_sheet.m_hWnd = GetParent(); // set the size of the active property page to slightly smaller // than the tab control's new client area size ::SetWindowPos(m_sheet.GetActivePage(), NULL, 0, 0, lpWP->cx - 8, lpWP->cy - 25, SWP_NOMOVE); // release the property sheet handle since we don't own it m_sheet.m_hWnd = NULL; return 0; }
现在,标签控件在收到属性表大小调整处理程序的通知后会调整活动属性页的大小。其他属性页在变为活动状态时会被调整大小。(注意:如果您希望控制视图或页面可以达到的最小或最大大小,请参阅本文稍后的“侧边栏关于窗口大小”)。
属性页
属性页也继承自 CDialogResize
,以便调整其子控件的大小。虽然您可以重写回调过程来更改页面样式,但更简单的方法是像这样将适当的窗口样式传递给对话框调整大小初始化程序:
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) { // init resize code. No gripper, no min size tracking, Child window style DlgResize_Init(false, false, WS_CHILD | WS_CLIPCHILDREN); return 0; }
将您希望调整大小或移动的任何控件或控件组添加到调整大小映射中,就像您为使用对话框调整大小类的任何对话框所做的那样。
提醒
在使用属性表和属性页时,请记住:
- 在属性表的构造函数中至少创建一个属性页
- 某些参数更改必须在表或页创建之前发生
另外,请注意,组合框与 WS_CLIPCHILDREN
样式不能很好地共存。如果您打算使用它们,请从属性页的 DlgResize_Init()
中删除剪裁子控件样式,并准备好忍受一些屏幕闪烁。
侧边栏关于窗口大小
某些窗口样式本身就提供了限制最小和最大窗口大小的功能。例如,WS_THICKFRAME
和 WS_CAPTION
。包含其中一个或两个样式的复合样式,例如 WS_OVERLAPPEDWINDOW
,也提供了此功能。这些样式在移动或调整大小时会收到 WM_GETMINMAXINFO
消息。
您可以通过在构造函数中初始化适当的成员变量来为具有这些样式的任何窗口(如主框架)启用最小(或最大)大小跟踪,如下所示:
POINT m_ptMinTrackSize; CMainFrame() { // initialize minimum size tracking variables m_ptMinTrackSize.x = -1; m_ptMinTrackSize.y = -1; }
接下来,向消息映射添加一个 WM_GETMINMAXINFO
条目,并添加以下消息处理程序:
LRESULT OnGetMinMaxInfo(UINT, WPARAM, LPARAM lParam, BOOL&) { if (m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) { LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; lpMMI->ptMinTrackSize = m_ptMinTrackSize; } return 0; }
最后,在 OnCreate
处理程序中将 m_ptMinTrackSize.x
和 m_ptMinTrackSize.y
设置为您期望的最小值。
对于不原生支持最小大小跟踪的窗口样式,请使用 WM_WINDOWPOSCHANGING
消息的处理程序来实现类似的结果,如下所示。根据需要,在创建或初始化处理程序中设置您的 x 和 y 跟踪值。
LRESULT OnWindowPosChanging(UINT, WPARAM, LPARAM lParam, BOOL&) { // get window position structure from lParam LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam; // don't allow resizing below minimum x if (lpWP->cx <= m_ptMinTrackSize.x) lpWP->cx = m_ptMinTrackSize.x; // don't allow resizing below minimum y if (lpWP->cy <= m_ptMinTrackSize.y) lpWP->cy = m_ptMinTrackSize.y; return 0; }
使用条款
本文提供的示例项目和属性表/页类是免费的。您可以随意使用它们。
本软件按“现状”分发,不提供任何形式的担保。