﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-白水鉴心的博客-文章分类-Windows界面编程</title><link>http://www.cppblog.com/weiyuntao/category/13411.html</link><description>潜心研习C++</description><language>zh-cn</language><lastBuildDate>Fri, 09 Apr 2010 15:39:36 GMT</lastBuildDate><pubDate>Fri, 09 Apr 2010 15:39:36 GMT</pubDate><ttl>60</ttl><item><title>Windows界面——使用Custom Draw优雅的实现ListCtrl的重绘</title><link>http://www.cppblog.com/weiyuntao/articles/110988.html</link><dc:creator>C++ FANS</dc:creator><author>C++ FANS</author><pubDate>Tue, 30 Mar 2010 06:45:00 GMT</pubDate><guid>http://www.cppblog.com/weiyuntao/articles/110988.html</guid><wfw:comment>http://www.cppblog.com/weiyuntao/comments/110988.html</wfw:comment><comments>http://www.cppblog.com/weiyuntao/articles/110988.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/weiyuntao/comments/commentRss/110988.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/weiyuntao/services/trackbacks/110988.html</trackback:ping><description><![CDATA[<p>使用Custom Draw优雅的实现ListCtrl的重绘<br>&nbsp;<br>common control 4.7版本介绍了一个新的特性叫做Custom Draw，这个名字显得模糊不清，让人有点摸不着头脑，而且MSDN里也只给出了一些如风的解释和例子，没有谁告诉你你想知道的，和究竟这个特性有什么好处。<br>&nbsp;<br>Custom draw可以被想象成一个轻量级的，容易使用的重绘方法（重绘方法还有几种，例如Owner Draw等）。这种容易来自于我们只需要处理一个消息（NM_CUSTOMDRAW），就可以让Windows为你干活了，你就不用被逼去处理＂重绘过程＂中所有的脏活了。<br>&nbsp;<br>这篇文章的焦点是如何在一个LISTCTRL控件上使用Custom Draw消息。究其原因，一部分是因为我已经在我的工作上使用了Custom Draw有一段时间了，我很熟悉它。另一个原因是这个机制确实是非常好用，你只需要写很少量的代码就可以达到很好的效果。使用 Custom draw 来对控件外观编程甚至可以代替很多的古老方法。<br>&nbsp;<br>以下代码是在WIN98 和VC6 SP2的环境下写的，common controls DLL的版本是5.0。我已经对其在WinNT 4上进行了测试。系统要运行这些代码，它的common controls DLL的版本必须至少是4.71。但随着IE4 的发布，这已经不是问题了。(IE会夹带着这个DLL一起发布) <br>&nbsp;<br>Custom Draw 基础<br>&nbsp;<br>我将会尽我所能把Custom Draw的处理描述清楚，而不是简单的引用MSDN的文档。这些例子都需要你的程序有一个ListCtrl在对话框上，并且这个ListCtrl处于Report和多列模式。<br>&nbsp;<br>Custom Draw 的消息映射入口<br>Custom draw 是一个类似于回调的处理过程，Windows在绘制List Ctrl的某个时间点上通过 Notification 消息通知你的程序，你可以选择忽略所有的通知（这样你就会看到标准的ListCtrl），或者处理某部分的绘制（实现简单的效果），甚至整个的控件都由你来绘制（就象使用Owner-Drawing一样）。这个机制的真正卖点是：你只需要实现一些你需要的，其余的可以让Windows为你代劳。<br>好了，现在你可以开始为你的ListCtrl添加Custom Draw去做一些个性化的事情了。你首先要有正确的Comm Ctrl Dll版本，然后Windows会为你发送NM_CUSTOMDRAW消息，你只需要添加一个处理函数以便开始使用Custom draw。首先添加一个消息映射，象下面一样：<br>ON_NOTIFY ( NM_CUSTOMDRAW, IDC_MY_LIST, OnCustomdrawMyList )处理函数的原形如下：<br>afx_msg void OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult );这就告诉ＭＦＣ你要处理从你的ListCtrl控件发出的WM_NOTIFY消息，ID为IDC_MY_LIST，通知码为NM_CUSTOMDRAW，OnCustomdrawMyList就是你的处理函数。<br>如果你有一个从ClistCtr派生的类，你想为它添加custom draw，你就可以使用ON_NOTIFY_REFLECT来代替。如下：<br>ON_NOTIFY_REFLECT ( NM_CUSTOMDRAW, OnCustomdraw ) <br>OnCustomdraw的原形和上面的函数一致，但它是声明在你的派生类里的。<br>&nbsp;<br>Custom draw将控件的绘制分为两部分：擦除和绘画。Windows在每部分的开始和结束都会发送NM_CUSTOMDRAW消息。所以总共就有4个消息。但是实际上你的程序所收到消息可能就只有1个或者多于四个，这取决于你想要让WINDOWS怎么做。每次发送消息的时段被称作为一个&#8220;绘画段&#8221;。你必须紧紧抓住这个概念，因为它贯穿于整个&#8220;重绘&#8221;的过程。<br>&nbsp;<br>所以，你将会在以下的时间点收到通知：<br>&nbsp;<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个item被画之前——&#8220;绘画前&#8221;段<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个item被画之后——&#8220;绘画后&#8221;段<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个item被擦除之前——&#8220;擦除前&#8221;段<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个item被擦除之后——&#8220;擦除后&#8221;段<br>&nbsp;<br>并不是所有的消息都是一样有用的，实际上，我不需要处理所有的消息，直到这篇文章完成之前，我还没使用过擦除前和擦除后的消息。所以，不要被这些消息吓到你。<br>NM_CUSTOMDRAW Messages提供给你的信息：<br>&nbsp;<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NM_CUSTOMDRAW消息将会给你提供以下的信息：<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ListCtrl的句柄<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ListCtrl的ID<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当前的&#8220;绘画段&#8221;<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 绘画的DC，让你可以用它来画画<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正在被绘制的控件、item、subitem的RECT值<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正在被绘制的Item的Index值<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正在被绘制的SubItem的Index值<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正被绘制的Item的状态值（selected, grayed, 等等）<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Item的LPARAM值，就是你使用CListCtrl::SetItemData所设的那个值<br>&nbsp;<br>上述所有的信息对你来说可能都很重要，这取决于你想实现什么效果，但最经常用到的就是&#8220;绘画段&#8221;、&#8220;绘画ＤＣ&#8221;、&#8220;Item Index&#8221;、&#8220;LPARAM&#8221;这几个值。<br>一个简单的例子：<br>好了，经过上面的无聊的细节之后，我们是时候来看一些简单的代码了。第一个例子非常的简单，它只是改变了一下控件中文字的颜色。<br>处理的代码如下：<br>void CPanel1::OnCustomdrawList ( NMHDR* pNMHDR, LRESULT* pResult ){ NMLVCUSTOMDRAW* pLVCD = reinterpret_cast&lt;NMLVCUSTOMDRAW*&gt;( pNMHDR );<br>&nbsp;&nbsp;&nbsp; // Take the default processing unless we set this to something else below.&nbsp;&nbsp;&nbsp; *pResult = 0;<br>&nbsp;&nbsp;&nbsp; // First thing - check the draw stage. If it's the control's prepaint&nbsp;&nbsp;&nbsp; // stage, then tell Windows we want messages for every item.&nbsp;&nbsp;&nbsp; if ( CDDS_PREPAINT == pLVCD-&gt;nmcd.dwDrawStage )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_NOTIFYITEMDRAW;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; else if ( CDDS_ITEMPREPAINT == pLVCD-&gt;nmcd.dwDrawStage )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This is the prepaint stage for an item. Here's where we set the&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // item's text color. Our return value will tell Windows to draw the&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // item itself, but it will use the new color we set here.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We'll cycle the colors through red, green, and light blue.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COLORREF crText;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( (pLVCD-&gt;nmcd.dwItemSpec % 3) == 0 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(255,0,0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else if ( (pLVCD-&gt;nmcd.dwItemSpec % 3) == 1 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(0,255,0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(128,128,255);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Store the color back in the NMLVCUSTOMDRAW struct.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pLVCD-&gt;clrText = crText;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Tell Windows to paint the control itself.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_DODEFAULT;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }}</p>
<p>&nbsp;</p>
<p>结果如下，你可以看到行和行间的颜色的交错显示，多酷，而这只需要两个if的判断就可以做到了。<br>&nbsp;<br>有一件事情必须记住，在做任何的绘画之前，你都要检查正处身的&#8220;绘画段&#8221;，因为你的处理函数会接收到非常多的消息，而&#8220;绘画段&#8221;将决定你代码的行为。<br>一个更小的简单例子：<br>下面的例子将演示怎么去处理subitem的绘画(其实subitem也就是列)<br>在ListCtrl控件绘画前处理NM_CUSTOMDRAW消息。 <br>告诉Windows我们想对每个Item处理NM_CUSTOMDRAW消息。 <br>当这些消息中的一个到来，告诉Windows我们想在每个SubItem的绘制前处理这个消息 <br>当这些消息到达，我们就为每个SubItem设置文字和背景的颜色。 <br>void CMyDlg::OnCustomdrawMyList ( NMHDR* pNMHDR, LRESULT* pResult )<br>{<br>NMLVCUSTOMDRAW* pLVCD = reinterpret_cast&lt;NMLVCUSTOMDRAW*&gt;( pNMHDR );<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; // Take the default processing unless we set this to something else below.<br>&nbsp;&nbsp;&nbsp; *pResult = CDRF_DODEFAULT;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; // First thing - check the draw stage. If it's the control's prepaint<br>&nbsp;&nbsp;&nbsp; // stage, then tell Windows we want messages for every item.<br>&nbsp;<br>&nbsp;&nbsp;&nbsp; if ( CDDS_PREPAINT == pLVCD-&gt;nmcd.dwDrawStage )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_NOTIFYITEMDRAW;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; elseif ( CDDS_ITEMPREPAINT == pLVCD-&gt;nmcd.dwDrawStage )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This is the notification message for an item. We'll request<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // notifications before each subitem's prepaint stage.<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_NOTIFYSUBITEMDRAW;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; elseif ( (CDDS_ITEMPREPAINT | CDDS_SUBITEM) == pLVCD-&gt;nmcd.dwDrawStage )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This is the prepaint stage for a subitem. Here's where we set the<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // item's text and background colors. Our return value will tell <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Windows to draw the subitem itself, but it will use the new colors<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // we set here.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The text color will cycle through red, green, and light blue.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // The background color will be light blue for column 0, red for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // column 1, and black for column 2.<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COLORREF crText, crBkgnd;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( 0 == pLVCD-&gt;iSubItem )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(255,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crBkgnd = RGB(128,128,255);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif ( 1 == pLVCD-&gt;iSubItem )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(0,255,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crBkgnd = RGB(255,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crText = RGB(128,128,255);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crBkgnd = RGB(0,0,0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Store the colors back in the NMLVCUSTOMDRAW struct.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pLVCD-&gt;clrText = crText;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pLVCD-&gt;clrTextBk = crBkgnd;<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Tell Windows to paint the control itself.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_DODEFAULT;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>}<br>执行的结果如下：</p>
<p>这里需要注意两件事：<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clrTextBk的颜色只是针对每一列，在最后一列的右边那个区域颜色也还是和ListCtrl控件的背景颜色一致。<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我重新看文档的时候，我注意到有一篇题目是&#8220;NM_CUSTOMDRAW (list view)&#8221;的文章，它说你可以在最开始的custom draw消息中返回CDRF_NOTIFYSUBITEMDRAW就可以处理SubItem了，而不需要在CDDS_ITEMPREPAINT绘画段中去指定CDRF_NOTIFYSUBITEMDRAW。但是我试了一下，发现这种方法并不起作用，你还是需要处理CDDS_ITEMPREPAINT段。<br>处理&#8220;绘画之后&#8221;的段<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 到限制为止的例子都是处理&#8220;绘画前&#8221;的段，当Windows绘制List Item之前就改变它的外观。然而，在&#8220;绘制前&#8221;，你的绘制行为时被限制的，你只能改变字体的颜色或者外观。如果你想改变图标的绘制，你可以在&#8220;绘画前&#8221;把整个 Item重画或者在&#8220;绘画后&#8221;去做这件事。当你做在绘画后去做&#8220;自定义绘画&#8221;是，你的&#8220;绘画处理函数&#8221;就会在Windows画完整个Item或者SubItem的时候被调用，你就可以随心所欲的乱画了！！<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个例子里，我将创建一个ListCtrl，一般的ListCtrl的Item如果被选择了，则其Icon也会呈现出被选择的状态。而我创建的这个ListCtrl的Icon是不会呈现被选择的状态的。步骤如下：<br>对ListCtrl在&#8220;绘画前&#8221;处理NM_CUSTOMDRAW消息。 <br>告诉Windows我们想在每个Item被画的时候获得NM_CUSTOMDRAW消息。 <br>当这些消息来临，告诉Windows我们想在你画完的时候获取NM_CUSTOMDRAW消息。 <br>当这些消息来到的时候，我们就重新画每一个Item的图标。 <br>void CPanel3::OnCustomdrawList ( NMHDR* pNMHDR, LRESULT* pResult ){ NMLVCUSTOMDRAW* pLVCD = reinterpret_cast&lt;NMLVCUSTOMDRAW*&gt;( pNMHDR );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = 0;&nbsp;&nbsp;&nbsp;&nbsp; // If this is the beginning of the control's paint cycle, request&nbsp;&nbsp;&nbsp; // notifications for each item.&nbsp;&nbsp;&nbsp;&nbsp; if ( CDDS_PREPAINT == pLVCD-&gt;nmcd.dwDrawStage ) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_NOTIFYITEMDRAW; }&nbsp;&nbsp;&nbsp; else if ( CDDS_ITEMPREPAINT == pLVCD-&gt;nmcd.dwDrawStage ) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // This is the pre-paint stage for an item.&nbsp; We need to make another&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // request to be notified during the post-paint stage.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_NOTIFYPOSTPAINT; }&nbsp;&nbsp;&nbsp; else if ( CDDS_ITEMPOSTPAINT == pLVCD-&gt;nmcd.dwDrawStage ) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If this item is selected, re-draw the icon in its normal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // color (not blended with the highlight color).&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LVITEM rItem;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp; nItem = static_cast&lt;int&gt;( pLVCD-&gt;nmcd.dwItemSpec );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get the image index and state of this item.&nbsp; Note that we need to&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // check the selected state manually.&nbsp; The docs _say_ that the&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // item's state is in pLVCD-&gt;nmcd.uItemState, but during my testing&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // it was always equal to 0x0201, which doesn't make sense, since&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // the max CDIS_ constant in commctrl.h is 0x0100.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZeroMemory ( &amp;rItem, sizeof(LVITEM) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rItem.mask&nbsp; = LVIF_IMAGE | LVIF_STATE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rItem.iItem = nItem;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rItem.stateMask = LVIS_SELECTED;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.GetItem ( &amp;rItem );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If this item is selected, redraw the icon with its normal colors.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( rItem.state &amp; LVIS_SELECTED )&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CDC*&nbsp; pDC = CDC::FromHandle ( pLVCD-&gt;nmcd.hdc );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRect rcIcon;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Get the rect that holds the item's icon.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_list.GetItemRect ( nItem, &amp;rcIcon, LVIR_ICON );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Draw the icon.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_imglist.Draw ( pDC, rItem.iImage, rcIcon.TopLeft(),&nbsp;&nbsp;&nbsp; ILD_TRANSPARENT );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pResult = CDRF_SKIPDEFAULT;&nbsp; } }}<br>重复，custom draw让我们可以做尽可能少的工作，上面的例子就是让Windows帮我们做完全部的工作，然后我们就重新对选择状态的Item的图标做重画，那就是我们看到的那个图标。执行结果如下：唯一的不足是，这样的方法会让你感觉到一点闪烁。因为图标被画了两次（虽然很快）。 用Custom Draw代替Owner Draw另外一件优雅的事情就是你可以使用Custom Draw来代替Owner Draw。它们之间的不同在我看来就是：<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 写Custom Draw的代码比写Owner Draw的代码更容易。<br>如果你只需要改变某行的外观，你可以不用管其他的行的绘画，让WINDOWS去做就行了。但如果你使用<br>Owner Draw，你必须要对所有的行作处理。当你想对控件作所有的处理时，你可以在处理NM_CUSTOMDRAW<br>消息的最后返回CDRF_SKIPDEFAULT，这有点和我们到目前为止所做的有些不同。CDRF_SKIPDEFAULT<br>告诉Windows由我们来做所有的控件绘画，你不用管任何事。<br>我没有在这里包含这个例子的代码，因为它有点长，但是你可以一步步地在调试器中调试代码，你可以看到每一<br>步发生了什么。如果你把窗口摆放好，让你可以看到调试器和演示的程序，那在你一步步的调试中，你可以看到<br>控件每一步的绘制，这里的ListCtrl是很简单的，只有一列并且没有列头，如下：<br>&nbsp;<br>如果需要看原文和下载例子程序，请到这个网址：<br><a href="http://www.codeproject.com/listctrl/lvcustomdraw.asp">http://www.codeproject.com/listctrl/lvcustomdraw.asp</a> </p>
<p>转载于：<a href="http://blog.csdn.net/dylgsy/archive/2006/06/21/818550.aspx">http://blog.csdn.net/dylgsy/archive/2006/06/21/818550.aspx</a><a href="http://blog.csdn.net/dylgsy/archive/2006/06/21/818550.aspx"></a></p>
<img src ="http://www.cppblog.com/weiyuntao/aggbug/110988.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/weiyuntao/" target="_blank">C++ FANS</a> 2010-03-30 14:45 <a href="http://www.cppblog.com/weiyuntao/articles/110988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>