在VC++应用程序中实现颜色选择组合框

王朝学院·作者佚名  2011-12-09  
宽屏版  字体:  |  |  | 超大  

相信读者朋友们对Office2000一定非常熟悉吧,它里面的东东可真不少,不管是活泼可爱的"大眼夹",还是各种平面造型的Windows控件都很受广大用户喜欢。那么这次就让我们来模拟它做个十分常用的控件:"颜色组合框"。假如你现在正在做关于字处理类的软件时这个"东东"一定对你有用。程序编译运行后的界面效果如图一所示:

图一、颜色选择组合框

一、实现方法

首先让我们先来了解一下画控件的基本原理和过程,也许这个才是本文的原意。大家都知道Windows中所有可视的东西都是画出来的,那么这个画画的内部过程又是怎样的呢?一般画Windows控件的过程分为三大部分:一是在WM_MEASUREITEM消息影射函数中设置当前要画的Item的大小尺寸;二是在WM_DRAWITEM消息影射函数中根据Item的大小尺寸来画该Item(图标/位图/字符串等);三是在WM_PAINT消息映射函数中不断的绘制当前的控件内容。下面我们针对CBSColorComboBox类的这几个过程来做个简单的介绍:

在WM_MEASUREITEM消息影射函数中设定Item的大小尺寸的时候,我们只需要设置Item的高度即可。这里的高度我们设置为2倍的系统小图标(SMALL ICON)的高度,其尺寸用::GetSystemMetrics(SM_CXSMICON)取得。

Visual C++的程序开发人员可以在Item的矩形区域内画各种各样的信息,例如:图标/位图/字符串等等。那么有人会疑问:"我们用什么来画?我们在哪里画?又如何来画呢?"。答案其实都在这个LPDRAWITEMSTRUCT结构中。hDC成员为设备上下文环境(HDC),获得了该设备句柄也就意味着我们拥有了画任何位图/图标/文本的能力;那么接下来的问题就是:我们在哪里来画呢?答案也很简单:获得LPDRAWITEMSTRUCT结构中Item的矩形区域(rcItem),那么这就是你施展才华的空间了,要充分利用它哦!

最后一步就是如何来画的问题了,说白了就是如何分配每个元素的空间,如何在它们各自的空间上画出你想要的东西。按照常规一般分别计算出ICON所占的矩形区域/文本所占的矩形区域/位图的矩形区域,假如你还有其他元素那么也应该计算出该元素所占的矩形区域/位图所占的矩形区域。接下来的一切都很简单了,不外乎CDC类的几个常用函数:画图标用DrawIcon()、画位图用BitBlt()、画文字用DrawText()等函数。假如你觉得视觉上还不够COOL,你还可以来设置各个Item的文本颜色,背景颜色,以及图标的突起和凹陷的视觉效果。

不过在上述过程中需要注重三个问题,一是为了消除不断绘制所带来的闪烁现象,需要在WM_ERASEBKGND消息响应中作些非凡处理;在WM_PAINT消息中直接把组合框的客户区当成一幅位图来不断更新,而不是对ICON区域和文本区域分别重绘。二是每当用户改变了组合框的当前内容后,在画新的Item之前一定要记得清除前次组合框内的内容。三是假如想选择更多的颜色,那么只要选择组合框中的最后一个Item(More Colors)即可,这个Item是为用户自定义颜色而专门设置的。

二、编程步骤

1、启动Visual C++6.0,生成一个基于对话框的项目,将该项目命名为"WW";

2、使用Class Wizard新建一个类CBSColorComboBox,其基类选择为CComboBox类;

3、在程序的对话框中放置一个ComboBox控件,使用CLASSWIZARD添加相应的CComboBox类成员变量,然后将该成员变量的类型修改为CBSColorComboBox;

4、添加代码,编译运行程序。

三、程序代码

//////////////////////////////////////////////////////////////CBSColorComboBox类的头文件;

#if !defined(_BS_BSCOLORCB)

#define _BS_BSCOLORCB

#include

//系统常用颜色的自定义名称

const static char* strColorName[] =

{

"crSCROLLBAR","crBACKGROUND","crACTIVECAPTION", "crINACTIVECAPTION", "crMENU", "crWINDOW", "crWINDOWFRAME", "crMENUTEXT", "crWINDOWTEXT", "crCAPTIONTEXT", "crACTIVEBORDER","crINACTIVEBORDER", "crAPPWORKSPACE", "crHIGHLIGHT", "crHIGHLIGHTTEXT", "crBTNFACE", "crBTNSHADOW", "crGRAYTEXT", "crBTNTEXT", "crINACTIVECAPTIONTEXT",

"crBTNHIGHLIGHT","cr3DDKSHADOW", "cr3DLIGHT", "crINFOTEXT", "crINFOBK",

"crHOTLIGHT","crGRADIENTACTIVECAPTION", crGRADIENTINACTIVECAPTION"

};

typedef struct BSCBITEM

{

int iIndex;

COLORREF crColor;

LPCTSTR lpCaption;

}BSCBITEM, *LPBSCBITEM;

class CBSColorComboBox : public CComboBox

{

DECLARE_DYNCREATE(CBSColorComboBox)

public:

CBSColorComboBox();

virtual ~CBSColorComboBox();

BOOL Create(DWord dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

//初始化组合框(第一个被调用的函数)

void InitBSColorCB(void);

//得到当前的颜色值或R/G/B值

COLORREF GetColor();

void GetRGBValue(int* R, int* G, int* B);

public:

//{{AFX_VIRTUAL(CBSColorComboBox)

public:

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);

//}}AFX_VIRTUAL

PRotected:

bool m_bOverControl; //鼠标的状态(是否处于按钮上)

int iIconX, iIconY; //SMALL ICON的大小尺寸

COLORREF m_crColor; //当前选中的颜色

CList

m_crItem;

void OnCBPaint(CDC* pDC);

LPBSCBITEM GetItem(int iIndex = 0);

protected:

//{{AFX_MSG(CBSColorComboBox)

afx_msg BOOL OnEraseBkgnd(CDC* pDC);

afx_msg void OnPaint();

afx_msg void OnTimer(UINT nIDEvent);

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

afx_msg void OnSelchange();

afx_msg void OnSelendok();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#endif // !defined(_BS_BSCOLORCB)

///////////////////////////////////////////////////////////////CBSColorComboBox的实现文件;

#include "stdafx.h"

#include "BSColorComboBox.h"

CBSColorComboBox::CBSColorComboBox()

{

//当前鼠标是否在对象上

m_bOverControl = false;

//小图标尺寸

iIconX = ::GetSystemMetrics(SM_CXSMICON);

iIconY = ::GetSystemMetrics(SM_CYSMICON);

}

CBSColorComboBox::~CBSColorComboBox()

{

while(!m_crItem.IsEmpty())

{

LPBSCBITEM lpItem = m_crItem.RemoveHead();

delete lpItem;

}

}

BOOL CBSColorComboBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)

{

DWORD dw = dwStyle;

if( !CComboBox::Create(dw, rect, pParentWnd, nID) )

return false;

CFont * font = CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT));

SetFont(font);

return true;

}

IMPLEMENT_DYNCREATE(CBSColorComboBox, CComboBox)

BEGIN_MESSAGE_MAP(CBSColorComboBox, CComboBox)

//{{AFX_MSG_MAP(CBSColorComboBox)

ON_WM_ERASEBKGND()

ON_WM_PAINT()

ON_WM_TIMER()

ON_WM_MOUSEMOVE()

ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelchange)

ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelendok)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CBSColorComboBox::InitBSColorCB(void)

{

int iMinColor = COLOR_SCROLLBAR,

iMaxColor = COLOR_BTNHIGHLIGHT;

if(WINVER

= 0x0400)

iMaxColor = COLOR_INFOBK;

if(WINVER

= 0x0500)

iMaxColor = 28;

//初始化CB颜色列表框的Item(常见的SysColor值)

for(int iLoop = iMinColor; iLoop

{

LPBSCBITEM lpItem = new BSCBITEM;

lpItem-

iIndex = AddString(strColorName[iLoop]);

lpItem-

crColor = ::GetSysColor(iLoop);

lpItem-

lpCaption = strColorName[iLoop];

//

if(m_crItem.IsEmpty())

m_crItem.AddHead(lpItem);

else

m_crItem.AddTail(lpItem);

}

//该Item是为了用户自定义颜色而设置

LPBSCBITEM lpItem = new BSCBITEM;

lpItem-

iIndex = AddString("More Colors");

lpItem-

crColor = RGB(213, 233, 249);

lpItem-

lpCaption = "More Colors";

if(m_crItem.IsEmpty())

m_crItem.AddHead(lpItem);

else

m_crItem.AddTail(lpItem);

//初始化当前颜色

m_crColor = m_crItem.GetHead()-

crColor;

}

BOOL CBSColorComboBox::OnEraseBkgnd(CDC* pDC)

{

ASSERT(pDC-

GetSafeHdc());

return false;

}

void CBSColorComboBox::OnPaint()

{

CPaintDC dc(this);

OnCBPaint(&dc);

}

void CBSColorComboBox::OnCBPaint(CDC* pDC)

{

ASSERT(pDC-

GetSafeHdc());

//绘制客户区

CDC dMemDC;

dMemDC.CreateCompatibleDC(pDC);

dMemDC.SetMapMode(pDC-

GetMapMode());

//画动作

CBitmap mNewBmp;

RECT rc;

GetClientRect(&rc);

mNewBmp.CreateCompatibleBitmap(pDC, rc.right - rc.left, rc.bottom - rc.top);

CBitmap* pOldBmp = dMemDC.SelectObject(&mNewBmp);

//子类可以以friend方式来访问父类的protected成员变量和函数

CWnd::DefWindowProc(WM_PAINT, (WPARAM)dMemDC.m_hDC, 0);

pDC-

BitBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, &dMemDC,rc.left ,rc.top, SRCCOPY);

//恢复

dMemDC.SelectObject(pOldBmp);

pOldBmp-

DeleteObject();

dMemDC.DeleteDC();

GetWindowRect(&rc);

ScreenToClient(&rc);

pDC-

DrawEdge(&rc, (m_bOverControl ? BDR_RAISEDINNER: BDR_SUNKENINNER), BF_RECT);

}

void CBSColorComboBox::OnTimer(UINT nIDEvent)

{

if(nIDEvent == 888 && IsWindowEnabled())

{

CPoint point;

::GetCursorPos(&point);

CRect rect;

GetWindowRect(&rect);

if(rect.PtInRect(point))

{

m_bOverControl = true;

}

else

{

m_bOverControl = false;

KillTimer(nIDEvent);

}

}

CComboBox::OnTimer(nIDEvent);

}

void CBSColorComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

{

lpMeasureItemStruct-

itemHeight = iIconY + 5;

}

void CBSColorComboBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)

{

ASSERT(lpDIS-

CtlType == ODT_COMBOBOX);

//画笔

CDC* pDC = CDC::FromHandle(lpDIS-

hDC);

ASSERT(pDC-

GetSafeHdc());

//绘制区

RECT rc = lpDIS-

rcItem;

RECT rcIcon(rc), rcTxt(rc);

//当前的Item索引号

LPBSCBITEM lpItem = GetItem(lpDIS-

itemID);

if(lpItem != NULL)

{

//画颜色Icon

rcIcon.right = rcIcon.left + iIconX;

rcIcon.top += (rc.bottom - rc.top - iIconY) / 2;

rcIcon.bottom = rcIcon.top + iIconY;

pDC-

FillSolidRect(rcIcon.left, rcIcon.top,

rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, lpItem-

crColor);

pDC-

DrawEdge(&rcIcon, BDR_RAISEDINNER, BF_RECT);

//开始画文字

int nOldBkMode = pDC-

SetBkMode(TRANSPARENT);

pDC-

SetTextColor(RGB(0, 0, 0));

rcTxt.left = rcIcon.right + 5;

rcTxt.top = rcIcon.top;

pDC-

DrawText(lpItem-

lpCaption, &rcTxt,

DT_VCENTER DT_END_ELLipSIS DT_NOCLIP DT_SINGLELINE);

pDC-

SetBkMode(nOldBkMode);

}

}

void CBSColorComboBox::OnMouseMove(UINT nFlags, CPoint point)

{

m_bOverControl = true;

SetTimer(888, 100, NULL);

CComboBox::OnMouseMove(nFlags, point);

}

LPBSCBITEM CBSColorComboBox::GetItem(int iIndex)

{

//当前的Item索引号

POSITION pos = m_crItem.FindIndex(iIndex);

if(pos)

{

LPBSCBITEM lpItem = m_crItem.GetAt(pos);

ASSERT(lpItem);

return lpItem;

}

else

return (LPBSCBITEM)NULL;

}

COLORREF CBSColorComboBox::GetColor()

{

if(IsWindowEnabled())

return m_crColor;

else

{

return (m_crColor = GetItem(this-

GetCurSel())-

crColor);

}

}

void CBSColorComboBox::GetRGBValue(int* R, int* G, int* B)

{

*R = GetRValue((DWORD)m_crColor);

*G = GetGValue((DWORD)m_crColor);

*B = GetBValue((DWORD)m_crColor);

}

void CBSColorComboBox::OnSelchange()

{

int iIndex = GetCurSel();

if(iIndex != CB_ERR && iIndex

= 0)

{

CDC* pDC = this-

GetDC();

//绘制区

RECT rc;

int iScrollX = ::GetSystemMetrics(SM_CXVSCROLL);

GetClientRect(&rc);

pDC-

FillSolidRect(rc.left + 2, rc.top + 2, rc.right - rc.left - iScrollX - 4, rc.bottom - rc.top - 2,

::GetSysColor(COLOR_WINDOW));

RECT rcIcon(rc), rcTxt(rc);

//当前的Item索引号

LPBSCBITEM lpItem = GetItem(iIndex);

if(lpItem != NULL)

{

m_crColor = lpItem-

crColor;

//画颜色Icon

rcIcon.left += 2;

rcIcon.right = rcIcon.left + iIconX;

rcIcon.top += (rc.bottom - rc.top - iIconY) / 2;

rcIcon.bottom = rcIcon.top + iIconY;

pDC-

FillSolidRect(rcIcon.left, rcIcon.top,

rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, lpItem-

crColor);

pDC-

DrawEdge(&rcIcon, BDR_RAISEDINNER, BF_RECT);

//开始画文字

int nOldBkMode = pDC-

SetBkMode(TRANSPARENT);

pDC-

SetTextColor(RGB(0, 0, 0));

rcTxt.left = rcIcon.right + 5;

rcTxt.top = rcIcon.top;

CFont* font = CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT));

pDC-

SelectObject(font);

pDC-

DrawText(lpItem-

lpCaption, &rcTxt,

DT_VCENTER DT_END_ELLIPSIS DT_NOCLIP DT_SINGLELINE);

pDC-

SetBkMode(nOldBkMode);

}

pDC-

DeleteDC();

}

}

void CBSColorComboBox::OnSelendok()

{

int iIndex = this-

GetCurSel();

LPBSCBITEM lpTmpItem = GetItem(iIndex);

if(lpTmpItem != NULL)

{

if(lpTmpItem-

lpCaption == "More Colors")

{

CColorDialog crDlg(RGB(255, 0, 0), CC_FULLOPEN);

int iRet = crDlg.DoModal();

if(iRet == IDOK)

{

m_crColor = crDlg.GetColor();

LPBSCBITEM lpItem = m_crItem.GetTail();

ASSERT(lpItem);

lpItem-

crColor = m_crColor;

Invalidate();

}

}

}

}

四、小结

上面的代码也适用于菜单等大多数控件的自画过程,其实本书在前面一些实例中也已经讲述了控件自画的内容,读者朋友们可以结合起来一起学习,相信一定能够把控件的自画这一内容把握的一清二楚的。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有