![用WTL实现自定义绘制控件_第1张图片](http://img.e-com-net.com/image/info8/4aefc25ac875428fb4dd65e7e0b88662.jpg)
简述
使用WTL一段时间以来,我发现非常缺乏相关的文档。在我看来,WTL是解决Win32编程的最佳方案,并且我们在网络上能够得到文档越多,对我们越有帮助。
本文主要阐述使用WTL创建自定义绘制控件的方法。
我选择使用一个listview和文章《Neat Stuff to do with List Controls using CustomDraw》联系起来。该篇文章通过MFC演示了相同的概念。我选择简单的方式并且将带领你到文档中获得更多的例子,通过这些例子,你可以改进你的listview的视觉效果。
MyListControl
WTL把自定义绘制控件变得非常的简单,其要领是你得弄明白你的项目中实现功能的每一行代码。我们从CListViewCtrl定义我们自己的类开始,这样我们就能够把自定义绘制放在同一个地方。
class MyListView : public CWindowImpl, public CCustomDraw { public: BEGIN_MSG_MAP(MyListView) CHAIN_MSG_MAP(CCustomDraw) END_MSG_MAP() }
我们必须从CWindowImpl中继承,否则我们将无法得到任何窗口消息。更重要的事情再次说明一下,我们也要从CCustomDraw中继承。该类与CHAIN_MSG_MAP(CCustomDraw)宏一起,让我们能够轻易得重载CListViewControl绘制的过程。
宏 CHAIN_MSG_MAP转发消息到基类中默认的的消息映射中去。
如果你在AtlCtrls.h的代码中看一眼CCustomDraw,你将看到其定义了宏NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw),该宏处理自定义绘制消息。NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)分流消息到各个组件,并且调用各自对应的函数。以下这些函数可以重载,用来绘制你的控件。
// Overrideables DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/); DWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/);
我们将重载几个函数并且改变每隔一行的背景填充颜色,让其有一个分层的直观,使得阅读每一行的时候更加容易。
所以在我们 MyListViewCtrl类中,我们将定义下面两个重载。
class MyListView : public CWindowImpl, public CCustomDraw { public: BEGIN_MSG_MAP(MyListView) CHAIN_MSG_MAP(CCustomDraw) END_MSG_MAP() DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_NOTIFYITEMDRAW; } DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) { NMLVCUSTOMDRAW* pLVCD = reinterpret_cast( lpNMCustomDraw ); // This is the prepaint stage for an item. Here's where we set the // item's text color. Our return value will tell Windows to draw the // item itself, but it will use the new color we set here for the background COLORREF crText; if ( (pLVCD->nmcd.dwItemSpec % 2) == 0 ) crText = RGB(200,200,255); else crText = RGB(255,255,255); // Store the color back in the NMLVCUSTOMDRAW struct. pLVCD->clrTextBk = crText; // Tell Windows to paint the control itself. return CDRF_DODEFAULT; } };
创建控件
大多数我们在MSDN以及其他的文章上看到的例子都是假设控件都是以资源的形式创建的,然后链接到我们的代码中。为了与之前的不一样,我们将直接在主界面上创建一个list box。
以下是所有的我们将添加到向导创建的CMainFrame中的代码,用来创建我们的自定义绘制控件。找到宏CHAIN_MSG
_MAP_MEMBER(m_listView)。失去了这个宏,你的类将无法得到NM_CUSTOMDRAW消息。这个宏把数据包中的消息转发消息到默认的消息映射中,这正是我们想要做的。
另外注意,我们可能已经在这级别处已经处理了NM_CUSTOMDRAW消息。查一下,看看控件的ID是什么?处理绘制过程是否合理?
在某些情况下,这是非常有用的,并且相对于我们当前做的事情已经简单多了。注意,保持我们的代码的简洁与明了。
class CMainFrame : public CFrameWindowImpl, public CUpdateUI, public CMessageFilter, public CIdleHandler { public: // ... // code left out for readability // ... BEGIN_MSG_MAP(CMainFrame) // ... // code left out for readability // ... CHAIN_MSG_MAP_MEMBER(m_listView) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // code left out for readability // create a list box RECT r = {0,0,182,80}; m_listView.Create(m_hWnd,r,CListViewCtrl::GetWndClassName(), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | LVS_REPORT, WS_EX_CLIENTEDGE); // fill in the headers m_listView.AddColumn(_T("Symbol"), 0); m_listView.AddColumn(_T("Company "), 1); m_listView.AddColumn(_T("Price "), 2); m_listView.AddItem(0,0,"VOD"); m_listView.AddItem(0,1,"Vodaphone Airtouch"); m_listView.AddItem(0,2,"252.25"); m_listView.AddItem(1,0,"LAT"); m_listView.AddItem(1,1,"Lattice Group"); m_listView.AddItem(1,2,"149.9"); m_listView.AddItem(2,0,"CLA"); m_listView.AddItem(2,1,"Claims Direct"); m_listView.AddItem(2,2,"132.50"); return 0; } // ... // code left out for readability // ... public : MyListView m_listView; };
在 OnCreate() 中,我们仅仅在,并且添加几个例子数值。大功告成!
许可(英语原文)
本文没有明确的许可。
作者:Billy Leverington
翻译:sKy
英语原文:http://www.codeproject.com/KB/wtl/customdrawlist_wtl.aspx