自繪按鈕實現顏色選擇器
一.前言
很多時候,我們需要讓使用者在軟體上選擇顏色,那麼一個“顏色選擇器”就肯定需要了,本例程就是使用普通的按鈕(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);
}
然後過載DrawItem函式:
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);
}
當然還需要在按鈕的滑鼠訊息裡記錄按鈕的狀態,但這些不是本例程的主要部分,在文章裡就不全部寫出了,大家可以下載完整原始碼檢視。
最後響應BN_CLICKED訊息,彈出位於下方的顏色選擇控制元件。
三.繪製位於下方的顏色選擇控制元件
這個顏色選擇控制元件稍微複雜一些,也可以算作本例程裡一些有用的東西,我是繼承自CWnd建立了一個新的視窗類,採用DirectUI的方式畫出各個顏色小方塊,即各個“子控制元件”事實上是不存在的,只是一些邏輯區域,直接畫在父視窗上。
首先我定義了一個資料結構來儲存各個“子控制元件”的資訊,並且加入到陣列
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;
}
最後畫出各個“子控制元件”:
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());
}
五.使用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兩種工程原始碼)
相關文章
- 點選按鈕實現切換頁面背景顏色效果
- 如何快速實現一個顏色選擇器
- JavaScript點選按鈕切換背景顏色JavaScript
- Android開發 如何使用選擇器(selector) 來實現點選按鈕變色Android
- 自繪實現半透明水晶按鈕
- 【HTML】顏色和選擇器HTML
- 用VC++實現自繪按鈕控制 (轉)
- 選中按鈕改變文字大小和顏色
- Color UI for Mac(顏色選擇器)UIMac
- 從零開始實現一個顏色選擇器(原生JavaScript實現)JavaScript
- HTML 單選按鈕實現 (性別選擇)(解讀)HTML
- 點選按鈕設定其背景顏色程式碼例項
- html 顏色選擇器 親測,很好用HTML
- 11個JavaScript顏色選擇器外掛JavaScript
- 短視訊開發,點選按鈕Button,更換背景顏色
- 快速搭建直播平臺,點選按鈕(Button)後改變顏色
- Java選擇框和單選按鈕Java
- 小程式,選擇顏色,去水印
- 改變Android按鈕背景顏色的高效方法Android
- 點選回車實現按鈕點選功能
- 短視訊系統原始碼,實現按鈕開啟關閉,顏色可自定義原始碼
- 實現前端點選按鈕自動複製剪貼簿功能前端
- 換個按鈕顏色, 就能增長百萬使用者?
- 如何點選一個按鈕實現列印
- 點選按鈕實現數字增加效果
- Android的shape和顏色選擇器結合使用Android
- element-ui的日期選擇框底部清空按鈕點選不關閉日期選擇框的實現辦法UI
- 點選按鈕實現狀態切換效果
- 點選按鈕實現圖片切換效果
- 視訊直播app原始碼,按鈕被按下時顏色隨著改變APP原始碼
- 自繪選單的實現 (轉)
- 微軟Chromium版Edge新特性:支援Win10現代顏色選擇器/印表機微軟Win10
- Ionic3學習筆記(四)修改返回按鈕文字、顏色筆記
- 實現隨機顏色隨機
- 交替顏色列表實現
- js實現的點選連結<a>實現切換背景顏色JS
- 基於js實現點選按鈕回到頂部JS
- 點選按鈕實現文字放大和縮小功能