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

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

1、按钮的外观类似静态控件类CStatic 产生的对象。(参见图一)


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

图一

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


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

图二

3、当按钮按下的情形:(参见图三)


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

图三

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

在VC6的IDE环境中,生成一个基于对话框的PROJECT。 将对话框资源中按钮的属性页打开,在“Style”标签页中选取按钮的“Owner Draw”(自绘)属性。 将光标引入到应用程序的资源中。 利用CLASSWIZARD,用CButton为基类,派生一个新类:CLinkButton。 在派生类中重载基类CButton的虚函数:
1. virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

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

定制以下的消息处理:
1. afx_msg void OnMouseMove(UINT nFlags, CPoint point);
2. afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
3. afx_msg void OnTimer(UINT nIDEvent);
4. afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
5. afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
6. afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
7. afx_msg BOOL OnEraseBkgnd(CDC* pDC);
声明类成员变量定义:
1. //定义字体变量
2. CFont fUnderline;
3. //定义光标变量
4. HCURSOR hHand;
5. //决定按钮是否按下
6. bool bLBtnDown;
7. //决定鼠标是否在按钮上
8. bool bHighlight;

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

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

01. void CLinkButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
02. {
03.     // 获取一个CDC指针
04.     CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
05.     //定义按钮区域并初始化
06.     CRect rect(lpDrawItemStruct->rcItem);
07.     //设置背景模式
08.     COLORREF oc = pDC->GetTextColor();
09.     int iObk = pDC->SetBkMode(TRANSPARENT);
10.     //初始化按钮状态
11.     UINT state = lpDrawItemStruct->itemState;
12.     CFont * pOldFont = NULL;
13.     int iYOffset = 0, iXOffset = 0;
14.     CString strText;
15.     GetWindowText(strText);
16.     rect.top  += iYOffset;
17.     rect.left += iXOffset;
18.   
19.     if (state & ODS_DISABLED)
20.     {       
21.         //按钮置灰(DISABLED)
22.         CBrush grayBrush;
23.         grayBrush.CreateSolidBrush (GetSysColor (COLOR_GRAYTEXT));
24.         CSize sz = pDC->GetTextExtent(strText);
25.         int x = rect.left + (rect.Width() - sz.cx)/2;
26.         int y = rect.top + (rect.Height() - sz.cy)/2;
27.         rect.top  += 2;
28.         rect.left += 2;
29.         pDC->SetTextColor(GetSysColor(COLOR_3DHIGHLIGHT));
30.         pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
31.         rect.top  -= 2;
32.         rect.left -= 2;
33.         pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
34.         pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
35.     }
36.     else
37.     {
38.         if (bHighlight)//光标在按钮上
39.         {
40.             if (state & ODS_SELECTED)
41.                 //按下按钮
42.                 pDC->Draw3dRect(rect,GetSysColor(COLOR_3DSHADOW), GetSysColor(COLOR_3DHILIGHT));
43.             else
44.                 //未按下按钮
45.                 pDC->Draw3dRect(rect,GetSysColor(COLOR_3DHILIGHT),GetSysColor(COLOR_3DSHADOW));
46.                   
47.             //字体颜色
48.             pDC->SetTextColor(RGB(0,0,255));
49.   
50.             //加下画线(也可以用其他字体)
51.             if (fUnderline.GetSafeHandle() == NULL)
52.             {
53.                 CFont * pFont = GetFont();
54.                 ASSERT(pFont);
55.                 LOGFONT lf;
56.                 pFont->GetLogFont(&lf);
57.                 lf.lfUnderline = TRUE;
58.                 fUnderline.CreateFontIndirect(&lf);     
59.             }
60.             pOldFont = pDC->SelectObject(&fUnderline);
61.         }
62.         else pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));
63.   
64.         pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
65.           
66.         if (pOldFont) pDC->SelectObject(pOldFont);
67.     }
68. }

2、定制的消息处理函数

1. void CLinkButton::OnMouseMove(UINT nFlags, CPoint point) 
2. {
3.     //设置一个定时器
4.     SetTimer(1,10,NULL);
5.       
6.     CButton::OnMouseMove(nFlags, point);
7. }

当鼠标光标移到按钮上时,执行此函数,定时器将发送一个 WM_TIMER消息到消息队列。由OnTimer(UINT nIDEvent)函数处理这个消息。

01. void CLinkButton::OnTimer(UINT nIDEvent) 
02. {
03.     static bool pPainted = false;
04.     POINT pt;
05.     GetCursorPos(&pt);
06.     CRect rect;
07.     GetWindowRect (rect);
08.     if (bLBtnDown)  
09.     {       
10.         KillTimer (1);
11.         if (pPainted) InvalidateRect (NULL);        
12.         pPainted = FALSE;       
13.         return
14.     }
15.   
16.     if (!rect.PtInRect (pt))    
17.     {       
18.         bHighlight = false;
19.         KillTimer (1);
20.   
21.         if (pPainted)           
22.             InvalidateRect(NULL);
23.   
24.         pPainted = false;
25.         return
26.     }
27.     else
28.     {
29.         bHighlight = true;
30.         if (!pPainted)
31.         {
32.             pPainted = true;
33.             InvalidateRect(NULL);
34.         }
35.     }
36.   
37.     CButton::OnTimer(nIDEvent);
38. }
39.   
40.   
41. BOOL CLinkButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
42. {
43.     if (bHighlight) 
44.     {
45.         ::SetCursor(hHand);
46.         return true;
47.     }
48.       
49.     return CButton::OnSetCursor(pWnd, nHitTest, message);
50. }
51.   
52.   
53. int CLinkButton::OnCreate(LPCREATESTRUCT lpCreateStruct) 
54. {
55.     if (CButton::OnCreate(lpCreateStruct) == -1)
56.         return -1;
57.       
58.     CFont * pFont = GetFont();
59.     ASSERT(pFont);
60.   
61.     LOGFONT lf;
62.     pFont->GetLogFont(&lf);
63.     lf.lfUnderline = TRUE;
64.   
65.     fUnderline.CreateFontIndirect(&lf);
66.       
67.     return 0;
68. }

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

01. void CLinkButton::OnLButtonUp(UINT nFlags, CPoint point) 
02. {
03.     bLBtnDown = false;
04.     if (bHighlight) 
05.     {
06.         bHighlight = false;
07.         InvalidateRect(NULL);
08.     }
09.       
10.     CButton::OnLButtonUp(nFlags, point);
11. }

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

1. void CLinkButton::OnLButtonDown(UINT nFlags, CPoint point) 
2. {
3.     bLBtnDown = true;
4.       
5.     CButton::OnLButtonDown(nFlags, point);
6. }

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

01. BOOL CLinkButton::OnEraseBkgnd(CDC* pDC) 
02. {
03.     COLORREF cr = GetSysColor(COLOR_3DFACE);
04.     int r = GetRValue(cr);
05.     int g = GetGValue(cr);
06.     int b = GetBValue(cr);
07.     if (r > 1) r -= 2;
08.     if (g > 1) g -= 2;
09.     if (r < 3 && g < 3 && b < 253) b += 2;
10.     COLORREF cr1 = RGB(r,g,b);
11.     CRect rc;
12.     GetClientRect(rc);
13.     pDC->FillSolidRect(rc, cr1);
14.       
15.     return CButton::OnEraseBkgnd(pDC);
16. }

当按钮的背景需要重画时,应用程序框架调用此函数。

其他实现细节请下载源代码。运行程序的效果图见图一、图二和图三。

 

 

from:http://www.vckbase.com/index.php/wv/8

你可能感兴趣的:(button)