CMFCToolbar按钮组实现单选:仅允许一个按钮处于选中状态
实现CMFCToolbar中TBBS_CHECKGROUP按钮的单选效果
我在CDialogEx内的CMFCToolbar中添加了三个按钮,设置了TBBS_CHECKGROUP样式,但目前按钮可各自独立切换选中/未选中状态,需要实现同一时间仅一个按钮处于选中状态的单选效果——点击新按钮时自动取消其他按钮的选中状态。
我的初始化代码如下:
DWORD dwCtrlStyle = TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CBRS_SIZE_DYNAMIC; DWORD dwStyle = AFX_DEFAULT_TOOLBAR_STYLE; if (m_ToolBar.CreateEx(this, dwCtrlStyle, dwStyle, CRect(1, 1, 1, 1), IDR_TOOLBAR1_PNG)) { dwStyle = CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC; m_ToolBar.SetPaneStyle(m_ToolBar.GetPaneStyle() | dwStyle); } CMFCToolBarInfo info; m_ToolBar.SetSizes(CSize(32, 32), CSize(32, 32)); BOOL ret2 = m_ToolBar.LoadBitmap(IDR_TOOLBAR1_PNG); // << 此代码正常工作 CMFCToolBarButton but1(0, 0, L"HELLO", TRUE, 0); CMFCToolBarButton but2(1, 1, L"HELLO", TRUE, 0); CMFCToolBarButton but3(2, 2, L"HELLO", TRUE, 0); but1.SetStyle(but1.m_nStyle | TBBS_CHECKGROUP); but2.SetStyle(but2.m_nStyle | TBBS_CHECKGROUP); but3.SetStyle(but3.m_nStyle | TBBS_CHECKGROUP); m_ToolBar.InsertButton(but1, 0); m_ToolBar.InsertButton(but2, 0); m_ToolBar.InsertButton(but3, 0); m_ToolBar.SetToolBarBtnText(0, _T("By")); m_ToolBar.SetToolBarBtnText(1, _T("Your")); m_ToolBar.SetToolBarBtnText(2, _T("Command")); m_ToolBar.InsertSeparator(2); m_ToolBar.SetWindowPos(0, 0, 0, 400, 36, 0, 0);
更新:
我尝试通过ON_UPDATE_COMMAND_UI_RANGE实现,但只能取消其他按钮的选中状态,无法让当前点击的按钮保持选中:
void CMFCApplication1Dlg::OnUpdateViewFilterData(CCmdUI* pCmdUI) { for (int i = 0; i < 3; ++i) { UINT nID; UINT info; int img; m_ToolBar.GetButtonInfo(i, nID, info,img); int check = 2; if (nID != pCmdUI->m_nID) { UINT newStyle = m_ToolBar.GetButtonStyle(i) & ~(TBBS_CHECKED | TBBS_INDETERMINATE); if (check == 1) newStyle |= TBBS_CHECKED; else if (check == 2) newStyle |= TBBS_INDETERMINATE; m_ToolBar.SetButtonStyle(i, newStyle | TBBS_CHECKBOX); } if (nID == pCmdUI->m_nID) { // 希望点击的按钮保持选中,但pCmdUI->SetCheck(1)无效 } } }
正确实现方案
要实现单选组效果,无需手动遍历修改样式,只需按以下步骤配置:
步骤1:给按钮分配唯一ID
先在Resource.h中定义三个唯一的按钮ID:
#define ID_BTN_BY 1001 #define ID_BTN_YOUR 1002 #define ID_BTN_COMMAND 1003
然后修改按钮初始化代码,用这些ID创建按钮,且仅给组内第一个按钮设置TBBS_CHECKGROUP,后续按钮用TBBS_CHECKBOX即可:
CMFCToolBarButton but1(ID_BTN_BY, 0, _T("By"), TRUE, 0); CMFCToolBarButton but2(ID_BTN_YOUR, 1, _T("Your"), TRUE, 0); CMFCToolBarButton but3(ID_BTN_COMMAND, 2, _T("Command"), TRUE, 0); // 仅第一个按钮设置TBBS_CHECKGROUP,后续按钮自动归入同一组 but1.SetStyle(but1.m_nStyle | TBBS_CHECKGROUP); but2.SetStyle(but2.m_nStyle | TBBS_CHECKBOX); but3.SetStyle(but3.m_nStyle | TBBS_CHECKBOX);
步骤2:添加COMMAND消息处理函数
在对话框类头文件声明处理函数:
afx_msg void OnBtnBy(); afx_msg void OnBtnYour(); afx_msg void OnBtnCommand();
在对话框类的消息映射中添加关联:
ON_COMMAND(ID_BTN_BY, &CMFCApplication1Dlg::OnBtnBy) ON_COMMAND(ID_BTN_YOUR, &CMFCApplication1Dlg::OnBtnYour) ON_COMMAND(ID_BTN_COMMAND, &CMFCApplication1Dlg::OnBtnCommand)
实现处理函数,点击时主动设置当前按钮选中并取消其他按钮:
void CMFCApplication1Dlg::OnBtnBy() { m_ToolBar.SetCheck(ID_BTN_BY, TRUE); m_ToolBar.SetCheck(ID_BTN_YOUR, FALSE); m_ToolBar.SetCheck(ID_BTN_COMMAND, FALSE); } void CMFCApplication1Dlg::OnBtnYour() { m_ToolBar.SetCheck(ID_BTN_YOUR, TRUE); m_ToolBar.SetCheck(ID_BTN_BY, FALSE); m_ToolBar.SetCheck(ID_BTN_COMMAND, FALSE); } void CMFCApplication1Dlg::OnBtnCommand() { m_ToolBar.SetCheck(ID_BTN_COMMAND, TRUE); m_ToolBar.SetCheck(ID_BTN_BY, FALSE); m_ToolBar.SetCheck(ID_BTN_YOUR, FALSE); }
步骤3:添加UPDATE_COMMAND_UI维护状态(可选)
如果需要确保按钮状态始终正确,可添加状态更新处理:
头文件声明:
afx_msg void OnUpdateBtnBy(CCmdUI* pCmdUI); afx_msg void OnUpdateBtnYour(CCmdUI* pCmdUI); afx_msg void OnUpdateBtnCommand(CCmdUI* pCmdUI);
消息映射关联:
ON_UPDATE_COMMAND_UI(ID_BTN_BY, &CMFCApplication1Dlg::OnUpdateBtnBy) ON_UPDATE_COMMAND_UI(ID_BTN_YOUR, &CMFCApplication1Dlg::OnUpdateBtnYour) ON_UPDATE_COMMAND_UI(ID_BTN_COMMAND, &CMFCApplication1Dlg::OnUpdateBtnCommand)
实现更新函数:
void CMFCApplication1Dlg::OnUpdateBtnBy(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_ToolBar.GetCheck(ID_BTN_BY)); } void CMFCApplication1Dlg::OnUpdateBtnYour(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_ToolBar.GetCheck(ID_BTN_YOUR)); } void CMFCApplication1Dlg::OnUpdateBtnCommand(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_ToolBar.GetCheck(ID_BTN_COMMAND)); }
原方案无效原因
你之前用ON_UPDATE_COMMAND_UI_RANGE的问题在于:
- 直接修改按钮样式会与MFC内部状态管理冲突,应使用
SetCheck方法设置选中状态 pCmdUI->SetCheck(1)无效是因为未正确关联按钮ID与状态,且遍历逻辑干扰了MFC的自动更新逻辑
按上述方案修改后,三个按钮将形成单选组,点击其中一个时,另外两个会自动取消选中。
内容的提问来源于stack exchange,提问作者user20716902
相关产品推荐
相关产品推荐

