首页 | 社区 | 博客 | 招聘 | 文章 | 新闻 | 下载 | 读书 | 代码
亲,您未登录哦! 登录 | 注册

制作风格独特的按钮—用VC6扩展CButton类

打印文章

分享到:
一、 本文介绍一个CButton的派生类CLinkButton,用此派生类制作的按钮具有以下特点:


1、按钮的外观类似静态控件类CStatic 产生的对象。

2、当鼠标的光标移到按钮上,但并未按下时,光标改变形状,字体改变形状;按钮类似应用在工具条和菜单上的扁平钮效果

二、下面具体描述这种按钮的实现方法和步骤:


1. 在VC6的IDE环境中,生成一个基于对话框的PROJECT。


2. 将对话框资源中按钮的属性页打开,在“Style”标签页中选取按钮的“Owner Draw”(自绘)属性。


3. 将光标引入到应用程序的资源中。


4. 利用CLASSWIZARD,用CButton为基类,派生一个新类:CLinkButton。


5. 在派生类中重载基类CButton的虚函数:


virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)


之所以要重载这个函数是因为选择了按钮的 “Owner Draw”属性后,当按钮的可视行为发生变化时,应用程序的框架要调用这个函数来重新绘制按钮。


6. 定制以下的消息处理:


afx_msg void OnMouseMove(UINT nFlags, CPoint point);


afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);


afx_msg void OnTimer(UINT nIDEvent);


afx_msg void OnLButtonUp(UINT nFlags, CPoint point);


afx_msg void OnLButtonDown(UINT nFlags, CPoint point);


afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);


afx_msg BOOL OnEraseBkgnd(CDC* pDC);


7. 声明类成员变量定义:


//定义字体变量


CFont fUnderline;


//定义光标变量


HCURSOR hHand;


//决定按钮是否按下


bool bLBtnDown;


//决定鼠标是否在按钮上


bool bHighlight;


二、 派生类CLinkButton 的具体实现:


1.重载函数  DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)。


void CLinkButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)


{


// 获取一个CDC指针


CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);


//定义按钮区域并初始化


CRect rect(lpDrawItemStruct->rcItem);


//设置背景模式


COLORREF oc = pDC->GetTextColor();


int iObk = pDC->SetBkMode(TRANSPARENT);


//初始化按钮状态


UINT state = lpDrawItemStruct->itemState;


CFont * pOldFont = NULL;


int iYOffset = 0, iXOffset = 0;


CString strText;


GetWindowText(strText);


rect.top += iYOffset;


rect.left += iXOffset;


if (state & ODS_DISABLED)


{


//按钮置灰状态(DISABLED)


CBrush grayBrush;


grayBrush.CreateSolidBrush (GetSysColor (COLOR_GRAYTEXT));


CSize sz = pDC->GetTextExtent(strText);


int x = rect.left + (rect.Width() - sz.cx)/2;


int y = rect.top + (rect.Height() - sz.cy)/2;


rect.top += 2;


rect.left += 2;


pDC->SetTextColor(GetSysColor(COLOR_3DHIGHLIGHT));


pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);


rect.top -= 2;


rect.left -= 2;


pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));


pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);


}


else


{


if (bHighlight)//光标在按钮上


{


if (state & ODS_SELECTED)


{


//按下按钮


pDC->Draw3dRect(rect,GetSysColor(COLOR_3DSHADOW),


                GetSysColor(COLOR_3DHILIGHT));


}


else


{//未按下按钮


           pDC->Draw3dRect(rect,GetSysColor(COLOR_3DHILIGHT),


                GetSysColor(COLOR_3DSHADOW));


}


//字体颜色


pDC->SetTextColor(RGB(0,0,255));




//加下画线(也可以用其他字体)


if (fUnderline.GetSafeHandle() == NULL)


{


CFont * pFont = GetFont();


ASSERT(pFont);


LOGFONT lf;


pFont->GetLogFont(&lf);


lf.lfUnderline = TRUE;


fUnderline.CreateFontIndirect(&lf);


}


pOldFont = pDC->SelectObject(&fUnderline);


}


else pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));


pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);


if (pOldFont) pDC->SelectObject(pOldFont);


}


}


2.定制的消息处理函数


void OnMouseMove(UINT nFlags, CPoint point)


{


//设置一个定时器


SetTimer(1,10,NULL);


//


...


}


当鼠标光标移到按钮上时,执行此函数,定时器将发送一个 WM_TIMER消息到消息队列。


由OnTimer(UINT nIDEvent)函数处理这个消息。


void OnTimer(UINT nIDEvent)


{


//处理WM_TIMER消息


static bool pPainted = false;


POINT pt;


GetCursorPos(&pt);


CRect rect;


GetWindowRect (rect);


if (bLBtnDown)


{


KillTimer (1);


if (pPainted) InvalidateRect (NULL);


pPainted = FALSE;


return;


}


if (!rect.PtInRect (pt))


{


bHighlight = false;


KillTimer (1);


if (pPainted)


InvalidateRect(NULL);


pPainted = false;


return;


}


else


{


bHighlight = true;


if (!pPainted)


{


pPainted = true;


InvalidateRect(NULL);


}


}


//


CButton::OnTimer(nIDEvent);


}


BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)


{


//当鼠标光标移到按钮上时,改变光标的形象


if (bHighlight)


{


::SetCursor(hHand);


return true;


}


//


...


}


int OnCreate(LPCREATESTRUCT lpCreateStruct)


{


...


CFont * pFont = GetFont();


ASSERT(pFont);


LOGFONT lf;


pFont->GetLogFont(&lf);


lf.lfUnderline = TRUE;


fUnderline.CreateFontIndirect(&lf);


...


}


这个函数由框架在显示出按钮之前自动调用,我在这里初始化在按钮上显示的字体。


void OnLButtonUp(UINT nFlags, CPoint point)


{


bLBtnDown = false;


if (bHighlight)


{


bHighlight = false;


InvalidateRect(NULL);


}


...


}


当按下按钮又放开时调用这个函数。


void OnLButtonDown(UINT nFlags, CPoint point)


{


bLBtnDown = true;


...


}


当按下按钮时调用这个函数。


BOOL OnEraseBkgnd(CDC* pDC)


{


COLORREF cr = GetSysColor(COLOR_3DFACE);


int r = GetRValue(cr);


int g = GetGValue(cr);


int b = GetBValue(cr);


if (r > 1) r -= 2;


if (g > 1) g -= 2;


if (r <3 && g < 3 && b < 253) b +=2;


COLORREF cr1 = RGB(r,g,b);


CRect rc;


GetClientRect(rc);


pDC->FillSolidRect(rc, cr1);


...


}


当按钮的背景需要重画时,应用程序框架调用此函数。编译并运行PROJECT LinkBtn

本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )

编程爱好者论坛

本栏最新文章