【问题标题】:Resetting a bunch of radio buttons重置一堆单选按钮
【发布时间】:2019-09-12 04:25:13
【问题描述】:
我有一个包含 500 多个单选按钮的对话框。我想创建一个按钮供用户单击以重置所有单选按钮,以防他/她犯了太多错误。
我试过单独做。
void DefectConfigurator::OnBnClickedButton2()
{
CButton* pBtn1 = (CButton*) GetDlgItem(IDC_AAAA);
pBtn1->SetCheck(0);
CButton* pBtn2 = (CButton*) GetDlgItem(IDC_BBBB);
pBtn2->SetCheck(0);
CButton* pBtn3 = (CButton*) GetDlgtem(IDC_CCCC);
pBtn3->SetCheck(0);
.
.
.
这种方法可行,但我想知道是否有更简单的方法?任何帮助,将不胜感激。谢谢!
【问题讨论】:
标签:
visual-c++
mfc
dialog
radio-button
【解决方案1】:
IDC_ 控件 ID 只是 resource.h 文件中的数字。所以确保IDC_AAAA、IDC_BBBB ...IDC_ZZZZ等是连续的,没有中断。然后在 for 循环中迭代:
for (UINT nID = IDC_AAAA; nID <= IDC_ZZZZ; ++nID)
{
CButton* pBtn = static_cast<CButton *>(GetDlgItem(nID));
pBtn->SetCheck(BST_UNCHECKED);
}
如果您要谨慎,可以将static_cast 替换为dynamic_cast 以进行运行时类型检查,然后检查空指针。
【解决方案2】:
MFC 中推荐的在控件和变量之间交换数据的方法是DDX。这使用默认情况下由 MFC 向导创建的 DoDataExchange 函数(在大多数情况下)。通过调用UpdateData 函数,数据在 UI 和变量之间双向交换。
一般的想法是在你的对话框类中有一个变量来保存单选组的当前状态(没有选中或选中的按钮的索引)。这是由DDX_Radio 函数完成的。 article 中有一个简单的例子。
回到你的问题:
如果您有 500 个单选按钮,它们可能被分成不同的组。组中的第一个单选按钮具有 WS_GROUP 样式,并且同一组中的所有后续单选按钮不得具有 WS_GROUP 样式。
有关 MFC 单选按钮和 DDX 的更多信息here。
实施:
-
在对话框标题中声明一个CMap,它将保存单选按钮的状态。它在对话框控件 ID 和状态之间进行映射。
CMap <UINT, UINT, int, int> m_Radios;
-
这里是 DDX 函数:
void CMFC1Dlg::DDX_CustomRadios(CDataExchange* pDX)
{
// 1. enumerate all radio groups.
// 2. call to a DDX_Radio implementation
CWnd * wnd = pDX->m_pDlgWnd->GetWindow(GW_CHILD);
while (wnd)
{
// verify if this is radio button with WS_GROUP style.
if (wnd->GetStyle() & WS_GROUP &&
wnd->SendMessage(WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
{
#define CLEAR_STATE -1
int radioState = CLEAR_STATE;
int radioId = wnd->GetDlgCtrlID();
if(!pDX->m_bSaveAndValidate)
if (!m_Radios.Lookup(radioId, radioState))
m_Radios[radioId] = radioState;
DDX_Radio(pDX, radioId, radioState);
m_Radios[radioId] = radioState;
}
wnd = wnd->GetNextWindow();
}
-
添加对 DoDataExchange 的调用:
void CMFC1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_CustomRadios(pDX);
}
用法:
清除所有单选按钮:
void CMFC1Dlg::OnBnClearAll()
{
m_Radios.RemoveAll();
UpdateData(FALSE); // this updates the ui
}
将所有按钮状态从 UI 保存到变量中:
void CMFC1Dlg::OnBnSaveAll()
{
UpdateData(TRUE);
POSITION pos = m_Radios.GetStartPosition();
while (pos != NULL)
{
UINT nId = 0;
BOOL state = 0;
m_Radios.GetNextAssoc(pos, nId, state);
TRACE("Control: %d State: %d\r\n", nId, state);
}
}
【解决方案3】:
我宁愿使用CheckRadioButton() Win32 函数:
CheckRadioButton(m_hWnd, IDC_AAAA, IDC_AAAA + 500 - 1, -1);
尚未测试,但请检查以下两点:
- 文档没有具体提及,但
nIDLastButton 参数似乎包含在内,所以我使用了IDC_AAAA + 500 - 1。
- 我将
nIDCheckButton 设置为-1,这应该不会导致选中单选按钮。
您可以选择使用 DDX/DDV,DDX_Radio() 函数会为您完成所有工作(写入和读取数据)。在调用UpdateData(FALSE) 之前将变量设置为-1。请记住,这是无线电组的索引,而不是控制标识符。
顺便说一句,有 500 个单选按钮的 UI 真的很混乱吗?考虑改用下拉列表。或者你的意思是复选框而不是单选按钮?使用单选按钮的“缺陷配置”将只允许选择一个“缺陷”。