工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > 开发专栏 > VC > 正文
MFC程序员的WTL指南之属性页与向导
[文章信息]
作者:LITHE
时间:2005-03-23
出处:VCKBASE
责任编辑:方舟
[文章导读]
向导模式的属性表通常用来引导用户安装软件或完成其他复杂的工作
advertisement
专题教程宝典
【软件应用】
【办公软件】
【图形图像】
【网页制作】
【操作系统】
【网络安全】
【程序开发】
【日报周刊】
【多媒体教程】
· 天极软件应用多媒体教程
· 微软对.NET失去信心?.NET专家激起千层浪
· Outlook使用技巧大全之一
· 抢先试用卡巴斯基 KIS 2006
· 自己动手制作手机Flash主题动画
· 完美的C++:C++/CLI
· 四款网络监控软件测评
· 中搜网络猪风行天下使用感受
· 数字证书使用一点通
· 软件消费服务信息指南
[正文]

上一页  1 2 3 4 5  

  使用DDV添加更多的属性页

  为了使这个向导能够有点用处,我们要为其添加一个设置视图背景颜色的页面。这个页面还将有一个checkbox演示如何处理DDV验证失败并阻止向导进行到下一页。下面就是新的页面,ID是IDD_WIZARD_BKCOLOR:

           

  这个类的实现代码在CWizBkColorPage类中,下面是相关的部分代码

class CWizBkColorPage :
public CPropertyPageImpl<CWizBkColorPage>,
public CWinDataExchange<CWizBkColorPage>
{
 public:
  // some stuff removed for brevity...

  BEGIN_DDX_MAP(CWizBkColorPage)
   DDX_RADIO(IDC_BLUE, m_nColor)
   DDX_CHECK(IDC_FAIL_DDV, m_bFailDDV)
  END_DDX_MAP()

  // Notification handlers
  int OnSetActive();
  BOOL OnKillActive();

  // DDX vars
  int m_nColor;

 protected:
  int m_bFailDDV;
};

  OnSetActive()的工作和前面的介绍页面相同,它使“上一步”和“下一步”按钮可用。OnKillActive()是个新的处理函数,它触发DDV,然后检查m_bFailDDV的值,如果是TRUE就表示checkbox处于选中状态,OnKillActive()将阻止向导进行到下一页。

int CWizBkColorPage::OnSetActive()
{
 SetWizardButtons ( PSWIZB_BACK | PSWIZB_NEXT );
 return 0;
}

int CWizBkColorPage::OnKillActive()
{
 if ( !DoDataExchange(true) )
  return TRUE; // prevent deactivation

 if ( m_bFailDDV )
 {
  MessageBox (_T("Error box checked, wizard will stay on this page."),_T("PSheets"), MB_ICONERROR );
  return TRUE; // prevent deactivation
 }

 return FALSE; // allow deactivation
}

  需要注意的是OnKillActive()中做的事情也可以在OnWizardNext()中完成,因为这两个处理函数都可以使向导维持在当前页面。它们的不同之处在于OnKillActive()在用户单击“上一步”和“下一步”按钮时被调用,而OnWizardNext()只是在用户单击“下一步”按钮时被调用。OnWizardNext()还被用来完成其它目的,比如,它可以直接将向导引导到指定的页面而不是按顺序的下一页。

  例子工程的向导还有另外两个页面,CWizBkPicturePage 和 CWizFinishPage,由于它们和前面的两个页面相似,我就不再详细介绍它们,想了解它们的细节可以查看源代码。

  其他的界面考虑

  置中一个属性表


  属性页和向导的默认位置是出现在父窗口的左上角:


  这看起来有点不爽,还好有方法可以补救。第一种方法是重载CPropertySheetImpl::PropSheetCallback()函数,在这个函数中将属性表置中。PropSheetCallback()是MSDN中介绍的PropSheetProc()的回调函数,操作系统在属性表创建时调用这个函数,WTL也是利用这个时间子类化属性表窗口的。所以我们的第一种尝试是:

class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>
{
 //...
 static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
 {
  int nRet = CPropertySheetImpl<CAppPropertySheet>::PropSheetCallback (hWnd, uMsg, lParam );

  if ( PSCB_INITIALIZED == uMsg )
  {
   // center sheet... somehow?
  }

  return nRet;
 }
};

  正如你看到的,我们遇到了棘手的问题。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();
}

  下面是这些代码的效果:


上一页  1 2 3 4 5  

天极社区邀请您:写博客日记  上传相片   论坛聊天  订阅电子杂志  推荐网摘   免费图铃工具
笔名:   请您注意:

 遵守国家有关法律、法规,尊重网上道德,承担一切因您的行为而直接或间接引起的法律责任。

 天极网拥有管理笔名和留言的一切权利。
评论:
 
发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • Visual C++ 6.0制作QQ连连看外挂
  • VC实现光驱、软驱、USB的禁用和启用
  • Visual C++中的日历控件使用详解
  • Visual C++小技巧:实现透明窗体
  • VC程序中实现控件的动态生成与响应
  • 3家搜索引擎集体诉讼8848 吕春维未敢出席
  • 杨元庆:没有准备不会获批的备用方案
  • 【315】华硕笔记本电脑漏电 存在设计缺陷
  • 军队信息化诞生新领域 电子军务呼之欲出
  • 世界经济论坛公布信息化程度全球最新排名
  • 2004政务绩效评估:政府门户尚处于发展阶段
  • 甲骨文出资5.15亿美元 意图收购RetekInc
  • 技术并购:帮你突破传统增长的“天花板”
  • Advertisement