本文将介绍如何在可调整视图中使用WTL(Windows Template Library)的CPropertySheetImpl模板。通过重写PropSheetCallback,可以改变属性页的风格,使其适应视图而非传统的模态或非模态对话框。此外,将探讨如何通过CDialogResize来处理控制元素的调整大小。CPropertySheetImpl位于atldlgs.h头文件中,而CDialogResize位于atlframe.h头文件中。
创建一个新的属性页类CPropView,它继承自CPropertySheetImpl和CDialogResize,以获得所需的行为。属性页模板提供了对标准Windows属性页控件的封装,而调整大小模板提供了移动或调整大小子控件的机制。然而,标准的属性页是为模态或非模态对话框设计的,而不是视图。为了克服默认行为,需要重写回调过程,并添加一个预创建消息处理程序来改变窗口风格,如下所示:
static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) {
if (uMsg == PSCB_PRECREATE) {
LPDLGTEMPLATE lpDT = (LPDLGTEMPLATE)lParam;
lpDT->style -= DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU;
lpDT->style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
return 0;
} else {
return CPropertySheetImpl::PropSheetCallback(hWnd, uMsg, lParam);
}
}
为了完成从独立对话框到视图的过渡,还需要进行其他样式的更改,但有两个障碍需要克服。第一个障碍是样式是扩展样式,在预创建中无法更改扩展样式。其次,属性页模板不处理WM_INITDIALOG消息,这通常是更改扩展样式的地方。因此,创建了一个初始化方法_Init,该方法通过设置WS_EX_CLIENTEDGE来修改属性页的扩展样式设置。它还初始化了对话框调整大小代码,并为属性页的标签控件进行了子类化。_Init方法由主框架的OnCreate()处理程序在视图创建后立即调用。
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方法中对标签控件进行子类化。
属性页也继承自CDialogResize,以便它们的子控件可以调整大小。尽管可以通过重写回调过程来更改页面样式,但更简单的方法是像这样将适当的窗口样式传递给对话框调整大小初始化器:
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {
DlgResize_Init(false, false, WS_CHILD | WS_CLIPCHILDREN);
return 0;
}
就像对任何使用对话框调整大小类的对话框一样,将想要调整大小或移动的任何控件或控件组添加到调整大小映射中。
在使用属性页和页面时,请记住:
某些窗口样式本身就提供了限制最小和最大窗口大小的能力。例如,WS_THICKFRAME和WS_CAPTION。包含任一或两者的复合样式,如WS_OVERLAPPEDWINDOW,也提供了这种能力。这些样式在移动或调整大小时会接收WM_GETMINMAXINFO消息。
可以通过在构造函数中初始化适当的成员变量来启用任何具有这些样式的窗口的最小(或最大)大小跟踪,如下所示:
POINT m_ptMinTrackSize;
CMainFrame() {
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设置为希望的最小值。
LRESULT OnWindowPosChanging(UINT, WPARAM, LPARAM lParam, BOOL&) {
LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;
if (lpWP->cx <= m_ptMinTrackSize.x) lpWP->cx = m_ptMinTrackSize.x;
if (lpWP->cy <= m_ptMinTrackSize.y) lpWP->cy = m_ptMinTrackSize.y;
return 0;
}