DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

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


图一

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


图二

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


图三

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

在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

posted on 2012-12-17 00:27  DoubleLi  阅读(1545)  评论(0编辑  收藏  举报