WTL 中的 COwnerDraw<T> 提供对以下四个自绘消息的支持, 在WTL 中不需要手动添加这些消息映射, 只需要继承这 COwnerDraw<T> 然后重写对应的方法就行了
- WM_DRAWITEM
- WM_MEASUREITEM
- WM_COMPAREITEM
- WM_DELETEITEM
button,combo box, list box, menu, tab 都可以使用 COwnerDraw<T> 来进行自绘
下面以 List Box 来演示
一, 修改 List Box 的 Style
在对话框资源编辑器中编辑对话框, 添加入 List Box, 修改风格 Owner Draw 为 Fixed, 这个操作相当于给 List Box 加入 LBS_OWNERDRAWFIXED style, 带这种风格的 List Box 在每次需要绘制内容时, 会发送 WM_DRAWITEM 消息到父窗口
并且取消 Sort
二, 在父窗口中启用消息反射
在自己实现一个自绘的 List Box 类中处理绘制, 而不是在全部在父窗口中处理, 这样会绘制更符合面向对象思想, 所以我们需要在在 List Box 所在的父窗口类中加入消息反射
BEGIN_MSG_MAP_EX(CMainDlg) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) //... REFLECT_NOTIFICATIONS(); // 反射 WM_MEASUREITEM 和 WM_DRAWITEM 消息 END_MSG_MAP()
三, 实现自绘的 List Box
class MyOwnerDrawListImpl : public CWindowImpl<MyOwnerDrawListImpl, CListBox> , public COwnerDraw<MyOwnerDrawListImpl> { public: BEGIN_MSG_MAP_EX(MyOwnerDrawListImpl) CHAIN_MSG_MAP_ALT(COwnerDraw<MyOwnerDrawListImpl>, 1) DEFAULT_REFLECTION_HANDLER(); END_MSG_MAP() public: // Overrideables void DrawItem(LPDRAWITEMSTRUCT item) {
// 简单绘制 CDCHandle dc(item->hDC); CRect rect(item->rcItem); dc.SetBkMode(TRANSPARENT); CFontHandle font(GetParent().GetFont()); if (item->itemState & ODS_SELECTED) { dc.FillSolidRect(rect, RGB(87, 87, 225)); dc.SetTextColor(RGB(255, 255, 255)); } else { dc.FillSolidRect(rect, RGB(225, 225, 225)); dc.SetTextColor(RGB(0, 0, 0)); } dc.DrawTextW((LPTSTR)item->itemData, -1, rect, DT_VCENTER); } };
四, 在对话框所在的类中加入 成员变量以及初始化代码
MyOwnerDrawListImpl m_listbox; //...
m_listbox.SubclassWindow(GetDlgItem(IDC_LIST1));
m_listbox.AddString(L"List Box Item 0");
m_listbox.AddString(L"List Box Item 1");
m_listbox.AddString(L"List Box Item 2");
m_listbox.AddString(L"List Box Item 3");
m_listbox.AddString(L"List Box Item 4");
效果