- 在VC6的IDE环境中,生成一个基于对话框的PROJECT。
- 将对话框资源中按钮的属性页打开,在“Style”标签页中选取按钮的“Owner Draw”(自绘)属性。
- 将光标引入到应用程序的资源中。
- 利用CLASSWIZARD,用CButton为基类,派生一个新类:CLinkButton。
- 在派生类中重载基类CButton的虚函数:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
之所以要重载这个函数是因为选择了按钮的 “Owner Draw”属性后,当按钮的可视行为发生变化时,应用程序的框架要调用这个函数来重新绘制按钮。 - 定制以下的消息处理:
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);
- 声明类成员变量定义:
//定义字体变量 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 CLinkButton::OnMouseMove(UINT nFlags, CPoint point) { //设置一个定时器 SetTimer(1,10,NULL); CButton::OnMouseMove(nFlags, point); }
当鼠标光标移到按钮上时,执行此函数,定时器将发送一个 WM_TIMER消息到消息队列。由OnTimer(UINT nIDEvent)函数处理这个消息。
void CLinkButton::OnTimer(UINT nIDEvent) { 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 CLinkButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if (bHighlight) { ::SetCursor(hHand); return true; } return CButton::OnSetCursor(pWnd, nHitTest, message); } int CLinkButton::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CButton::OnCreate(lpCreateStruct) == -1) return -1; CFont * pFont = GetFont(); ASSERT(pFont); LOGFONT lf; pFont->GetLogFont(&lf); lf.lfUnderline = TRUE; fUnderline.CreateFontIndirect(&lf); return 0; }
这个函数由框架在显示出按钮之前自动调用,我在这里初始化按钮上显示的字体。
void CLinkButton::OnLButtonUp(UINT nFlags, CPoint point) { bLBtnDown = false; if (bHighlight) { bHighlight = false; InvalidateRect(NULL); } CButton::OnLButtonUp(nFlags, point); }
当按下按钮又放开时调用这个函数。
void CLinkButton::OnLButtonDown(UINT nFlags, CPoint point) { bLBtnDown = true; CButton::OnLButtonDown(nFlags, point); }
当按下按钮时调用这个函数。
BOOL CLinkButton::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); return CButton::OnEraseBkgnd(pDC); }
当按钮的背景需要重画时,应用程序框架调用此函数。
原文链接http://www.vckbase.com/document/viewdoc/?id=559