zoukankan      html  css  js  c++  java
  • WTL 自绘ComboBox改变颜色和大小

    要点

          1. ComboBox控件由三部分组成:ComboBox本身,CEidt或者CStaitc,ClistBox。当类型是Dropdown时,内部是CEdit;是类型是Drop List时,内部是Static。

          2. ComboBox支持自绘需要修改Owner Draw属性为Fixed(固定的列表宽度和高度) or Variable(可变的列表宽度和高度)。响应WM_DRAWITEM(反射OCM_DRAWITEM)消息,重载DrawItem函数对下拉列表元素进行重绘。在DrawItem中需要用到GetLBText函数来获取要绘制的文本信息,这就需要增加Has Strings属性。

          3. 改变ComboBox列表宽度高度,是通过响应WM_MEASUREITEM(发射OCM_MEASUREITEM)消息,重载MeasureItem函数,修改LPMEASUREITEMSTRUCT成员来达到效果。有这么短英文原话(出处忘了是哪了)
          For “fixed” type owner draw list box or combo box, WM_MEASUREITEM is sent when it is first created and the returned size will be used for all items. For “variable” type owner-draw list box or combo box, this message is sent for each item separately. 
          意思就是如果属性是“Fixed”,WM_MESUREITEM消息在控件第一次创建的时候触发,重载函数MesureItem返回的LPMEASUREITEMSTRUCT成员中的宽度和高度将被用作列表中的所有条目。如果属性是“Variable”,列表中每一项分别响应。
          这句话容易被忽略掉一种情况,如果是通过子类化(DDX_Control,SubclassDlgItem或SubclassWindow)来改变已有的控件,该控件又是“Fixed”。则重载的MeasureItem将不起作用。因为在子类化之前,创建的时候已经触发过了。所以要想改变列表宽度和高度,要这么设置: 
          1) 通过子类化关联控件:属性要设置为“Variable”,下拉列表包含几个条目,MeasureItem就会被调用几次,改变每一项的的宽度高度,但是不能文本框(LPMEASUREITEMSTRUCT成员itemID = -1)的宽度高度
          2) 调用Create动态创建:属性设置为“Fixed”,MeasureItem会被调用两次,LPMEASUREITEMSTRUCT成员itemID为-1和1。等于-1的时候可以改变文本框宽度高度。等于1的时候,被设置的宽度高度将应用于下拉列表所有项;属性设置为“Variable”,MeasureItem会被调用>2次(列表条目个数+1)。同样的,等于itemID=-1时候改变文本框,itemID=0,1,2...改变列表每一项各自的宽度高度。(如果发现点击下拉按钮出现不了列表框,请检查调用Create函数时候穿进去的Rect的高度是不是太小了)

          4. 改变颜色
          ● 改变CEdit颜色(Dropdown类型):只要响应WM_CTLCOLOREDIT消息,在响应函数中返回新的画刷;
          ● 改变下拉列表颜色:在DrawItem重载函数中,根据Item状态,绘制颜色。

    实践

          新建一个ComboBox派生类CColorComboBox,并且继承CownerDraw,MSG_MAP中添加自绘的消息链,父窗口中MSG_MAP中添加消息反射宏 REFLECT_NOTIFICATIONS()

      1: class CColorComboBox
    
      2:     : public CWindowImpl<CColorComboBox, CComboBox>
    
      3:     , public COwnerDraw<CColorComboBox>
    
      4: {
    
      5: public:
    
      6:     CColorComboBox(){}
    
      7:     ~CColorComboBox(){}
    
      8: 
    
      9: protected:
    
     10:     BEGIN_MSG_MAP(CColorComboBox)
    
     11:         CHAIN_MSG_MAP_ALT(COwnerDraw<CColorComboBox> ,1)
    
     12:         DEFAULT_REFLECTION_HANDLER()
    
     13:     END_MSG_MAP()
    
     14: }

          如果是子类化,在界面设计器中添加一个ComboBox控件,修改其Owner Draw属性为“Variable”,Has Strings属性设置为“true”。在CColorComboBox类中,重载SubclassWindow函数:

      1:     BOOL SubclassWindow(HWND hWnd)
    
      2:     {
    
      3:         ATLASSERT(hWnd);
    
      4:         ATLASSERT(::IsWindow(hWnd));
    
      5: 
    
      6:         BOOL bRet = __super::SubclassWindow(hWnd);
    
      7:         if ( bRet )
    
      8:             _Init();
    
      9: 
    
     10:         ATLASSERT(GetStyle() & CBS_OWNERDRAWVARIABLE);
    
     11:         ATLASSERT(GetStyle() & CBS_HASSTRINGS);
    
     12: 
    
     13:         return bRet;
    
     14:     }

        如果是动态创建,重载Create函数:

      1:     HWND Create(HWND hWndParent, _U_RECT rect, _U_MENUorID MenuOrID = 0U)
    
      2:     {
    
      3:         HWND hWnd = __super::Create(hWndParent, rect, NULL, 
    
      4:             WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWN /*or CBS_DROPDOWNLIST*/
    
      5:             | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED/* or CBS_OWNERDRAWVARIABLE*/, 
    
      6:             0, MenuOrID, NULL);
    
      7: 
    
      8:         if ( hWnd )
    
      9:             _Init();
    
     10: 
    
     11:         return hWnd;
    
     12:     }

          自绘下拉类表,重载DrawItem函数:

      1:     void DrawItem(LPDRAWITEMSTRUCT lpdis)
    
      2:     {
    
      3:         if ( (long)lpdis->itemID == -1 )
    
      4:             return;
    
      5: 
    
      6:         CDCHandle dc(lpdis->hDC);
    
      7:         CRect rcItem(lpdis->rcItem);
    
      8:         CString strItem;
    
      9:         GetLBText(lpdis->itemID, strItem);
    
     10: 
    
     11:         dc.SetBkMode(TRANSPARENT);
    
     12: 
    
     13:         BOOL bSelected = (lpdis->itemState & ODS_SELECTED) ? TRUE : FALSE;
    
     14:         if ( bSelected )
    
     15:         {
    
     16:             dc.FillSolidRect(rcItem, RGB(238, 238, 238));
    
     17:             dc.SetTextColor(RGB(0, 0, 0));
    
     18:         }
    
     19:         else
    
     20:         {
    
     21:             dc.FillSolidRect(rcItem, RGB(218, 218, 218));
    
     22:             dc.SetTextColor(RGB(255, 255, 255));
    
     23:         }
    
     24: 
    
     25:         dc.DrawText(strItem, strItem.GetLength(), rcItem, DT_LEFT | DT_SINGLELINE);
    
     26:     }

          改变宽度高度,重载MeasureItem函数:

      1:     void MeasureItem(LPMEASUREITEMSTRUCT lpmis)
    
      2:     {
    
      3:         if ( (long)lpmis->itemID == -1 )    
    
      4:             lpmis->itemHeight = 15;  // 文本框(对子类化无效)
    
      5:         else
    
      6:             lpmis->itemHeight = 40;  // 列表
    
      7:     }

          改变CEdit颜色,响应WM_CTLCOLOREDIT消息,返回新的画刷:

      1:     HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit)
    
      2:     {
    
      3:         dc.SetBkMode(TRANSPARENT);
    
      4:         dc.SetTextColor(RGB(255, 0, 0));
    
      5:         
    
      6:         HBRUSH hBrush = ::CreateSolidBrush(RGB(216, 216, 216));
    
      7:         return hBrush;
    
      8:     }

        最终效果:

    ab

    完整代码:ColorComboBox  vs2008

    微信号:yinxufeng503
    本博客文章,有原创和网络搜集,转载请注明出处

    分享到: 更多
  • 相关阅读:
    WinMain与wWinMain,win32的字符集问题
    tornado基础入门(一)——简单了解tornado
    万里长征第二步——django个人博客(第七步 ——上传文件)
    万里长征第二步——django个人博客(第六步 ——添加富文本编辑器)
    万里长征第二步——django个人博客(第五步 ——配置后台admin)
    万里长征第二步——django个人博客(第四步 ——创建数据库)
    万里长征第二步——django个人博客(第三步 —— 设置一些全局变量)
    万里长征第二步——django个人博客(第二步 ——日志记录器)
    万里长征第二步——django个人博客(第一步 ——创建主页)
    新的开始
  • 原文地址:https://www.cnblogs.com/yinxufeng/p/2598974.html
Copyright © 2011-2022 走看看