自绘按钮实现颜色选择器

来源:互联网 发布:python 字符串数组 编辑:程序博客网 时间:2024/05/22 18:16
1787人阅读 评论(4)收藏 举报
nullbutton数据结构mfcstruct

目录(?)[+]

  1. 一前言
  2. 二自绘按钮
  3. 三绘制位于下方的颜色选择控件
  4. 四点击更多颜色时弹出的颜色选择对话框
  5. 五使用CColorButton
  6. 六总结

一.前言

很多时候,我们需要让用户在软件上选择颜色,那么一个“颜色选择器”就肯定需要了,本例程就是使用普通的按钮(Button)控件来实现颜色选择器。
首先来看一下最后的效果图:

从上图可以看出,这个“颜色选择器”分3个部分,1是可以显示当前选中颜色的按钮;2是点击按钮时在下方弹出的颜色选择部分;3是点击“更多颜色”时弹出的一个选择颜色的对话框。下面分别说说各个部分的实现。

二.自绘按钮

在这里我首先创建了一个CColorButton类,继承自CButton,要实现自绘,首先是要加入BS_OWNERDRAW样式

[cpp] view plaincopyprint?
  1. BOOL CColorButton::PreCreateWindow(CREATESTRUCT& cs)  
  2. {  
  3.   BOOL bRet=CButton::PreCreateWindow(cs);  
  4.   ColorButtonInit();  
  5.   return bRet;  
  6. }  
  7.   
  8. void CColorButton::PreSubclassWindow()  
  9. {  
  10.   CButton::PreSubclassWindow();  
  11.   ColorButtonInit();  
  12. }  
  13.   
  14. void CColorButton::ColorButtonInit()  
  15. {  
  16.   m_bTracking=false;  
  17.   m_bOver=m_bDown=m_bDisable=false;  
  18.   m_bDisable=IsWindowEnabled()?FALSE:TRUE;  
  19.   ModifyStyle(NULL,BS_OWNERDRAW);  
  20. }  


然后重载DrawItem函数:

[cpp] view plaincopyprint?
  1. void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
  2. {  
  3.    DrawButton(lpDrawItemStruct->hDC);  
  4. }  


这里的DrawButton是一个单独的函数,用来画出按钮,这里我使用了DrawThemeBackground来画按钮背景,这个API函数的优点是可以根据当前系统主题来画出控件:

[cpp] view plaincopyprint?
  1. void CColorButton::DrawButton(HDC hDestDC)  
  2. {  
  3. CRect rc;  
  4. GetClientRect(rc);  
  5. int nWindth=rc.Width();  
  6. int nHeight=rc.Height();  
  7. HDC hDC=CreateCompatibleDC(hDestDC);//创建兼容DC,采用双缓冲画出  
  8. HBITMAP hBitmap=CreateCompatibleBitmap(hDestDC,nWindth,nHeight);  
  9. HBITMAP hOldBitmap=(HBITMAP)SelectObject(hDC,hBitmap);  
  10. //画出整个控件背景   
  11. HBRUSH hbr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));  
  12. FillRect(hDC,&rc,hbr);  
  13. DeleteObject(hbr);  
  14. HTHEME hTheme=OpenThemeData(m_hWnd,L"Button");  
  15. if(hTheme){  
  16. if(m_bDisable){//禁止状态  
  17. DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_DISABLED,&rc,NULL);  
  18. }else if(m_bDown){//按下状态  
  19. DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_PRESSED,&rc,NULL);  
  20. }else if(m_bOver){//热点状态  
  21. DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_HOT,&rc,NULL);  
  22. }else{//普通状态  
  23. DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_NORMAL,&rc,NULL);  
  24. }  
  25. CloseThemeData (hTheme);  
  26. }else{  
  27. if(m_bDisable){  
  28. DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_INACTIVE);  
  29. }else if(m_bDown){  
  30. DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);  
  31. }else if(m_bOver){  
  32. DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_HOT);  
  33. }else{  
  34. DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH);  
  35. }  
  36. }  
  37.   
  38. //画出颜色显示区   
  39. rc=CRect(4,4,nWindth-17,nHeight-4);  
  40. hbr=CreateSolidBrush(0xFFFFFF);//颜色显示区的背景   
  41. FillRect(hDC,&rc,hbr);  
  42. DeleteObject(hbr);  
  43. HPEN hPen=CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOWFRAME));//颜色显示区的边框  
  44. FrameRect(hDC,&rc,(HBRUSH)hPen);  
  45. DeleteObject(hPen);  
  46. rc.InflateRect(-2,-2);  
  47. hbr=CreateSolidBrush(m_CurColor);//当前的颜色  
  48. FillRect(hDC,&rc,hbr);  
  49. DeleteObject(hbr);  
  50. //画出下拉的小三角   
  51. int w=7;  
  52. int h=4;  
  53. int x=nWindth-w-7;  
  54. int y=(nHeight-h)/2;  
  55. for(int i=0;i<h;i++){  
  56. MoveToEx(hDC,x,y,NULL);  
  57. LineTo(hDC,x+w,y);  
  58. x++;  
  59. y++;  
  60. w=w-2;  
  61. }  
  62.   
  63. //复制到控件的DC上   
  64. BitBlt(hDestDC,0,0,nWindth,nHeight,hDC,0,0,SRCCOPY);  
  65.   
  66. //删除资源,释放内存   
  67. SelectObject(hDC,hOldBitmap);  
  68. DeleteObject(hBitmap);  
  69. DeleteDC(hDC);  
  70. }  


当然还需要在按钮的鼠标消息里记录按钮的状态,但这些不是本例程的主要部分,在文章里就不全部写出了,大家可以下载完整源码查看。
最后响应BN_CLICKED消息,弹出位于下方的颜色选择控件。

三.绘制位于下方的颜色选择控件


这个颜色选择控件稍微复杂一些,也可以算作本例程里一些有用的东西,我是继承自CWnd创建了一个新的窗口类,采用DirectUI的方式画出各个颜色小方块,即各个“子控件”事实上是不存在的,只是一些逻辑区域,直接画在父窗口上。
首先我定义了一个数据结构来保存各个“子控件”的信息,并且加入到数组

[cpp] view plaincopyprint?
  1. typedef struct tagCOLORITEM  
  2. {  
  3.     COLORREF color;  
  4.     RECT rect;  
  5.     BOOL bCheck;  
  6. }COLORITEM,*LPCOLORITEM;  
  7.   
  8. CArray <COLORITEM,COLORITEM&> m_ItemArray;  


创建完窗口后创建各个“子控件”:

[cpp] view plaincopyprint?
  1. CreateItem(0x000000,_T("黑色"));  
  2. CreateItem(0x800000,_T("藏青"));  
  3.   
  4. int CColorWnd::CreateItem(COLORREF color,CString strName)  
  5. {  
  6.     int nIndex=m_nCount;  
  7.     COLORITEM item;  
  8.     item.bCheck=color==m_CurColor;  
  9.     item.color=color;  
  10.     item.rect=CRect(m_nItemX,m_nItemY,m_nItemX+18,m_nItemY+18);  
  11.     m_ItemArray.Add(item);  
  12.     m_nCount++;  
  13.     m_nItemX+=18;  
  14.     if(m_nCount%7==0){  
  15.         m_nItemY+=18;  
  16.         m_nItemX=0;  
  17.     }  
  18.       
  19.     m_ToolTip.AddTool(this,strName,&item.rect,100+nIndex);  
  20.     return nIndex;  
  21. }  


最后画出各个“子控件”:

[cpp] view plaincopyprint?
  1. void CColorWnd::UpdateCache()  
  2. {  
  3.     CRect rc;  
  4.     GetClientRect(rc);  
  5.     int nWindth=rc.Width();  
  6.     int nHeight=rc.Height();  
  7.     HDC hDC=::GetDC(m_hWnd);  
  8.     m_hCacheDC=CreateCompatibleDC(hDC);//创建兼容DC,采用双缓冲画出  
  9.     m_hCacheBitmap=CreateCompatibleBitmap(hDC,nWindth,nHeight);  
  10.     m_hOldBitmap=(HBITMAP)SelectObject(m_hCacheDC,m_hCacheBitmap);   
  11.     m_hOldFont=(HFONT)SelectObject(m_hCacheDC,(HFONT)GetStockObject(DEFAULT_GUI_FONT));   
  12.     SetBkMode(m_hCacheDC,TRANSPARENT);  
  13.       
  14.     m_hOrderPen1=CreatePen(PS_SOLID,1,0xA0A0A0);  
  15.     m_hOrderPen2=CreatePen(PS_SOLID,1,0xFFFFFF);  
  16.     m_hBackBrush1=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));  
  17.     m_hBackBrush2=CreateSolidBrush(0xFFFFFF);  
  18.       
  19.     FillRect(m_hCacheDC,&rc,m_hBackBrush1);  
  20.     int x=4;  
  21.     int y=nHeight-29;  
  22.     HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);  
  23.     MoveToEx(m_hCacheDC,x,y,NULL);  
  24.     LineTo(m_hCacheDC,nWindth-x,y);  
  25.     SelectObject(m_hCacheDC,hOldPen);  
  26.     y+=1;  
  27.     hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);  
  28.     MoveToEx(m_hCacheDC,x,y,NULL);  
  29.     LineTo(m_hCacheDC,nWindth-x,y);  
  30.     SelectObject(m_hCacheDC,hOldPen);  
  31.       
  32.       
  33.     for(int i=0;i<m_nCount;i++){  
  34.         DrawItem(m_hCacheDC,i);  
  35.     }  
  36.       
  37.       
  38.     BitBlt(hDC,0,0,nWindth,nHeight,m_hCacheDC,0,0,SRCCOPY);  
  39.     ::ReleaseDC(m_hWnd,hDC);  
  40. }  
  41.       
  42. void CColorWnd::DrawItem(HDC hDC,int nIndex)  
  43. {  
  44.     COLORITEM item=m_ItemArray.GetAt(nIndex);  
  45.     HBRUSH hbr=m_hBackBrush1;  
  46.     if(item.color!=-1 && item.bCheck){  
  47.         hbr=m_hBackBrush2;  
  48.     }  
  49.     FillRect(m_hCacheDC,&item.rect,hbr);  
  50.       
  51.       
  52.     if(m_nDownItem==nIndex || item.bCheck){  
  53.         HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);  
  54.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);  
  55.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);  
  56.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);  
  57.         LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);  
  58.         SelectObject(m_hCacheDC,hOldPen);  
  59.         hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);  
  60.         MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);  
  61.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);  
  62.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);  
  63.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);  
  64.         SelectObject(m_hCacheDC,hOldPen);  
  65.     }else if(m_nHotItem==nIndex){  
  66.         HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);  
  67.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);  
  68.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);  
  69.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);  
  70.         LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);  
  71.         SelectObject(m_hCacheDC,hOldPen);  
  72.         hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);  
  73.         MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);  
  74.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);  
  75.         MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);  
  76.         LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);  
  77.         SelectObject(m_hCacheDC,hOldPen);  
  78.     }  
  79.       
  80.     if(item.color!=-1){  
  81.         CRect rc(item.rect);  
  82.         rc.InflateRect(-3,-3);   
  83.         hbr=CreateSolidBrush(item.color);  
  84.         FillRect(hDC,&rc,hbr);  
  85.         DeleteObject(hbr);  
  86.         FrameRect(hDC,&rc,(HBRUSH)m_hOrderPen1);  
  87.     }else{  
  88.         DrawText(hDC,_T("其他颜色..."),-1,&item.rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);  
  89.     }  
  90. }  


四.点击“更多颜色”时弹出的颜色选择对话框

这部分,我就没有自己去画了,而是直接采用了MFC的CColorDialog:

[cpp] view plaincopyprint?
  1. CColorDialog dlg(m_CurColor,0,this);  
  2. if(dlg.DoModal()==IDOK){  
  3.     SetColor(dlg.GetColor());  
  4. }  


五.使用CColorButton

1.把ColorButton.h、ColorButton.cpp加入到你的工程
2.在对话框的头文件里引用ColorButton.h 
#include "ColorButton.h"
3.在对话框的头文件里声明变量 
CColorButton m_ColorButton1;
4.可以使用一下3种方式来关联按钮控件 
DDX_Control(pDX,IDC_BUTTON1, m_ColorButton1);   
m_ColorButton1.SubclassWindow(...)子类化关联现有控件;   
m_ColorButton1.Create(...)创建控件
5.在BEGIN_MESSAGE_MAP里添加消息映射 
ON_BN_COLORCHANGE(IDC_BUTTON1,& CColorBtnTestDlg::OnBnColorChangeButton1)
6.设置“颜色选择器”的颜色 m_ColorButton1.SetColor()
7.获取“颜色选择器”的当前选择的颜色 m_ColorButton1.GetColor()

六.总结

很多时候我们需要一些非系统自带的标准控件,完全可以通过自绘来实现,Windows整个都是画出来的,只要掌握了方法,我们也可以画出各种的窗口、控件,希望本文能给你带来一些帮助。

 

源代码下载(包含VS2005以及VC6两种工程源码)

更多0
0 0
原创粉丝点击