自制扩展button(转)

  • 在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值