MFC程序员WTL指南(9)属性页与向导
2008-01-19 20:26:45 来源:WEB开发网正如你看到的,我们遇到了棘手的问题。PropSheetCallback()是一个静态方法,不能使用this指针访问属性表窗口。那将这些代码从CPropertySheetImpl::PropSheetCallback()中拷贝出来,然后添加我们自己的方法行不行呢?撇开刚才将代码和特定版本的WTL联系在一起的方法(这已经被证明不是各好方法),现在代码应该是这样的:
class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>
{
//...
static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM)
{
if(uMsg == PSCB_INITIALIZED)
{
// Code copied from WTL and tweaked to use CAppPropertySheet
// instead of T:
ATLASSERT(hWnd != NULL);
CAppPropertySheet* pT = (CAppPropertySheet*)
_Module.ExtractCreateWndData();
// subclass the sheet window
pT->SubclassWindow(hWnd);
// remove page handles array
pT->_CleanUpPages();
// Our own code follows:
pT->CenterWindow ( pT->m_psh.hwndParent );
}
return 0;
}
};
这从理论上讲很完美,但是我试过,属性表的位置并未改变。显然,通用控件的代码在我们调用CenterWindow()之后又改变了属性表窗口的位置。
必须放弃这个将代码封装到属性表类的方法,尽管它是个好的解决方案。我又回到原来的方案,即使用属性页窗口和属性表窗口相互协作是属性表窗口置中。我添加了一个用户定义消息UWM_CENTER_SHEET:
#define UWM_CENTER_SHEET WM_APP
CAppPropertySheet 在它的消息映射链中处理这个消息:
class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>
{
//...
BEGIN_MSG_MAP(CAppPropertySheet)
MESSAGE_HANDLER_EX(UWM_CENTER_SHEET, OnPageInit)
CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>)
END_MSG_MAP()
// Message handlers
LRESULT OnPageInit ( UINT, WPARAM, LPARAM );
protected:
bool m_bCentered; // set to false in the ctor
};
LRESULT CAppPropertySheet::OnPageInit ( UINT, WPARAM, LPARAM )
{
if ( !m_bCentered )
{
m_bCentered = true;
CenterWindow ( m_psh.hwndParent );
}
return 0;
}
然后,每个属性页的OnInitDialog() 方法发送这个消息到属性表窗口:
BOOL CBackgroundOptsPage::OnInitDialog ( HWND hwndFocus, LPARAM lParam )
{
GetPropertySheet().SendMessage ( UWM_CENTER_SHEET );
DoDataExchange(false);
return TRUE;
}
添加m_bCentered标志确保属性表窗口只响应收到的第一个UWM_CENTER_SHEET消息。
在属性页中添加图标如果要使用属性表和属性页的未被成员函数封装的特性,就需要直接访问相关的数据结构:CPropertySheetImpl类中的PROPSHEETHEADER类型(结构)成员m_psh和CPropertyPageImpl类中的PROPSHEETPAGE类型(结构)成员m_psp。
例如:为例子中Option属性表中的Background页面添加一个图标,就需要添加一个标志并设置属性页的PROPSHEETPAGE结构中的几个成员:
CBackgroundOptsPage::CBackgroundOptsPage()
{
m_psp.dwFlags |= PSP_USEICONID;
m_psp.pszIcon = MAKEINTRESOURCE(IDI_TABICON);
m_psp.hInstance = _Module.GetResourceInstance();
}
下面是这些代码的效果:
继续
我将在第九章介绍WTL的一些工具类,还有GDI对象和通用对话框的包装类。
修改记录September 13, 2003: 文章第一次发布。
更多精彩
赞助商链接