zoukankan      html  css  js  c++  java
  • WTL 自绘ComboBox带CheckBox

    效果图:

    1

    原帖:http://www.cnblogs.com/liangbin/articles/2064932.html

    通过SetWindowLong自定义ListBox的窗口过程“ComboBoxListBoxProc”,来改变在下拉列表中的一些行为。

    但是这么做需要在CheckComboBox类中添加一些静态变量,可以在自定义的窗口过程中调用。

    其实可以封装的更简洁些,通过容器窗口,也可以通过子类/超类化,下面代码通过容器窗口实现:

      1: //*************************************************************************
    
      2: //
    
      3: // Copyright (C), 2009-2010, Handy Information Co.,Ltd,All Rights Reserved
    
      4: //
    
      5: // FileName:      CheckComboBox.h  
    
      6: // Author:        yinxf
    
      7: // Date:          2012/2012/4
    
      8: // Description:   带checkbox的ComboBox,自绘
    
      9: //                要将ComboBox的Tyep设置为Drop List
    
     10: //                               OwnerDraw设置为Variable
    
     11: //                               Has Strings设置为True
    
     12: // Function List:  
    
     13: // History:              
    
     14: //          <author>        <time>           <desc>        
    
     15: //            yinxf          2010/07/13        Build
    
     16: //
    
     17: //*************************************************************************
    
     18: #pragma once
    
     19: 
    
     20: class CCheckComboBox
    
     21:     : public CWindowImpl<CCheckComboBox, CComboBox>
    
     22:     , public COwnerDraw<CCheckComboBox>
    
     23: {
    
     24: public:
    
     25:     CCheckComboBox(void) 
    
     26:         : m_listBox(this, 1)
    
     27:         , m_bTextUpdated(FALSE)
    
     28:     {}
    
     29:     ~CCheckComboBox(void){}
    
     30: 
    
     31:     // 设置选中
    
     32:     int SetCheck(int nIndex, BOOL bCheck)
    
     33:     {
    
     34:        int nRet = SetItemData(nIndex, bCheck);
    
     35:        if ( nRet == CB_ERR )  
    
     36:            return nRet;
    
     37: 
    
     38:        // Signal that the text need updating
    
     39:        m_bTextUpdated = FALSE;
    
     40: 
    
     41:        // Redraw the window       
    
     42:        Invalidate(FALSE);
    
     43: 
    
     44:        return nRet;
    
     45:     }
    
     46: 
    
     47:     // 获取选中状态
    
     48:     BOOL GetCheck(int nIndex)
    
     49:     {
    
     50:         return GetItemData(nIndex);
    
     51:     }
    
     52: 
    
     53:     // Selects all/unselects all
    
     54:     void SelectAll(BOOL bCheck = TRUE)
    
     55:     {
    
     56:         for ( int i = 0; i < GetCount(); i++ )
    
     57:             SetCheck(i, bCheck);
    
     58:     }
    
     59: 
    
     60: protected:
    
     61:     BEGIN_MSG_MAP(CCheckComboBox)
    
     62:         MSG_WM_CTLCOLORLISTBOX(OnCtlColorListBox)
    
     63:         MSG_WM_GETTEXT(OnGetText)       
    
     64:         MSG_WM_GETTEXTLENGTH(OnGetTextLength)
    
     65:         CHAIN_MSG_MAP_ALT(COwnerDraw<CCheckComboBox>, 1)
    
     66:         DEFAULT_REFLECTION_HANDLER()
    
     67:     /////////////////处理ListBox消息/////////////////////////////
    
     68:     ALT_MSG_MAP(1) 
    
     69:         MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
    
     70:         MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
    
     71:         MESSAGE_HANDLER(LB_GETCURSEL, OnGetCurSel)
    
     72:         MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)
    
     73:     //////////////////////////////////////////////////////////////
    
     74:     END_MSG_MAP()
    
     75: 
    
     76:     BOOL SubclassWindow(HWND hWnd)
    
     77:     {
    
     78:         BOOL bRet = __super::SubclassWindow(hWnd);
    
     79:         if ( bRet )
    
     80:         {
    
     81:             // 一旦创建无法修改,要么通过create创建
    
     82:             // CWindow::ModifyStyle(0, CBS_OWNERDRAWVARIABLE); // 添加自绘属性
    
     83:             // CWindow::ModifyStyle(CBS_DROPDOWN, CBS_DROPDOWNLIST); 
    
     84: 
    
     85:             DWORD style = GetStyle();        
    
     86:             // Make sure to use the CBS_DROPDOWNLIST style        
    
     87:             ATLASSERT(style & CBS_DROPDOWNLIST);        
    
     88:             // Make sure to use the CBS_OWNERDRAWVARIABLE style        
    
     89:             ATLASSERT(style & CBS_OWNERDRAWVARIABLE);        
    
     90:             // Use default strings. We need the itemdata to store checkmarks       
    
     91:             ATLASSERT(style & CBS_HASSTRINGS);
    
     92:         }
    
     93:         return bRet;
    
     94:     }
    
     95: 
    
     96:     // 自绘
    
     97:     void DrawItem(LPDRAWITEMSTRUCT lpdis)
    
     98:     {
    
     99:         CRect rcCheck = lpdis->rcItem;
    
    100:         CRect rcText  = lpdis->rcItem;
    
    101:         CString strText;
    
    102: 
    
    103:         // 检查是否绘制的静态文本框
    
    104:         if ( (LONG)lpdis->itemID < 0 )  // *一定要强制转换为有符号性*
    
    105:         {
    
    106:             RecalcText();
    
    107:             strText = m_strTextAll;
    
    108:         }
    
    109:         // 下拉列表
    
    110:         else 
    
    111:         {
    
    112:             BOOL bCheck = GetCheck(lpdis->itemID);
    
    113:             GetLBText(lpdis->itemID, strText);
    
    114: 
    
    115:             // 绘制checkbox
    
    116:             TEXTMETRIC txtMetric;
    
    117:             GetTextMetrics(lpdis->hDC, &txtMetric);
    
    118:             rcCheck.top += 1;
    
    119:             rcCheck.left = 0;
    
    120:             rcCheck.right = rcCheck.left + txtMetric.tmHeight + txtMetric.tmExternalLeading + 6;
    
    121:             rcCheck.bottom -= 1;
    
    122:             rcText.left = rcCheck.right;
    
    123: 
    
    124:             UINT nState = bCheck ? DFCS_CHECKED : DFCS_BUTTONCHECK;
    
    125:             DrawFrameControl(lpdis->hDC, rcCheck, DFC_BUTTON, nState);
    
    126:         }
    
    127: 
    
    128:         // 绘制文字
    
    129:         if ( lpdis->itemState & ODS_SELECTED ) // 设置背景色
    
    130:         {
    
    131:             SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
    
    132:             SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
    
    133:         }
    
    134:         else
    
    135:         {
    
    136:             SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
    
    137:             SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
    
    138:         }
    
    139: 
    
    140:         // Erase and draw       
    
    141:         ExtTextOut(lpdis->hDC, 0, 0, ETO_OPAQUE, rcText, 0, 0, 0); // ETO_OPAQUE表示当前背景颜色会充满整个矩形框
    
    142:         DrawText(lpdis->hDC, strText, strText.GetLength(), rcText, DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
    
    143: 
    
    144:         // 绘制焦点(虚线)
    
    145:         if ((lpdis->itemState & (ODS_FOCUS|ODS_SELECTED)) == (ODS_FOCUS|ODS_SELECTED))           
    
    146:             DrawFocusRect(lpdis->hDC, &rcText);
    
    147:     }
    
    148: 
    
    149:     LRESULT OnCtlColorListBox(HDC hdc, HWND hwnd)
    
    150:     {
    
    151:         ATLTRACE(_T("[%s]0x%x"), _T(__FUNCTION__), hwnd);
    
    152: 
    
    153:         if ( NULL == m_listBox.m_hWnd )
    
    154:             m_listBox.SubclassWindow(hwnd);
    
    155: 
    
    156:         return DefWindowProc();
    
    157:     }
    
    158: 
    
    159:     //
    
    160:     // By adding this message handler, we may use CWindow::GetText()
    
    161:     //
    
    162:     int OnGetText(int cchTextMax, LPTSTR lpszText)
    
    163:     {
    
    164:         // Make sure the text is updated
    
    165:         RecalcText();
    
    166: 
    
    167:         if (NULL == lpszText)
    
    168:             return 0;
    
    169: 
    
    170:         // Copy the 'fake' window text
    
    171:         _tcscpy_s(lpszText, cchTextMax, m_strTextAll);
    
    172:         return m_strTextAll.GetLength();
    
    173:     }
    
    174: 
    
    175:     //
    
    176:     // By adding this message handler, we may use CWindow::GetTextLength()
    
    177:     //
    
    178:     int OnGetTextLength()
    
    179:     {
    
    180:         // Make sure the text is updated
    
    181:         RecalcText();
    
    182:         return m_strTextAll.GetLength();
    
    183:     }
    
    184:     
    
    185:     ///////////////////////////////////////////////////////////////////////////////////
    
    186:     // 处理ListBox消息
    
    187:     
    
    188:     LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    
    189:     {
    
    190:         CPoint pt;           
    
    191:         pt.x = LOWORD(lParam);          
    
    192:         pt.y = HIWORD(lParam);
    
    193: 
    
    194:         // Compute which index to check/uncheck
    
    195:         int nItemHeight = GetItemHeight(0);
    
    196:         int nTopIndex = GetTopIndex();
    
    197:         int nIndexClick = nTopIndex + pt.y / nItemHeight;
    
    198: 
    
    199:         // Get clicked item rect
    
    200:         CRect rcItem;
    
    201:         m_listBox.GetItemRect(nIndexClick, rcItem);
    
    202: 
    
    203:         if ( PtInRect(rcItem, pt) )
    
    204:         {
    
    205:              // Invert the check mark
    
    206:             SetCheck(nIndexClick, !GetCheck(nIndexClick));
    
    207:             ::InvalidateRect(m_listBox.m_hWnd, rcItem, FALSE);
    
    208:             
    
    209:             // Notify that selection has changed
    
    210:             /*::SendMessage(this->GetParent().m_hWnd, WM_COMMAND, 
    
    211:                 MAKELONG(::GetWindowLong(this->m_hWnd, GWL_ID), CBN_SELCHANGE), 
    
    212:                 (LPARAM)this->m_hWnd);*/
    
    213: 
    
    214:             // 按照上面发送消息没有效果,直接刷新
    
    215:             Invalidate(FALSE);
    
    216:         }
    
    217: 
    
    218:         bHandled = FALSE;
    
    219:         return 0;
    
    220:     }
    
    221: 
    
    222:     LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
    
    223:     {
    
    224:         // 什么都不做,让列表窗口在被选中了一个条目后仍然保持显示(不自动关闭)
    
    225:         return 0;
    
    226:     }
    
    227: 
    
    228:     LRESULT OnGetCurSel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
    
    229:     {
    
    230:         // Make the combobox always return -1 as the current selection. This
    
    231:         // causes the lpDrawItemStruct->itemID in DrawItem() to be -1
    
    232:         // when the always-visible-portion of the combo is drawn
    
    233:         return -1;
    
    234:     }
    
    235: 
    
    236:     LRESULT OnRButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
    
    237:     {
    
    238:         // If you want to select all/unselect all using the
    
    239:         // right button, remove this ifdef. Personally, I don't really like it
    
    240: #if TRUE
    
    241:         INT nCount = GetCount();
    
    242:         INT nSelCount = 0;
    
    243: 
    
    244:         for (INT i = 0; i < nCount; i++)
    
    245:         {
    
    246:             if ( GetCheck(i) )
    
    247:                 nSelCount++;
    
    248:         }
    
    249: 
    
    250:         SelectAll(nSelCount != nCount);
    
    251: 
    
    252:         // invalidate list box
    
    253:         ::InvalidateRect(m_listBox.m_hWnd, 0, FALSE);
    
    254: #endif
    
    255: 
    
    256:         bHandled = FALSE;
    
    257:         return 0;
    
    258:     }
    
    259: 
    
    260: 
    
    261:     //////////////////////////////////////////////////////////////////////////
    
    262:     // Help
    
    263: 
    
    264:     //
    
    265:     // This routine steps through all the items and builds    
    
    266:     // a string containing the checked items    
    
    267:     //
    
    268:     void RecalcText()
    
    269:     {
    
    270:         if ( m_bTextUpdated )
    
    271:             return;
    
    272: 
    
    273:         CString strText;
    
    274: 
    
    275:         int nCount = GetCount();
    
    276:         for ( int i = 0; i < nCount; i++ )
    
    277:         {
    
    278:             if ( TRUE == GetCheck(i) )
    
    279:             {
    
    280:                 CString strItem;
    
    281:                 GetLBText(i, strItem);
    
    282: 
    
    283:                 if ( !strText.IsEmpty() )
    
    284:                     strText += _T(", ");
    
    285:                 
    
    286:                 strText += strItem;
    
    287:             }
    
    288:         }
    
    289: 
    
    290:         m_strTextAll = strText;
    
    291: 
    
    292:         m_bTextUpdated = TRUE;
    
    293:         return;
    
    294:     }
    
    295: 
    
    296: protected:
    
    297:     CContainedWindowT<CListBox> m_listBox;
    
    298:     CString m_strTextAll;       // 静态文本框显示的内容
    
    299:     BOOL    m_bTextUpdated;     
    
    300: };
    微信号:yinxufeng503
    本博客文章,有原创和网络搜集,转载请注明出处

    分享到: 更多
  • 相关阅读:
    centos 8.5设置nginx开机自动启动
    python利用Faker模块造测试数据(转载)
    结构化分析建模
    关于使用com.anjiplus依赖实现的验证码功能在linux服务器上失效的问题
    vue 子组件提交接口,父组件刷新数据
    vue 全局钩子:路由守卫
    Scala函数式编程基础
    Flink
    Scala面向对象编程
    Scala运算符
  • 原文地址:https://www.cnblogs.com/yinxufeng/p/2578756.html
Copyright © 2011-2022 走看看