重绘单选框控件

单选框的本质也是按钮,但是,基于单选框的显示逻辑,它的界面绘制比复选框要复杂。

单选框有:BS_RADIOBUTTTON、BS_AUTORADIOBUTTON两种显示风格。具有BS_AUTORADIOBUTTON风格的单选框,只要选中一个子项,同组的其它子项就会自动变成非选中状态。本文主要讨论后者的绘制。

绘制难点:
确定同组中的所有子项

解决方法:

以WS_GROUP标识为界,遍历所有窗口,我们可以筛选出同组的子窗口集合。

这样做逻辑上合理,但是,如果在一组单选框中,存在复选框时;则复选框也会被误当成子项。要解决这个问题,我们可以把同组中的子项都加上标识;这样,即使存在复选框,也不会对子窗口集合产生干扰。

我测试了下,子项标识任意选取,都能实现我们需要的效果。但是,为了与标准控件保持一致,我们用Spy++查看标准单选框,发现如下信息:



据MSDN说明,WM_GETDLGCODE消息发送给窗口控件后,控件返回自身想要处理的输入类型。从消息返回值中,我们发现刚好有DLGC_RADIOBUTTON(单选框)。于是,我们选取DLGC_RADIOBUTTON作为子项标识。

主要源码如下:

LRESULT CRadioBoxEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
// TODO: Add your specialized code here and/or call the base class
if (message == BM_GETCHECK)
{
return m_nCheck ;
}
else if (message == BM_SETCHECK)
{
// 保存状态
m_nCheck = int(wParam) ;

// 强制重绘
Invalidate() ;

// 设置同组中其他单选框的状态
if (((m_dwStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON) && (wParam == 1))
{
HWND hWndCtrl = NULL;

// 向前遍历,设置状态
hWndCtrl = GetSafeHwnd() ;
while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP))
{
hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDPREV);

// 如控件输入类型匹配,则处理
if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON)
{
::SendMessage(hWndCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
}
}

// 向后遍历,设置状态
hWndCtrl = ::GetWindow(GetSafeHwnd(), GW_HWNDNEXT) ;
while(hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)) 
{
// 如控件输入类型匹配,则处理
if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON)
{
::SendMessage(hWndCtrl, BM_SETCHECK, BST_UNCHECKED, 0);
}

hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);

}

return 0;
}
else if (message == WM_GETDLGCODE)
{
// 返回自身想要处理的输入类型
  if ((m_dwStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON)
  {
  return DLGC_RADIOBUTTON;
  }
}

return CButton::WindowProc(message, wParam, lParam);
}

void CRadioBoxEx::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

if (!m_bLBtnDown)
{
m_bLBtnDown = TRUE ;
}

CButton::OnLButtonDown(nFlags, point);
}

void CRadioBoxEx::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default

if (m_bLBtnDown)
{
m_bLBtnDown = FALSE ;

CRect rcClient ;
GetClientRect(rcClient) ;

if (rcClient.PtInRect(point))
{
// 设置当前单选框的状态
if ((m_dwStyle & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON)
{
SetCheck(1) ;
}
}
}

CButton::OnLButtonUp(nFlags, point);
}

效果图如下:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值