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

📄 wtl for mfc programmers, part v - advanced dialog ui classes - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>
<head>
<title>WTL for MFC Programmers, Part V - Advanced Dialog UI Classes</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 V - Advanced Dialog UI Classes</font></b><br>
  <br>
</p>
<p align="left">原作 :<b><font color="#CC3366">Michael Dunn</font></b> [<a href="http://www.codeproject.com/wtl/WTL4MFC5.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/WTL4MFC5_demo.zip">下载演示程序代码</a></p>
 
<H2><font color="#FFFF66">本章内容</font></H2>
<UL>
        
  <LI><A href="#intro">第五章介绍</A> 
  <LI><A href="#specialized">特别的自画和外观定制类</A> 
        <UL>
          <LI><A href="#cownerdraw">COwnerDraw</A> 
          <LI><A href="#ccustomdraw">CCustomDraw</A></LI>
        </UL>
        <LI><A href="#newwtlctrls">WTL的新控件</A> 
        <UL>
          <LI><A href="#newcbitmapbutton">CBitmapButton</A> 
          <LI><A href="#cchecklist">CCheckListViewCtrl</A> 
          <LI><A href="#treeex">CTreeViewCtrlEx 和 CTreeItem</A> 
          <LI><A href="#chyperlink">CHyperLink</A></LI>
       </UL>
        
  <LI><A href="#uiupdctrl">对话框中控件的UI Updating</A> 
  <LI><A href="#ddv">DDV</A> 
        <UL>
          <LI><A href="#ddvfail">处理DDV验证失败</A> </LI>
        </UL>
        <LI><A href="#resizing">改变对话框的大小</A> 
        <LI><A href="#upnext">继续</A> 
        <LI><A href="#references">参考</A> 
        <LI><A href="#revisionhistory">修改记录</A> </LI>
</UL>
  
<H2><A name=intro></A><font color="#FFFF66">第五章介绍</font></H2>
 
<p>在上一篇文章我们介绍了一些与对话框和控件有关的WTL的特性,它们和MFC的相应的类作用相同。本文将介绍一些新类实现高级界面特性新类:控件自画和自定外观控件,新的WTL控件,UI 
  updating和对话框数据验证(DDV)。</p>     
<H2><A name=specialized></A><font color="#FFFF66">特别的自画和外观定制类</font></H2>
      
<P>由于自画和定制外观控件在图形用户界面中是很常用的手段,所以WTL提供了几个嵌入类来完成这些令人厌烦的工作。我接着就会介绍它们,事实上我们在上一个例子工程ControlMania2的结尾部分已经这么做了。如果你正随着我的讲解用应用程序生成向导创建新工程,请不要忘了使用无模式对话框,为了使正常工作必须使用无模式对话框,我会在<a href="#uiupdctrl">对话框中控件的UI 
  Updating</a>部分详细解释为什么这样作。</P>
<H3><A name=cownerdraw></A><font color="#FFFF66">COwnerDraw</font></H3>
      
<P>控件的自画需要响应四个消息:WM_MEASUREITEM, WM_DRAWITEM, WM_COMPAREITEM, 和WM_DELETEITEM,在atlframe.h头文件中定义的COwnerDraw类可以简化这些工作,使用这个类就不需要处理这四个消息,你只需将消息链入COwnerDraw,它会调用你的类中的重载函数。</P>
<p>如何将消息链入COwnerDraw取决与你是否将消息反射给控件,两种方法有些不同。下面是COwnerDraw类的消息映射链,它使得两种方法的差别更加明显:</p>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">template</font></SPAN> <font color="#0033FF">&lt;<SPAN class=cpp-keyword>class</SPAN> T&gt; <SPAN class=cpp-keyword>class</SPAN> COwnerDraw
{
<SPAN class=cpp-keyword>public</SPAN>:
  BEGIN_MSG_MAP(COwnerDraw&lt;T&gt;)
    MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
    MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
    MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
    MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
  ALT_MSG_MAP(<SPAN class=cpp-literal>1</SPAN>)
    MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
    MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
    MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
    MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
  END_MSG_MAP()
};</font></PRE>
      
<P>注意,消息映射链的主要部分处理WM_*消息,而ATL部分处理反射的消息,OCM_*。自画的通知消息就像WM_NOTIFY消息一样,你可以在父窗口处理它们,也可以将它们反射会控件,如果你使用前一种方法,消息被直接链入COwnerDraw:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CSomeDlg : <SPAN class=cpp-keyword>public</SPAN> COwnerDraw&lt;CSomeDlg&gt;, ...
{
  BEGIN_MSG_MAP(CSomeDlg)
    <SPAN class=cpp-comment>//...</SPAN>
    CHAIN_MSG_MAP(COwnerDraw&lt;CSomeDlg&gt;)
  END_MSG_MAP()
 
  <SPAN class=cpp-keyword>void</SPAN> DrawItem ( LPDRAWITEMSTRUCT lpdis );
};</font></PRE>
      
<P>当然,如果你想要控件自己处理这些消息,你需要使用CHAIN_MSG_MAP_ALT宏将消息链入ALT_MSG_MAP(1)部分:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CSomeButtonImpl : <SPAN class=cpp-keyword>public</SPAN> COwnerDraw&lt;CSomeButtonImpl&gt;, ...
{
  BEGIN_MSG_MAP(CSomeButtonImpl)
    <SPAN class=cpp-comment>//...</SPAN>
    CHAIN_MSG_MAP_ALT(COwnerDraw&lt;CSomeButtonImpl&gt;, <SPAN class=cpp-literal>1</SPAN>)
    DEFAULT_REFLECTION_HANDLER()
  END_MSG_MAP()
 
  <SPAN class=cpp-keyword>void</SPAN> DrawItem ( LPDRAWITEMSTRUCT lpdis );
};</font></PRE>
      
<P>COwnerDraw类将对消息传递的参数展开,然后调用你的类中的实现函数。上面的例子中,我们自己的类实现DrawItem()函数,当有WM_DRAWITEM或OCM_DRAWITEM消息被链入COwnerDraw时,这个函数就会被调用。你可以重载的方法有:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
<SPAN class=cpp-keyword>void</SPAN> MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
<SPAN class=cpp-keyword>int</SPAN>  CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);
<SPAN class=cpp-keyword>void</SPAN> DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct);</font></PRE>
      
<P>如果你不想处理某个消息,你可以调用SetMsgHandled(false),消息会被传递给消息映射链中的其他响应者。SetMsgHandled()事实上是COwnerDraw类的成员函数,但是它的作用和在BEGIN_MSG_MAP_EX()中使用SetMsgHandled()一样。</P>
<p>对于ControlMania2,它从ControlMania1中的树控件开始,添加了自画按钮处理反射的WM_DRAWITEM消息,下面是资源编辑器中的新按钮:</p>
<P><IMG height=346 alt=" [Owner-drawn button 1 - 7K] " 
      src="images/cm2_od15.png" 
      width=325 align=bottom border=0></P>
      
<P>现在我们需要一个新类实现自画按钮:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CODButtonImpl : <SPAN class=cpp-keyword>public</SPAN> CWindowImpl&lt;CODButtonImpl, CButton&gt;,
                      <SPAN class=cpp-keyword>public</SPAN> COwnerDraw&lt;CODButtonImpl&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CODButtonImpl)
        CHAIN_MSG_MAP_ALT(COwnerDraw&lt;CODButtonImpl&gt;, <SPAN class=cpp-literal>1</SPAN>)
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()
 
    <SPAN class=cpp-keyword>void</SPAN> DrawItem ( LPDRAWITEMSTRUCT lpdis );
};</font></PRE>
      
<P>DrawItem()使用了像BitBlt()这样的GDI函数向按钮的表面画位图,代码应该很容易理解,因为WTL使用的类名和函数名都和MFC类似。</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> CODButtonImpl::DrawItem ( LPDRAWITEMSTRUCT lpdis )
{
<SPAN class=cpp-comment>// NOTE: m_bmp is a CBitmap init'ed in the constructor.</SPAN>
CDCHandle dc = lpdis-&gt;hDC;
CDC dcMem;
 
    dcMem.CreateCompatibleDC ( dc );
    dc.SaveDC();
    dcMem.SaveDC();
 
    <SPAN class=cpp-comment>// Draw the button's background, red if it has the focus, blue if not.</SPAN>
    <SPAN class=cpp-keyword>if</SPAN> ( lpdis-&gt;itemState &amp; ODS_FOCUS ) 
        dc.FillSolidRect ( &amp;lpdis-&gt;rcItem, RGB(<SPAN class=cpp-literal>255</SPAN>,<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>0</SPAN>) );
    <SPAN class=cpp-keyword>else</SPAN>
        dc.FillSolidRect ( &amp;lpdis-&gt;rcItem, RGB(<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>255</SPAN>) );
 
    <SPAN class=cpp-comment>// Draw the bitmap in the top-left, or offset by 1 pixel if the button</SPAN>
    <SPAN class=cpp-comment>// is clicked.</SPAN>
    dcMem.SelectBitmap ( m_bmp );
 
    <SPAN class=cpp-keyword>if</SPAN> ( lpdis-&gt;itemState &amp; ODS_SELECTED ) 
        dc.BitBlt ( <SPAN class=cpp-literal>1</SPAN>, <SPAN class=cpp-literal>1</SPAN>, <SPAN class=cpp-literal>80</SPAN>, <SPAN class=cpp-literal>80</SPAN>, dcMem, <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>0</SPAN>, SRCCOPY );
    <SPAN class=cpp-keyword>else</SPAN>
        dc.BitBlt ( <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>80</SPAN>, <SPAN class=cpp-literal>80</SPAN>, dcMem, <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>0</SPAN>, SRCCOPY );
 
    dcMem.RestoreDC(-<SPAN class=cpp-literal>1</SPAN>);
    dc.RestoreDC(-<SPAN class=cpp-literal>1</SPAN>);
}</font></PRE>
      
<P>我们的按钮看起来是这个样子:</P>
      
<P><IMG height=324 alt=" [Owner-drawn button - 11K] " 
      src="images/cm2_od25.png" 
      width=305 align=bottom border=0></P>
      
<H3><A name=ccustomdraw></A><font color="#FFFF66">CCustomDraw</font></H3>
      
<P>CCustomDraw类使用和COwnerDraw类相同的方法处理NM_CUSTOMDRAW消息,对于自定绘制的每个阶段都有相应的重载函数:</P>
<PRE><font color="#0033FF">DWORD OnPrePaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnPostPaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnPreErase(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnPostErase(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
 
DWORD OnItemPrePaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnItemPostPaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnItemPreErase(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
DWORD OnItemPostEraset(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);
 
DWORD OnSubItemPrePaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, LPNMCUSTOMDRAW lpNMCD);</font></PRE>
      
<P>这些函数默认都是返回CDRF_DODEFAULT,如果想自画控件或返回一个不同的值,就需要重载这些函数:</P>
<p>你可能注意到上面的屏幕截图将“道恩”(Dawn:女名)显示成绿色,这是因为CBuffyTreeCtrl将消息链入CCustomDraw并重载了OnPrePaint()和OnItemPrePaint()方法。向树控件中添加节点时,节点的item 
  data字段被设置成1,OnItemPrePaint()检查这个值,然后改变文字的颜色。</p>
<PRE><font color="#0033FF">DWORD CBuffyTreeCtrl::OnPrePaint(<SPAN class=cpp-keyword>int</SPAN> idCtrl, 

⌨️ 快捷键说明

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