VC实现类似Windows的颜色选择器
2009-05-29 20:05:43 来源:WEB开发网二、编程步骤
1、启动Visual C++6.0,创建一个基于对话框的应用程序,该程序命名为ColorPickerDemo;
2、在项目代码中添加ColorPicker类;
3、利用资源编辑器在主对话框中加入ID为IDC_EDIT1的编辑框;添加ID为IDC_BUTTON1的按钮,在Style中设置其为Owner draw属性。在CColorPickerDemoDlg类中为IDC_BUTTON1添加Control类别的成员变量(Member Variables)m_btnColor1,然后在ColorPickerDemoDlg.h中将CButton m_btnColor1改为CColorPicker m_btnColor1,并在ColorPickerDemoDlg.h中加上#include "ColorPicker.h",同样的方法来此处理m_btnColor2、 m_btnColor3按钮,这些按钮分别用来在绑定编辑框上显示当前颜色、设置对话框的背景和显示字体色;
4、使用Class Wizard为主对话框添加按纽单击、重画背景等消息处理函数,为CcolorPickerDemoDlg类添加COLORREF m_clrBKColor、COLORREF m_clrTEXTColor成员变量,分别用来存放当前的背景、文本颜色;
5、添加代码,编译运行程序。
三、程序代码
////////////////////////////////////////// ColorPicker.h : header file
#if !defined(AFX_COLORPICKER_H__52F28BCF_DBD4_49A1_8293_1B7FBFB8735D__INCLUDED_)
#define AFX_COLORPICKER_H__52F28BCF_DBD4_49A1_8293_1B7FBFB8735D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CColorPicker : public CButton
{
// Construction
public:
CColorPicker();
virtual ~CColorPicker();
// Attributes
public:
// Operations
public:
void SetColor(COLORREF ref);
void SetBuddy(HWND hWnd);
COLORREF GetColor();
void GetColor(CString& strColor);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CColorPicker)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
//}}AFX_VIRTUAL
// Implementation
private:
void DestroyPaletteWindow();
BOOL CreatePaletteWindow();
static LONG FAR PASCAL PaletteWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
// Generated message map functions
protected:
//{{AFX_MSG(CColorPicker)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
HWND m_hwndBuddy;
COLORREF m_CurrentColor;
HWND m_hPaletteWnd;
BOOL m_bPaletteWndActive;
HCURSOR m_hCursorStraw;
};
/////////////////////////////////////////////////////////// CColorPicker
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_COLORPICKER_H__52F28BCF_DBD4_49A1_8293_1B7FBFB8735D__INCLUDED_)
#include "stdafx.h"
#include "ColorPicker.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define LPARAM_X(lp) ((int)(short)LOWORD(lp))
#define LPARAM_Y(lp) ((int)(short)HIWORD(lp))
//自定义消息
#define WM_SETCOLOR WM_USER+1
#define WM_COLORDLG WM_USER+2
#define IDC_COLORDLG_BUTTON 100
//设置3D效果、白色、黑色画笔;
CPen _pen3DDKShadow(PS_SOLID,1,::GetSysColor(COLOR_3DDKSHADOW));
CPen _penW(PS_SOLID,1,RGB(0xff,0xff,0xff));
CPen _penB(PS_SOLID,1,RGB(0,0,0));
CColorPicker::CColorPicker()
{
m_CurrentColor = COLORREF(::GetSysColor(COLOR_3DFACE));
m_hwndBuddy = NULL;
m_hPaletteWnd = NULL;
m_bPaletteWndActive = FALSE;
}
CColorPicker::~CColorPicker()
{
}
BEGIN_MESSAGE_MAP(CColorPicker, CButton)
//{{AFX_MSG_MAP(CColorPicker)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_SETCURSOR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CColorPicker::OnEraseBkgnd(CDC* pDC)
{
CPen *pOldPen;
COLORREF clr3DFace = GetSysColor(COLOR_3DFACE);
CRect rect;
GetClientRect(&rect);
if(!m_bPaletteWndActive)
{
pDC->Draw3dRect (rect,RGB(0xff,0xff,0xff),GetSysColor (COLOR_3DDKSHADOW));
rect.DeflateRect(1,1);
pDC->Draw3dRect (rect,clr3DFace,clr3DFace);
rect.InflateRect(1,1);
}
rect.DeflateRect(3,3);
pDC->FillSolidRect(rect,m_CurrentColor);
rect.left -= 1;rect.top -= 1;
pOldPen = pDC->SelectObject(&_pen3DDKShadow);
pDC->MoveTo(rect.right - 1,rect.top);
pDC->LineTo(rect.left,rect.top);
pDC->LineTo(rect.left,rect.bottom);
pDC->SelectObject(&_penW);
pDC->LineTo(rect.right - 6,rect.bottom);
pDC->LineTo(rect.right - 6,rect.bottom - 4);
pDC->LineTo(rect.right,rect.bottom - 4);
pDC->MoveTo(rect.right,rect.top);
pDC->LineTo(rect.right,rect.bottom - 3);
rect.right += 1;
rect.bottom += 1;
rect.left = rect.right - 6;
rect.top = rect.bottom - 4;
pDC->FillSolidRect(rect,clr3DFace);
pDC->SelectObject(&_penB);
pDC->MoveTo(rect.left + 1,rect.top + 1);
pDC->LineTo(rect.right,rect.top + 1);
pDC->MoveTo(rect.left + 2,rect.top + 2);
pDC->LineTo(rect.right-1,rect.top + 2);
pDC->MoveTo(rect.left + 3,rect.top + 3);
pDC->LineTo(rect.right-2,rect.top + 3);
pDC->SelectObject(pOldPen);
return TRUE;
}
void CColorPicker::OnLButtonDown(UINT nFlags, CPoint point)
{
CButton::OnLButtonDown(nFlags, point);
::ClientToScreen(this->m_hWnd,&point);
if(CreatePaletteWindow())
{
nFlags = (UINT)m_CurrentColor;
::PostMessage(m_hPaletteWnd,WM_LBUTTONDOWN,nFlags,MAKELPARAM(point.x,point.y));
}
HWND hwndParent = GetParent()->m_hWnd;
if(hwndParent)
{
POINT p1,p2;
RECT rect;
::GetWindowRect(m_hWnd,&rect);
p1.x = rect.left;
p1.y = rect.top;
p2.x = rect.right;
p2.y = rect.bottom;
::ScreenToClient(hwndParent,&p1);
::ScreenToClient(hwndParent,&p2);
rect.left = p1.x;
rect.top = p1.y;
rect.right = p2.x;
rect.bottom = p2.y;
::InvalidateRect(hwndParent,&rect,TRUE);
}
}
void CColorPicker::OnLButtonUp(UINT nFlags, CPoint point)
{
DestroyPaletteWindow();
if((COLORREF)nFlags != m_CurrentColor)
SetColor((COLORREF)nFlags);
else
Invalidate();
}
LONG FAR PASCAL CColorPicker::PaletteWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
POINT point;
CRect crtColorRect(5,125,40,143);
static POINT oldPoint;
static BOOL bMouseMoved = FALSE;
static HWND hwndParent;
static HWND hwndColorBtn;
static HFONT hFont = NULL;
static COLORREF crtColor,oldColor;
static int iActiveRect = -1;
switch(nMsg)
{
case WM_CREATE:
{
hwndParent = ((LPCREATESTRUCT)lParam)->hwndParent;
crtColor = ::GetSysColor(COLOR_3DFACE);
LOGFONT logFont;
ZeroMemory((void*)&logFont,sizeof(logFont));
strcpy(logFont.lfFaceName,"宋体");
logFont.lfHeight = -12;
logFont.lfWeight = 400;
logFont.lfCharSet = GB2312_CHARSET;
logFont.lfOutPrecision = 3;
logFont.lfClipPrecision = 2;
logFont.lfQuality = 1;
logFont.lfPitchAndFamily = 2;
hFont = ::CreateFontIndirect(&logFont);
}
break;
case WM_DESTROY:
::DeleteObject(hFont);
break;
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
if(lpDis->CtlID == IDC_COLORDLG_BUTTON)
{
CRect rect(3,3,8,8);
::FillRect(lpDis->hDC,&lpDis->rcItem,(HBRUSH)::GetStockObject(LTGRAY_BRUSH));
HPEN hOldPen = (HPEN)::SelectObject(lpDis->hDC,_penW);
if(lpDis->itemState == 17)
{
::MoveToEx(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.top,NULL);
::LineTo(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.bottom-1);
::LineTo(lpDis->hDC,lpDis->rcItem.left,lpDis->rcItem.bottom-1);
::SelectObject(lpDis->hDC,_penB);
::LineTo(lpDis->hDC,lpDis->rcItem.left,lpDis->rcItem.top);
::LineTo(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.top);
rect.OffsetRect(1,1);
}
else
{
::MoveToEx(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.top,NULL);
::LineTo(lpDis->hDC,lpDis->rcItem.left,lpDis->rcItem.top);
::LineTo(lpDis->hDC,lpDis->rcItem.left,lpDis->rcItem.bottom-1);
::SelectObject(lpDis->hDC,_penB);
::LineTo(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.bottom-1);
::LineTo(lpDis->hDC,lpDis->rcItem.right-1,lpDis->rcItem.top);
}
::SelectObject(lpDis->hDC,_pen3DDKShadow);
::Rectangle(lpDis->hDC,rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
::SetBkColor(lpDis->hDC, RGB(0xff,0,0));
::ExtTextOut(lpDis->hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect.OffsetRect(2,2);
::Rectangle(lpDis->hDC,rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
::SetBkColor(lpDis->hDC, RGB(0,0xff,0));
::ExtTextOut(lpDis->hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
rect.OffsetRect(2,2);
::Rectangle(lpDis->hDC,rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
::SetBkColor(lpDis->hDC, RGB(0xff,0xff,0));
::ExtTextOut(lpDis->hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
::SelectObject(lpDis->hDC,hOldPen);
}
}
break;
case WM_SETCOLOR:
crtColor = (COLORREF)wParam;
oldColor = crtColor;
break;
case WM_COMMAND:
::PostMessage(hwndParent,WM_COLORDLG,NULL,NULL);
break;
case WM_MOUSEMOVE:
{
BOOL bInCtrlArea = FALSE;
point.x = LPARAM_X(lParam);
point.y = LPARAM_Y(lParam);
::ClientToScreen(hWnd,&point);
if(point.x != oldPoint.x || point.y != oldPoint.y)
{
bMouseMoved = TRUE;
HWND hwndPoint = ::WindowFromPoint(point);
if(hwndPoint)
{
COLORREF crtTMPColor;
CRect rect;
HDC hDC;
hDC = ::GetWindowDC(hwndPoint);
::GetWindowRect(hwndPoint,&rect);
crtTMPColor = GetPixel(hDC,point.x-rect.left,point.y-rect.top);
::ReleaseDC(hwndPoint,hDC);
RECT redrawRect;
redrawRect.left = 0;
redrawRect.right = 150;
redrawRect.top = 120;
redrawRect.bottom = 145;
::GetWindowRect(hWnd,&rect);
if(!rect.PtInRect(point))//不在本窗口
{
crtColor = crtTMPColor;
::InvalidateRect(hWnd,&redrawRect,TRUE);
}
else
{
rect.bottom = rect.top + 120;
int iCurrentActiveRect;
if(rect.PtInRect(point))///判断鼠标是否在当前窗口的色彩区域
{
////计算位于哪个方框内////
point.x -= rect.left;
point.y -= rect.top;
if(point.x%10 != 0 && point.y%10 != 0)
iCurrentActiveRect = point.y/10*19 + point.x/10;
else
iCurrentActiveRect = -1;
}
else
{
iCurrentActiveRect = -1;
crtColor = oldColor;
if(hwndColorBtn == hwndPoint)
::ReleaseCapture();
else
bInCtrlArea = TRUE;
}
if(iCurrentActiveRect != iActiveRect)
{
///清除原焦点
CRect ActiveRect;
ActiveRect.left = iActiveRect%19*10;
ActiveRect.top = iActiveRect/19*10;
ActiveRect.right = ActiveRect.left + 10;
ActiveRect.bottom = ActiveRect.top + 10;
::InvalidateRect(hWnd,&ActiveRect,TRUE);
///新焦点
if(iCurrentActiveRect != -1)
{
crtColor = crtTMPColor;
ActiveRect.left = iCurrentActiveRect%19*10;
ActiveRect.top = iCurrentActiveRect/19*10;
ActiveRect.right = ActiveRect.left + 10;
ActiveRect.bottom = ActiveRect.top + 10;
::InvalidateRect(hWnd,&ActiveRect,TRUE);
}
::InvalidateRect(hWnd,&redrawRect,TRUE);
iActiveRect = iCurrentActiveRect;
}
}
}
}
if(bInCtrlArea)
::PostMessage(hwndParent,WM_SETCURSOR,NULL,MAKELPARAM(1,0));
else
::PostMessage(hwndParent,WM_SETCURSOR,NULL,NULL);
}
break;
case WM_ACTIVATE:
if(LOWORD(wParam) != WA_INACTIVE)
break;
case WM_LBUTTONUP:
point.x = LPARAM_X(lParam);
point.y = LPARAM_Y(lParam);
if(bMouseMoved || ( point.x == oldPoint.x && point.y == oldPoint.y ))
::PostMessage(hwndParent,WM_LBUTTONUP,(UINT)crtColor,lParam);
break;
case WM_LBUTTONDOWN:
oldPoint.x = LPARAM_X(lParam);
oldPoint.y = LPARAM_Y(lParam);
bMouseMoved = FALSE;
::InvalidateRect(hWnd,&crtColorRect,TRUE);
break;
case WM_ERASEBKGND:
{
hDC = (HDC)wParam;
HPEN oldPen = (HPEN)::SelectObject(hDC,_penB);
for(int i=0;i<18;i++)
{
::MoveToEx(hDC,9+i*10,0,NULL);
::LineTo(hDC,9+i*10,120);
}
for(i=0;i<12;i++)
{
::MoveToEx(hDC,0,9+i*10,NULL);
::LineTo(hDC,190,9+i*10);
}
CRect btmRect(0,120,191,150);
::FillRect(hDC,btmRect,(HBRUSH)::GetStockObject(LTGRAY_BRUSH));
::Rectangle(hDC,crtColorRect.left-1,crtColorRect.top-1,crtColorRect.right + 1,crtColorRect.bottom + 1);
::SelectObject(hDC,oldPen);
}
break;
case WM_PAINT:
{
hDC = ::BeginPaint(hWnd,&ps);
CDC dc;
dc.Attach(hDC);
CRect rect;
int x1,y1,i,j,k;
UCHAR R=255,G=255,B=255;
for(i=0;i<12;i++)
{
y1 = i*10;
rect.SetRect(0,y1,9,y1+9);
if(i == 10)
R=G=B=0x17;
dc.FillSolidRect(rect,RGB(R,G,B));
R -= 0x17;
G -= 0x17;
B -= 0x17;
}
R = G = B = 0;
for(k = 0;k < 2;k++)
for(j = 0;j < 18;j++)
for(i = 0;i < 6;i++)
{
x1 = 10+j*10;
y1 = k*60+i*10;
rect.SetRect(x1,y1,x1+9,y1+9);
dc.FillSolidRect(rect,RGB(R,G,B));
if(B == 0xff)
{
B = 0x00;
if(G == 0xff)
{
G = 0x00;
R += 0x33;
}
else
G += 0x33;
}
else
B += 0x33;
}
if(iActiveRect != -1)
{
CRect ActiveRect;
ActiveRect.left = iActiveRect%19*10;
ActiveRect.top = iActiveRect/19*10;
ActiveRect.right = ActiveRect.left + 10;
ActiveRect.bottom = ActiveRect.top + 10;
dc.DrawFocusRect(ActiveRect);
}
rect.SetRect(0,y1+130,60,y1+140);
dc.FillSolidRect(crtColorRect,crtColor);
char strColor[8]="#"; sprintf(strColor+1,"%02X%02X%02X",GetRValue(crtColor),GetGValue(crtColor),GetBValue(crtColor));
HFONT hOldFont = (HFONT)dc.SelectObject(hFont);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(80,127,strColor,7);
dc.SelectObject(hOldFont);
dc.Detach();
::EndPaint(hWnd,&ps);
}
break;
default:
return(::DefWindowProc(hWnd,nMsg,wParam,lParam));
}
return NULL;
}
BOOL CColorPicker::CreatePaletteWindow()
{
if(!m_bPaletteWndActive)
{
// 创建调色板子窗口
WNDCLASS wndcls;
wndcls.style = CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = PaletteWndProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = ::AfxGetInstanceHandle();
wndcls.hIcon = NULL;
wndcls.hCursor = NULL;
wndcls.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = "ColorPalette";
if (!::RegisterClass(&wndcls))
AfxThrowResourceException();
HDC hDC = ::GetDC(m_hWnd);
int scrWidth = ::GetDeviceCaps(hDC,HORZRES);
int scrHeight = ::GetDeviceCaps(hDC,VERTRES);
::ReleaseDC(m_hWnd,hDC);
CRect rect;
GetWindowRect(rect);
rect.top = rect.bottom - 1;
if(rect.left > scrWidth-191)
rect.left = scrWidth-191;
else if(rect.left < 0)
rect.left = 0;
if(rect.top > scrHeight-150)
rect.top = rect.top-150;
rect.bottom = rect.top + 150;
rect.right = rect.left + 191;
if(!(m_hPaletteWnd = ::CreateWindowEx(WS_EX_TOPMOST,"ColorPalette","Palatte",
WS_POPUP|WS_BORDER|WS_VISIBLE,rect.left,rect.top,rect.Width(),
rect.Height(),m_hWnd,NULL,wndcls.hInstance,NULL)))
return FALSE;
}
::PostMessage(m_hPaletteWnd,WM_SETCOLOR,(WPARAM)m_CurrentColor,NULL);
::ShowWindow(m_hPaletteWnd,SW_SHOW);
::SetCapture(m_hPaletteWnd);
m_bPaletteWndActive = TRUE;
return TRUE;
}
void CColorPicker::DestroyPaletteWindow()
{
::DestroyWindow(m_hPaletteWnd);
::UnregisterClass("ColorPalette",::AfxGetInstanceHandle());
m_bPaletteWndActive = FALSE;
m_hPaletteWnd = NULL;
}
BOOL CColorPicker::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if(m_bPaletteWndActive && m_hCursorStraw && nHitTest != 1)
::SetCursor(m_hCursorStraw);
else
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
return TRUE;
}
void CColorPicker::GetColor(CString& strColor)
{
char cColor[8]="#";
sprintf(cColor+1,"%02X%02X%02X",GetRValue(m_CurrentColor),GetGValue(m_CurrentColor),GetBValue(m_CurrentColor));
strColor = cColor;
}
COLORREF CColorPicker::GetColor()
{
return m_CurrentColor;
}
LRESULT CColorPicker::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_COLORDLG)
{
DestroyPaletteWindow();
CColorDialog dlg;
dlg.m_cc.Flags |= CC_FULLOPEN;
if(dlg.DoModal() == IDOK)
SetColor(dlg.GetColor());
return TRUE;
}
else
return CButton::DefWindowProc(message, wParam, lParam);
}
void CColorPicker::SetBuddy(HWND hWnd)
{
m_hwndBuddy = hWnd;
}
void CColorPicker::SetColor(COLORREF ref)
{
m_CurrentColor = ref;
::PostMessage(GetParent()->m_hWnd,WM_COMMAND,MAKELPARAM(::GetWindowLong(m_hWnd,GWL_ID),BN_CLICKED),(LPARAM)m_hWnd);
if(m_hwndBuddy)
{
CString strColor;
GetColor(strColor);
::SetWindowText(m_hwndBuddy,strColor);
}
Invalidate();
}
///////////////////////////////////
BOOL CColorPickerDemoDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(rect);
pDC->FillSolidRect(rect,m_clrBKColor);
return TRUE;
}
void CColorPickerDemoDlg::OnButton2()
{
m_clrBKColor = m_btnColor2.GetColor();
Invalidate();
}
void CColorPickerDemoDlg::OnButton3()
{
m_clrTEXTColor = m_btnColor3.GetColor();
Invalidate();
}
HBRUSH CColorPickerDemoDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr;
switch(nCtlColor)
{
case CTLCOLOR_STATIC:
pDC->SetBkMode( TRANSPARENT );
pDC->SetTextColor( m_clrTEXTColor );
hbr = ( HBRUSH )::GetStockObject( NULL_BRUSH );
break;
default:
hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
return hbr;
}
四、小结
上述实例在实现颜色选择窗的过程中,使用了Windwos API编程的方法,包括窗口的创建、窗口消息的处理等,虽然该方法相对于MFC方法来说比较繁琐,但是它能使读者朋友们更好的掌握Windows底层编程的方法,加深对Windows的消息机制的认识,从而对我们学习、理解Visual C++的MFC类有更大的帮助。
更多精彩
赞助商链接