重绘静态控件

MFC提供的静态控件,仅满足文本显示的简单需求。如果要实现“类似于超链接”的功能,我们需要在原有控件的基础上进行扩展。具体实现步骤如下:

1. 从CStatic类派生一个子类CStaticEx

2. 重载虚函数PreSubclassWindow,添加控件风格SS_NOTIFY

说明:静态控件需要设置SS_NOTIFY风格,才能响应鼠标事件。
void CStaticEx::PreSubclassWindow() 
{
// TODO: Add your specialized code here and/or call the base class

// 在缺省情况下,静态控件是不响应鼠标事件的
DWORD dwStyle = GetStyle();
if (!(dwStyle & SS_NOTIFY)) 
{
::SetWindowLong(m_hWnd, GWL_STYLE, dwStyle | SS_NOTIFY);
}


CStatic::PreSubclassWindow();
}


3. 添加消息ON_WM_MOUSEMOVE,WM_MOUSEHOVER,WM_MOUSELEAVE

说明:1. 函数TrackMouseEvent,用于侦测鼠标位置,并寄送盘旋(WM_MOUSEHOVER)或离开(WM_MOUSELEAVE)消息。
          2. 盘旋(WM_MOUSEHOVER)和离开(WM_MOUSELEAVE)消息,需要手动添加。
void CStaticEx::OnMouseMove(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
if (!m_bIsTracking)
{
TRACKMOUSEEVENT tme;   
tme.cbSize = sizeof(tme);   
tme.hwndTrack = GetSafeHwnd();   
tme.dwFlags = TME_HOVER|TME_LEAVE;   
tme.dwHoverTime = 10;  
m_bIsTracking = _TrackMouseEvent(&tme);   
}

CStatic::OnMouseMove(nFlags, point);
}


LRESULT CStaticEx::OnMouseHover(WPARAM wParam, LPARAM lParam) 
{
if (m_nMouseState != MOUSE_HOVER)
{
m_nMouseState = MOUSE_HOVER ;
m_bUnderLine  = TRUE;
Invalidate();
}

return 0 ;
}


LRESULT CStaticEx::OnMouseLeave(WPARAM wParam, LPARAM lParam) 
{
if (m_nMouseState != MOUSE_LEAVE)
{
m_nMouseState = MOUSE_LEAVE ;
m_bUnderLine  = FALSE;
Invalidate() ;
}

m_bIsTracking = FALSE ;
return 0 ;
}


4. 添加反射消息ON_WM_CTLCOLOR_REFLECT,在响应函数里,设置画图模式、画刷类型、文本字体、文本颜色

HBRUSH CStaticEx::CtlColor(CDC* pDC, UINT nCtlColor) 
{
DWORD dwStyle = GetStyle();
HBRUSH hbr = NULL;

// TODO: Change any attributes of the DC here
if ((GetStyle() & 0xFF) <= SS_RIGHT)
{
// 设置画图模式
pDC->SetBkMode(TRANSPARENT);


// 设置画刷类型
hbr = (HBRUSH)::GetStockObject(HOLLOW_BRUSH);


// 选择文本字体
if (m_cTextFont.GetSafeHandle() != NULL)
{
m_cTextFont.Detach();
}

if (m_bUnderLine)
{
m_cTextFont.Attach(m_hHoverFont);
}
else
{
m_cTextFont.Attach(m_hLeaveFont);
}

pDC->SelectObject(&m_cTextFont);

// 设置文本颜色
if (m_nMouseState == MOUSE_HOVER)
{
pDC->SetTextColor(m_clrHoverColor);
}
else
{
pDC->SetTextColor(m_clrLeaveColor);
}
}

// TODO: Return a different brush if the default is not desired
return hbr;
}


5. 添加消息ON_WM_ERASEBKGND,在响应函数里,绘制控件背景

说明:控件背景可能是纯色,也可能非纯色。纯色好处理,简单填充即可;如果是非纯色(比如渐变或贴图),则需要把父窗口的背景抠出,在子窗口重绘一次。
当然,最好的方法是利用父窗口DC,在子窗口辅助绘制(这是珽震的高招)。
BOOL CStaticEx::OnEraseBkgnd(CDC* pDC) 
{
// TODO: Add your message handler code here and/or call default
CRect rcClient;
GetClientRect(&rcClient);

CDC dcMem;
dcMem.CreateCompatibleDC(pDC);

CBitmap cNewBmp;
cNewBmp.CreateCompatibleBitmap(pDC, rcClient.Width(), rcClient.Height());

CBitmap*pOldBmp = NULL;
pOldBmp = dcMem.SelectObject(&cNewBmp);


CWnd* parent = GetParent() ;
if (parent != NULL && m_parent_dc != NULL)
{
CRect bound_in_parent ;
GetWindowRect(&bound_in_parent) ;

parent->ScreenToClient(&bound_in_parent) ;
dcMem.BitBlt(
0, 0,
rcClient.Width(), rcClient.Height(),
m_parent_dc,
bound_in_parent.left, bound_in_parent.top,
SRCCOPY
) ;
}
else
{
dcMem.FillSolidRect(0, 0, rcClient.Width(), rcClient.Height(), m_clrBkColor);
}


pDC->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcMem, 0, 0, SRCCOPY);


// 选择旧设备
dcMem.SelectObject(pOldBmp);


// 释放资源
if (dcMem.GetSafeHdc() != NULL)
{
dcMem.DeleteDC();
}

if (cNewBmp.GetSafeHandle() != NULL)
{
cNewBmp.DeleteObject();
}

return TRUE;
// return CStatic::OnEraseBkgnd(pDC);
}

6. 添加消息ON_WM_SETCURSOR,设置鼠标在控件范围内的光标(通常为手型光标)

BOOL CStaticEx::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
::SetCursor(m_hLinkCursor);
return TRUE;
}


7. 添加消息ON_WM_LBUTTONDOWN,设置点击后的动作

说明:m_lpClickCb是一个回调函数指针,由调用者传入。
void CStaticEx::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

if (m_lpClickCb != NULL)
{
m_lpClickCb();
}

CStatic::OnLButtonDown(nFlags, point);
}

至此,一个“类似于超链接”的静态控件已完成。效果图如下:



具体代码可以参考:http://download.csdn.net/detail/zwz1984/4853457

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值