⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtl for mfc programmers, part viii - property sheets and wizard.htm

📁 MFC程序员的WTL指南,非常具体,WTL入门最好的书
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>
<head>
<title>WTL for MFC Programmers, Part VIII - Property Sheets and Wizards</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>

<body bgcolor="#33CCCC" text="#000000">
<p align="center"><b><font style="FONT-SIZE: 16pt" size="4" color="#0033CC">WTL 
  for MFC Programmers, Part VIII - Property Sheets and Wizards</font></b><br>
  <br>
</p>
<p align="left">原作 :<b><font color="#CC3366">Michael Dunn</font></b> [<a href="http://www.codeproject.com/wtl/WTL4MFC8.asp">英文原文</a>]<br>
  翻译 :<a href="mailto:inte2000@163.com">Orbit(桔皮干了)</a> [<a href="http://www.winmsg.com/cn/orbit.htm">http://www.winmsg.com/cn/orbit.htm</a>]</p>
<p align="left"><a href="demo/WTL4MFC8_demo.zip">下载演示程序代码</a></p>
 
<H2><font color="#FFFF66">本章内容</font></H2>
      <UL>
        <LI><A 
        href="#intro">介绍</A> 

        <LI><A href="#sheetclasses">WTL 的属性表类</A> 
        <UL>
          <LI><A href="#sheetmethods">CPropertySheetImpl 的方法</A> </LI></UL>
        <LI><A href="#pageclasses">WTL 的属性页类</A> 
        <UL>
          <LI><A href="#pagewinmethods">CPropertyPageWindow 的方法</A> 
          <LI><A href="#pageimplmethods">CPropertyPageImpl 的方法</A> 
          <LI><A href="#handlingnotify">处理通知消息</A> </LI></UL>
        <LI><A href="#creatingsheet">创建一个属性表</A> 
        <UL>
          <LI><A href="#simplesheet">最简单的属性表</A> 
          <LI><A href="#usefulpage">创建一个有用的属性页</A> 
          <LI><A href="#bettersheet">创建一个更好的属性表类</A> </LI></UL>
        <LI><A href="#createwiz">创建向导样式的属性表</A> 
        <UL>
          <LI><A href="#morepages">添加更多的属性页,使用DDV</A> </LI></UL>
        <LI><A href="#otherui">其他的界面考虑</A> 
        <UL>
          <LI><A href="#centersheet">置中一个属性表</A> 
          <LI><A href="#addicons">在属性页中添加图标</A> </LI></UL>
        <LI><A href="#upnext">继续</A> 
        <LI><A href="#revisionhistory">修改记录</A> </LI></UL>

<H2><A name=intro></A><font color="#FFFF66">介绍</font></H2>
      
<P>甚至在成为Windows 95的通用控件之前,使用属性表来表示一些选项就已经成为一种很流行的方式。向导模式的属性表通常用来引导用户安装软件或完成其他复杂的工作。WTL对这两种方式的属性表都提供了很好的支持,可以使用前面介绍的与对话框相关的特性,如DDX和DDV。在本章我将演示如何创建一个基本的属性表和向导,如何处理属性页发送的通知消息和事件。</P>
      
<H2><A name=sheetclasses></A><font color="#FFFF66">WTL 的属性表类</font></H2>
      
<P>实现一个属性表需要CPropertySheetWindow和CPropertySheetImpl两个类联合使用,它们都定义在atldlgs.h头文件中。CPropertySheetWindow类是一个窗口接口类(也就是说是一个CWindow派生类),CPropertySheetImpl有消息映射链和窗口的完整实现,这和ATL的基本窗口类相似,它需要CWindow和CWindowImpl两个类联合使用。</P>
<p>CPropertySheetWindow类封装了对各种PSM_* 消息的处理,例如,SetActivePageByID()封装了PSM_SETCURSELID消息。CPropertySheetImpl类管理一个PROPSHEETHEADER结构和一个HPROPSHEETPAGE类型的数组,CPropertySheetImpl类还提供了 
  <br>
  一些方法用来填充PROPSHEETHEADER结构,添加或删除属性页,你也可以使用m_psh成员变量直接操作PROPSHEETHEADER结构。</p>
<p>最后,CPropertySheet类是CPropertySheetImpl类的一个特例,你可以直接使用它而不需要定制整个属性表。</p>
<H3><A name=sheetmethods></A><font color="#FFFF66">CPropertySheetImpl 的方法</font></H3>
      
<P><br>
  下面是CPropertySheetImpl类的一些重要方法。由于许多方法仅仅是对窗口消息的封装,所以就不在这里列出,你可以查看atldlgs.h中完整的函数清单。</P>
<PRE><font color="#0033FF">CPropertySheetImpl(_U_STRINGorID title = (LPCTSTR) NULL,
                   UINT uStartPage = <SPAN class=cpp-literal>0</SPAN>, HWND hWndParent = NULL)</font></PRE>
      
<P>CPropertySheetImpl类的构造函数允许你使用一些常用的属性(默认值),所以就不需要在调用其他的方法设置它们。title指定显示在属性表的标题栏的文字,_U_STRINGorID是一个WTL的工具类,它可以自动转换LPCTSTR和资源ID,例如,下面的两行代码都是正确的:<br>
</P>
<PRE><font color="#0033FF">  CPropertySheetImpl mySheet ( IDS_SHEET_TITLE );
  CPropertySheetImpl mySheet ( _T(<SPAN class=cpp-string>"My prop sheet"</SPAN>) );</font></PRE>
<P>IDS_SHEET_TITLE 是字符串的ID。 uStartPage 是属性表启动时激活的属性页,是一个从0开始的索引。hWndParent 是属性表的父窗口的句柄。</P>
<p><font color="#0000FF">BOOL AddPage(HPROPSHEETPAGE hPage)<br>
  BOOL AddPage(LPCPROPSHEETPAGE pPage)</font></p>
<p>添加一个属性页。如果这个属性页已经创建了,你可以使用第一个重载函数,使用属性页的句柄(HPROPSHEETPAGE)作为参数。通常是使用第二个重载函数,使用这个重载函数只需设置一个PROPSHEETPAGE数据结构(后面会讲到,它和CPropertyPageImpl一起协同工作),CPropertySheetImpl会为你创建并管理这个属性页。</p>
<p><font color="#0000FF">BOOL RemovePage(HPROPSHEETPAGE hPage)<br>
  BOOL RemovePage(int nPageIndex)</font></p>
<P>移除一个属性页,可以使用属性页的句柄或索引。</P>
<p><font color="#0000FF">BOOL SetActivePage(HPROPSHEETPAGE hPage)<br>
  BOOL SetActivePage(int nPageIndex)</font></p>
<p>设置属性表的活动页面。可以使用属性页的句柄或索引。你可以在属性表创建(显示)之前使用这个方法动态的设置处于激活的属性页。</p>
<p><font color="#0000FF">void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)</font></p>
<p>使之属性表窗口的标题文字。nStyle可以是0或PSH_PROPTITLE,如果是PSH_PROPTITLE,则属性表就具有PSH_PROPTITLE样式,这样系统会在你通过lpszText参数指定的窗口标题前添加字符串“Properties 
  for”。</p>
<PRE><font color="#0000FF">void SetWizardMode()</font></PRE>
<p>设置PSH_WIZARD样式,将属性表改称向导模式,这个函数必须在属性表显示之前调用。</p>
<p><font color="#0000FF">void EnableHelp()</font></p>
<p>设置PSH_HASHELP样式,将在属性表中添加帮助按钮。需要注意的是你还要在每个属性页中使帮助按钮可用并提供帮助才能使之生效。</p>
<p><font color="#0000FF">INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())</font></p>
<p>创建并显示一个模式的属性表,返回正值表示操作成功,有关PropertySheet() API的帮助文档有有关返回值的详细解释,如果发生错误,属性表无法创建,DoModal()返回-1。</p>
<p><font color="#0000FF">HWND Create(HWND hWndParent = NULL)</font></p>
<p>创建并显示一个无模式的属性表,返回值是窗口的句柄,如果发生错误,属性表无法创建,Create()返回NULL。</p>
<H2><A name=pageclasses></A><font color="#FFFF66">WTL 的属性页类</font></H2>
      
<P>WTL对属性页的封装类与属性表的封装类相似,有一个窗口接口类 CPropertyPageWindow 和一个实现类 CPropertyPageImpl 
  。CPropertyPageWindow 很小,包含最常用的需要在作为父窗口的属性表中调用的方法。</P>
<p>CPropertyPageImpl 是从 CDialogImplBaseT派生,由于属性页是从对话框资源中创建的,这就意味着所有可以在对话框中使用的WTL的特性都可以在属性页中使用,如DDX和DDV。CPropertyPageImpl 
  有两个主要作用:管理一个PROPSHEETPAGE数据结构(保存在成员变量m_psp中),处理所有PSN_开头的通知消息。对于很简单的属性页可以直接使用CPropertyPage类,这个类只适合与用户没有任何交互的属性页,例如“关于”页面或者向导中的介绍页面</p>
<p>也可以创建含有ActiveX控件的属性页。首先,这需要在stdafx.h文件中添加对atlhost.h的包含,还要使用CAxPropertyPageImpl代替CPropertyPageImpl。对于简单的页面可以使用CAxPropertyPage代替CPropertyPage。</p>
<H3><A name=pageimplmethods></A><font color="#FFFF66">CPropertyPageImpl 的方法</font></H3>
      
<P>CPropertyPageImpl 管理着一个 PROPSHEETPAGE 结构,也就是公有成员 m_psp。CPropertyPageImpl还重载了PROPSHEETPAGE*操作符,所以你可以将CPropertyPageImpl传递给需要LPPROPSHEETPAGE 
  或 LPCPROPSHEETPAGE 类型的参数的方法,例如CPropertySheetImpl::AddPage()。</P>
<p>CPropertyPageImpl的构造函数允许你设置页面的标题,标题通常显示在页面的Tab标签上:</p>
<PRE><font color="#0000FF">CPropertyPageImpl(_U_STRINGorID title = (LPCTSTR) NULL)</font></PRE>
      
<P>如果你不想让属性表创建属性页面而是想手工创建页面,你可以调用Create():</P>
<PRE><font color="#0000FF">HPROPSHEETPAGE Create()</font></PRE>
      
<P>Create() 只是调用用m_psp做参数调用了 CreatePropertySheetPage() 。如果你向一个已经创建的属性表添加属性页或者向另一个不在控制的属性表添加属性页(例如,处理系统Shell扩展的属性表),那就只需要调用Create()函数。</P>
<p>下面的三个方法用于设置属性页的各种标题文本:</p>
<p>void SetTitle(_U_STRINGorID title)<br>
  void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)<br>
  void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)</p>
<p>第一个方法改变页面标签的文字,另外几个用来设置Wizard97样式的向导中属性页顶部的文字。</p>
<p>void EnableHelp()</p>
<p>设置m_psp中的PSP_HASHELP标志,当本页面激活时使属性表的帮助按钮可用。</p>
<H3><A name=handlingnotify></A><font color="#FFFF66">处理通知消息</font></H3>
      
<P>CPropertyPageImpl有一个消息映射处理WM_NOTIFY。如果通知代码是PSN_*的值,OnNotify()就会调用相应的通知处理函数。这使用了编译阶段虚函数机制,从而使得派生类可以很容易的重载这些处理函数。</P>
<p>由于WTL 3和WTL 7设计的改变,从而存在两套不同的通知处理机制。在WTL 3中通知处理函数返回的值与PSN_*消息的返回值不同,例如,WTL 3是这样处理PSN_WIZFINISH的:<br>
  <br>
  case PSN_WIZFINISH:<br>
  lResult = !pT-&gt;OnWizardFinish();<br>
  break;</p>
<p>OnWizardFinish()期望返回TRUE结束向导,FALSE阻止关闭向导。这个方法很简陋,但是IE5的通用控件对PSN_WIZFINISH处理的返回值添加了新解释,他返回需要获得焦点的窗口的句柄。WTL 
  3的程序将不能使用这个特性,因为它对所有非0的返回值都做相同的处理。</p>
<P>在WTL 7中,OnNotify() 没有改变 PSN_* 消息的返回值,处理函数返回任何文档中规定的合法数值和正确的行为。当然,为了向前兼容,WTL 
  3 仍然使用当前默认的工作方式,要使用WTL 7的消息处理方式,你必须在中including atldlgs.h一行之前添加一行定义:</P>
<p>#define _WTL_NEW_PAGE_NOTIFY_HANDLERS</p>
<p>编写新的代码没有理由不使用WTL 7的消息处理函数,所以这里就不介绍WTL 3的消息处理方式。</p>
<p>CPropertyPageImpl 为所有消息提供了默认的通知消息处理函数,你可以重载与你的程序有关的消息处理函数完成特殊的操作。默认的消息处理函数和相应的行为如下:</p>
<BLOCKQUOTE> 
  <P>int OnSetActive() - 允许页面成为激活状态</P>
  <p>BOOL OnKillActive() - 允许页面成为非激活状态</p>
  <p>int OnApply() - 返回 PSNRET_NOERROR 表示应用操作成功完成</p>
  <p>void OnReset() - 无相应的动作</p>
  <p>BOOL OnQueryCancel() - 允许取消操作</p>
  <p>int OnWizardBack() - 返回到前一个页面</p>
  <p>int OnWizardNext() - 进行到下一个页面</p>
  <p>INT_PTR OnWizardFinish() - 允许向导结束</p>
  <p>void OnHelp() - 无相应的动作</p>
  <p>BOOL OnGetObject(LPNMOBJECTNOTIFY lpObjectNotify) - 无相应的动作</p>
  <p>int OnTranslateAccelerator(LPMSG lpMsg) - 返回 PSNRET_NOERROR 表示消息没有被处理 </p>
  <p>HWND OnQueryInitialFocus(HWND hWndFocus) - 返回 NULL 表示将按Tab Order顺序的第一个控件设为焦点状态</p>
</BLOCKQUOTE>
<H2><A name=creatingsheet></A><font color="#FFFF66">创建一个属性表</font></H2>
      
<P>关于这些类的解释就全部讲完了,现在需要一个例子程序演示如何使用它们。本章的例子工程是一个简单的SDI程序,它在客户区显示一幅图片并使用一总颜色填充背景,使用的图片和颜色可以通过一个选项对话框(一个属性表)来设置,还有一个向导(稍后会介绍)。</P>
      
<H3><A name=simplesheet></A><font color="#FFFF66">最简单的属性表</font></H3>
      
<P>首先用WTL的向导创建一个SDI工程,然后为关于对话框添加一个属性表。首先改变向导创建的关于对话框样式,使它用起来像个属性页。</P>
<p>第一步就是去除OK按钮,因为属性表不希望属性页自己关闭。在Style Tab中,将对话框样式改为Child,Thin Border,选择Title Bar,在More 
  Styles tab,选择Disabled。</p>
<p>第二步(也是最后一步)是在OnAppAbout()的处理函数中创建一个属性表,我们使用非定制的CPropertySheet 和 CPropertyPage类:</p>
<PRE><font color="#0000FF">LRESULT CMainFrame::OnAppAbout(...)
{
CPropertySheet sheet ( _T(<SPAN class=cpp-string>"About PSheets"</SPAN>) );
CPropertyPage&lt;IDD_ABOUTBOX&gt; pgAbout;
 
    sheet.AddPage ( pgAbout );
    sheet.DoModal();
    <SPAN class=cpp-keyword>return</SPAN> <SPAN class=cpp-literal>0</SPAN>;
}</font></PRE>
<P>结果看起来向下面这样:</P>
      
<P><IMG height=282 alt=" [Simple sheet - 5K] " 
      src="images/simplesheet8.png" 
      width=344 align=bottom border=0></P>
      
<H3><A name=usefulpage></A><font color="#FFFF66">创建一个有用的属性页</font></H3>
      
<P>并不是每一个属性表中的每一个属性页都像关于对话框这么简单,大多数属性页需要使用CPropertyPageImpl的派生类,所以我们现在就看一个这样的类。我们创建了一个新的属性页用来设置客户区背景显示的图片,它是这个样子的:</P>
      
<P><IMG height=190 alt=" [Background options - 4K] " 
      src="images/bkgndsheet8.png" 
      width=243 align=bottom border=0></P>
      
<P>这个对话框的样式和关于页面相同,我们需要一个新类来和这个属性页协同工作,我们将其命名为CBackgroundOptsPage。这个类是从CPropertyPageImpl类派生的,它有一个CWinDataExchange来支持DDX。</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CBackgroundOptsPage :
    <SPAN class=cpp-keyword>public</SPAN> CPropertyPageImpl&lt;CBackgroundOptsPage&gt;,
    <SPAN class=cpp-keyword>public</SPAN> CWinDataExchange&lt;CBackgroundOptsPage&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    <SPAN class=cpp-keyword>enum</SPAN> { IDD = IDD_BACKGROUND_OPTS };
 
    <SPAN class=cpp-comment>// Construction</SPAN>
    CBackgroundOptsPage();
    ~CBackgroundOptsPage();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -