自绘按钮实现颜色选择器
来源:互联网 发布:python 字符串数组 编辑:程序博客网 时间:2024/05/22 18:16
自绘按钮实现颜色选择器
目录(?)[+]
- 一前言
- 二自绘按钮
- 三绘制位于下方的颜色选择控件
- 四点击更多颜色时弹出的颜色选择对话框
- 五使用CColorButton
- 六总结
一.前言
很多时候,我们需要让用户在软件上选择颜色,那么一个“颜色选择器”就肯定需要了,本例程就是使用普通的按钮(Button)控件来实现颜色选择器。
首先来看一下最后的效果图:
从上图可以看出,这个“颜色选择器”分3个部分,1是可以显示当前选中颜色的按钮;2是点击按钮时在下方弹出的颜色选择部分;3是点击“更多颜色”时弹出的一个选择颜色的对话框。下面分别说说各个部分的实现。
二.自绘按钮
在这里我首先创建了一个CColorButton类,继承自CButton,要实现自绘,首先是要加入BS_OWNERDRAW样式
- BOOL CColorButton::PreCreateWindow(CREATESTRUCT& cs)
- {
- BOOL bRet=CButton::PreCreateWindow(cs);
- ColorButtonInit();
- return bRet;
- }
- void CColorButton::PreSubclassWindow()
- {
- CButton::PreSubclassWindow();
- ColorButtonInit();
- }
- void CColorButton::ColorButtonInit()
- {
- m_bTracking=false;
- m_bOver=m_bDown=m_bDisable=false;
- m_bDisable=IsWindowEnabled()?FALSE:TRUE;
- ModifyStyle(NULL,BS_OWNERDRAW);
- }
BOOL CColorButton::PreCreateWindow(CREATESTRUCT& cs){ BOOL bRet=CButton::PreCreateWindow(cs); ColorButtonInit(); return bRet;}void CColorButton::PreSubclassWindow(){ CButton::PreSubclassWindow(); ColorButtonInit();}void CColorButton::ColorButtonInit(){ m_bTracking=false; m_bOver=m_bDown=m_bDisable=false; m_bDisable=IsWindowEnabled()?FALSE:TRUE; ModifyStyle(NULL,BS_OWNERDRAW);}
然后重载DrawItem函数:
- void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
- {
- DrawButton(lpDrawItemStruct->hDC);
- }
void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){ DrawButton(lpDrawItemStruct->hDC);}
这里的DrawButton是一个单独的函数,用来画出按钮,这里我使用了DrawThemeBackground来画按钮背景,这个API函数的优点是可以根据当前系统主题来画出控件:
- void CColorButton::DrawButton(HDC hDestDC)
- {
- CRect rc;
- GetClientRect(rc);
- int nWindth=rc.Width();
- int nHeight=rc.Height();
- HDC hDC=CreateCompatibleDC(hDestDC);//创建兼容DC,采用双缓冲画出
- HBITMAP hBitmap=CreateCompatibleBitmap(hDestDC,nWindth,nHeight);
- HBITMAP hOldBitmap=(HBITMAP)SelectObject(hDC,hBitmap);
- //画出整个控件背景
- HBRUSH hbr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
- FillRect(hDC,&rc,hbr);
- DeleteObject(hbr);
- HTHEME hTheme=OpenThemeData(m_hWnd,L"Button");
- if(hTheme){
- if(m_bDisable){//禁止状态
- DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_DISABLED,&rc,NULL);
- }else if(m_bDown){//按下状态
- DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_PRESSED,&rc,NULL);
- }else if(m_bOver){//热点状态
- DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_HOT,&rc,NULL);
- }else{//普通状态
- DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_NORMAL,&rc,NULL);
- }
- CloseThemeData (hTheme);
- }else{
- if(m_bDisable){
- DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_INACTIVE);
- }else if(m_bDown){
- DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);
- }else if(m_bOver){
- DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_HOT);
- }else{
- DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH);
- }
- }
- //画出颜色显示区
- rc=CRect(4,4,nWindth-17,nHeight-4);
- hbr=CreateSolidBrush(0xFFFFFF);//颜色显示区的背景
- FillRect(hDC,&rc,hbr);
- DeleteObject(hbr);
- HPEN hPen=CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOWFRAME));//颜色显示区的边框
- FrameRect(hDC,&rc,(HBRUSH)hPen);
- DeleteObject(hPen);
- rc.InflateRect(-2,-2);
- hbr=CreateSolidBrush(m_CurColor);//当前的颜色
- FillRect(hDC,&rc,hbr);
- DeleteObject(hbr);
- //画出下拉的小三角
- int w=7;
- int h=4;
- int x=nWindth-w-7;
- int y=(nHeight-h)/2;
- for(int i=0;i<h;i++){
- MoveToEx(hDC,x,y,NULL);
- LineTo(hDC,x+w,y);
- x++;
- y++;
- w=w-2;
- }
- //复制到控件的DC上
- BitBlt(hDestDC,0,0,nWindth,nHeight,hDC,0,0,SRCCOPY);
- //删除资源,释放内存
- SelectObject(hDC,hOldBitmap);
- DeleteObject(hBitmap);
- DeleteDC(hDC);
- }
void CColorButton::DrawButton(HDC hDestDC){CRect rc;GetClientRect(rc);int nWindth=rc.Width();int nHeight=rc.Height();HDC hDC=CreateCompatibleDC(hDestDC);//创建兼容DC,采用双缓冲画出HBITMAP hBitmap=CreateCompatibleBitmap(hDestDC,nWindth,nHeight);HBITMAP hOldBitmap=(HBITMAP)SelectObject(hDC,hBitmap);//画出整个控件背景HBRUSH hbr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));FillRect(hDC,&rc,hbr);DeleteObject(hbr);HTHEME hTheme=OpenThemeData(m_hWnd,L"Button");if(hTheme){if(m_bDisable){//禁止状态DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_DISABLED,&rc,NULL);}else if(m_bDown){//按下状态DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_PRESSED,&rc,NULL);}else if(m_bOver){//热点状态DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_HOT,&rc,NULL);}else{//普通状态DrawThemeBackground (hTheme,hDC, BP_PUSHBUTTON, PBS_NORMAL,&rc,NULL);}CloseThemeData (hTheme);}else{if(m_bDisable){DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_INACTIVE);}else if(m_bDown){DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_PUSHED);}else if(m_bOver){DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH|DFCS_HOT);}else{DrawFrameControl (hDC,rc,DFC_BUTTON, DFCS_BUTTONPUSH);}}//画出颜色显示区rc=CRect(4,4,nWindth-17,nHeight-4);hbr=CreateSolidBrush(0xFFFFFF);//颜色显示区的背景FillRect(hDC,&rc,hbr);DeleteObject(hbr);HPEN hPen=CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOWFRAME));//颜色显示区的边框FrameRect(hDC,&rc,(HBRUSH)hPen);DeleteObject(hPen);rc.InflateRect(-2,-2);hbr=CreateSolidBrush(m_CurColor);//当前的颜色FillRect(hDC,&rc,hbr);DeleteObject(hbr);//画出下拉的小三角int w=7;int h=4;int x=nWindth-w-7;int y=(nHeight-h)/2;for(int i=0;i<h;i++){MoveToEx(hDC,x,y,NULL);LineTo(hDC,x+w,y);x++;y++;w=w-2;}//复制到控件的DC上BitBlt(hDestDC,0,0,nWindth,nHeight,hDC,0,0,SRCCOPY);//删除资源,释放内存SelectObject(hDC,hOldBitmap);DeleteObject(hBitmap);DeleteDC(hDC);}
当然还需要在按钮的鼠标消息里记录按钮的状态,但这些不是本例程的主要部分,在文章里就不全部写出了,大家可以下载完整源码查看。
最后响应BN_CLICKED消息,弹出位于下方的颜色选择控件。
三.绘制位于下方的颜色选择控件
这个颜色选择控件稍微复杂一些,也可以算作本例程里一些有用的东西,我是继承自CWnd创建了一个新的窗口类,采用DirectUI的方式画出各个颜色小方块,即各个“子控件”事实上是不存在的,只是一些逻辑区域,直接画在父窗口上。
首先我定义了一个数据结构来保存各个“子控件”的信息,并且加入到数组
- typedef struct tagCOLORITEM
- {
- COLORREF color;
- RECT rect;
- BOOL bCheck;
- }COLORITEM,*LPCOLORITEM;
- CArray <COLORITEM,COLORITEM&> m_ItemArray;
typedef struct tagCOLORITEM{COLORREF color;RECT rect;BOOL bCheck;}COLORITEM,*LPCOLORITEM;CArray <COLORITEM,COLORITEM&> m_ItemArray;
创建完窗口后创建各个“子控件”:
- CreateItem(0x000000,_T("黑色"));
- CreateItem(0x800000,_T("藏青"));
- int CColorWnd::CreateItem(COLORREF color,CString strName)
- {
- int nIndex=m_nCount;
- COLORITEM item;
- item.bCheck=color==m_CurColor;
- item.color=color;
- item.rect=CRect(m_nItemX,m_nItemY,m_nItemX+18,m_nItemY+18);
- m_ItemArray.Add(item);
- m_nCount++;
- m_nItemX+=18;
- if(m_nCount%7==0){
- m_nItemY+=18;
- m_nItemX=0;
- }
- m_ToolTip.AddTool(this,strName,&item.rect,100+nIndex);
- return nIndex;
- }
CreateItem(0x000000,_T("黑色"));CreateItem(0x800000,_T("藏青"));int CColorWnd::CreateItem(COLORREF color,CString strName){int nIndex=m_nCount;COLORITEM item;item.bCheck=color==m_CurColor;item.color=color;item.rect=CRect(m_nItemX,m_nItemY,m_nItemX+18,m_nItemY+18);m_ItemArray.Add(item);m_nCount++;m_nItemX+=18;if(m_nCount%7==0){m_nItemY+=18;m_nItemX=0;}m_ToolTip.AddTool(this,strName,&item.rect,100+nIndex);return nIndex;}
最后画出各个“子控件”:
- void CColorWnd::UpdateCache()
- {
- CRect rc;
- GetClientRect(rc);
- int nWindth=rc.Width();
- int nHeight=rc.Height();
- HDC hDC=::GetDC(m_hWnd);
- m_hCacheDC=CreateCompatibleDC(hDC);//创建兼容DC,采用双缓冲画出
- m_hCacheBitmap=CreateCompatibleBitmap(hDC,nWindth,nHeight);
- m_hOldBitmap=(HBITMAP)SelectObject(m_hCacheDC,m_hCacheBitmap);
- m_hOldFont=(HFONT)SelectObject(m_hCacheDC,(HFONT)GetStockObject(DEFAULT_GUI_FONT));
- SetBkMode(m_hCacheDC,TRANSPARENT);
- m_hOrderPen1=CreatePen(PS_SOLID,1,0xA0A0A0);
- m_hOrderPen2=CreatePen(PS_SOLID,1,0xFFFFFF);
- m_hBackBrush1=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
- m_hBackBrush2=CreateSolidBrush(0xFFFFFF);
- FillRect(m_hCacheDC,&rc,m_hBackBrush1);
- int x=4;
- int y=nHeight-29;
- HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);
- MoveToEx(m_hCacheDC,x,y,NULL);
- LineTo(m_hCacheDC,nWindth-x,y);
- SelectObject(m_hCacheDC,hOldPen);
- y+=1;
- hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);
- MoveToEx(m_hCacheDC,x,y,NULL);
- LineTo(m_hCacheDC,nWindth-x,y);
- SelectObject(m_hCacheDC,hOldPen);
- for(int i=0;i<m_nCount;i++){
- DrawItem(m_hCacheDC,i);
- }
- BitBlt(hDC,0,0,nWindth,nHeight,m_hCacheDC,0,0,SRCCOPY);
- ::ReleaseDC(m_hWnd,hDC);
- }
- void CColorWnd::DrawItem(HDC hDC,int nIndex)
- {
- COLORITEM item=m_ItemArray.GetAt(nIndex);
- HBRUSH hbr=m_hBackBrush1;
- if(item.color!=-1 && item.bCheck){
- hbr=m_hBackBrush2;
- }
- FillRect(m_hCacheDC,&item.rect,hbr);
- if(m_nDownItem==nIndex || item.bCheck){
- HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);
- SelectObject(m_hCacheDC,hOldPen);
- hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);
- MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);
- SelectObject(m_hCacheDC,hOldPen);
- }else if(m_nHotItem==nIndex){
- HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);
- SelectObject(m_hCacheDC,hOldPen);
- hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);
- MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);
- MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);
- LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);
- SelectObject(m_hCacheDC,hOldPen);
- }
- if(item.color!=-1){
- CRect rc(item.rect);
- rc.InflateRect(-3,-3);
- hbr=CreateSolidBrush(item.color);
- FillRect(hDC,&rc,hbr);
- DeleteObject(hbr);
- FrameRect(hDC,&rc,(HBRUSH)m_hOrderPen1);
- }else{
- DrawText(hDC,_T("其他颜色..."),-1,&item.rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
- }
- }
void CColorWnd::UpdateCache(){CRect rc;GetClientRect(rc);int nWindth=rc.Width();int nHeight=rc.Height();HDC hDC=::GetDC(m_hWnd);m_hCacheDC=CreateCompatibleDC(hDC);//创建兼容DC,采用双缓冲画出m_hCacheBitmap=CreateCompatibleBitmap(hDC,nWindth,nHeight);m_hOldBitmap=(HBITMAP)SelectObject(m_hCacheDC,m_hCacheBitmap); m_hOldFont=(HFONT)SelectObject(m_hCacheDC,(HFONT)GetStockObject(DEFAULT_GUI_FONT)); SetBkMode(m_hCacheDC,TRANSPARENT);m_hOrderPen1=CreatePen(PS_SOLID,1,0xA0A0A0);m_hOrderPen2=CreatePen(PS_SOLID,1,0xFFFFFF);m_hBackBrush1=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));m_hBackBrush2=CreateSolidBrush(0xFFFFFF);FillRect(m_hCacheDC,&rc,m_hBackBrush1);int x=4;int y=nHeight-29;HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);MoveToEx(m_hCacheDC,x,y,NULL);LineTo(m_hCacheDC,nWindth-x,y);SelectObject(m_hCacheDC,hOldPen);y+=1;hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);MoveToEx(m_hCacheDC,x,y,NULL);LineTo(m_hCacheDC,nWindth-x,y);SelectObject(m_hCacheDC,hOldPen);for(int i=0;i<m_nCount;i++){DrawItem(m_hCacheDC,i);}BitBlt(hDC,0,0,nWindth,nHeight,m_hCacheDC,0,0,SRCCOPY);::ReleaseDC(m_hWnd,hDC);}void CColorWnd::DrawItem(HDC hDC,int nIndex){COLORITEM item=m_ItemArray.GetAt(nIndex);HBRUSH hbr=m_hBackBrush1;if(item.color!=-1 && item.bCheck){hbr=m_hBackBrush2;}FillRect(m_hCacheDC,&item.rect,hbr);if(m_nDownItem==nIndex || item.bCheck){HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);SelectObject(m_hCacheDC,hOldPen);hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);SelectObject(m_hCacheDC,hOldPen);}else if(m_nHotItem==nIndex){HPEN hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen2);MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.top);MoveToEx(m_hCacheDC,item.rect.left,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.left,item.rect.bottom-1);SelectObject(m_hCacheDC,hOldPen);hOldPen=(HPEN)SelectObject(m_hCacheDC,m_hOrderPen1);MoveToEx(m_hCacheDC,item.rect.right-1,item.rect.top,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);MoveToEx(m_hCacheDC,item.rect.left,item.rect.bottom-1,NULL);LineTo(m_hCacheDC,item.rect.right-1,item.rect.bottom-1);SelectObject(m_hCacheDC,hOldPen);}if(item.color!=-1){CRect rc(item.rect);rc.InflateRect(-3,-3); hbr=CreateSolidBrush(item.color);FillRect(hDC,&rc,hbr);DeleteObject(hbr);FrameRect(hDC,&rc,(HBRUSH)m_hOrderPen1);}else{DrawText(hDC,_T("其他颜色..."),-1,&item.rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);}}
四.点击“更多颜色”时弹出的颜色选择对话框
这部分,我就没有自己去画了,而是直接采用了MFC的CColorDialog:
- CColorDialog dlg(m_CurColor,0,this);
- if(dlg.DoModal()==IDOK){
- SetColor(dlg.GetColor());
- }
CColorDialog dlg(m_CurColor,0,this);if(dlg.DoModal()==IDOK){SetColor(dlg.GetColor());}
五.使用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两种工程源码)
- 自绘按钮实现颜色选择器
- 自绘按钮实现颜色选择器
- 自绘按钮实现颜色选择器
- 自绘按钮实现颜色选择器
- 自写两种颜色选择器
- Button 提交按钮+颜色变化选择器 shape 实现
- 通过自绘背景图改变按钮颜色
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘按钮的实现
- 自绘实现半透明水晶按钮
- HDU 2201 熊猫阿波的故事
- ListView
- 004_005 Python 在不适用引用的时候,创建列表的列表
- 基于浏览器的在线代码编辑器
- 自绘按钮实现颜色选择器
- AVL树及C语言实现
- Java多线程2:synchronized
- 颜色迁移之二——Reinhard经典算法
- 在Eclipse中debug源码OpenERP7.0的步骤
- oracle sql语句
- Windows,linux双系统,删除linux.之后恢复损坏的MBR方法
- SVN问题
- jQueryMobile主题修改的若干问题