重置一堆单选按钮

Resetting a bunch of radio buttons

我有一个包含 500 多个单选按钮的对话框。我想创建一个按钮供用户单击以重置所有单选按钮,以防 he/she 犯了太多错误。

我试过单独做。

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);
            .
            .
            .

这个方法可行,但我想知道是否有更简单的方法?任何帮助,将不胜感激。谢谢!

IDC_ 控件 ID 只是 resource.h 文件中的数字。因此,请确保 IDC_AAAAIDC_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 以进行运行时类型检查,然后检查空指针。

在 MFC 中用于在控件和变量之间交换数据的推荐方法是 DDX. This uses DoDataExchange function which is created by MFC Wizard by default (in most cases). The data is exchanged between the UI and the variables both ways by a call to UpdateData 函数。

一般的想法是在您的对话框中有一个变量 class 来保存单选组的当前状态(未选中或选中的按钮的索引)。这是由 DDX_Radio function. You have a simple example in this article.

完成的

回到你的问题:

如果您有 500 个单选按钮,它们可能被分成不同的组。该组中的第一个单选按钮具有 WS_GROUP 样式,同一组中的所有后续单选按钮不得具有 WS_GROUP 样式。 有关 MFC 单选按钮和 DDX 的更多信息 here

实施:

  1. 在对话框 header 中声明一个 CMap 来保存单选按钮的状态。它在对话框控件 ID 和状态之间映射。

    CMap <UINT, UINT, int, int> m_Radios;
    
  2. 这里是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();
        }   
    
  3. 添加对 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);
        }
    }

我宁愿使用 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 是不是真的非常混乱?考虑改用下拉列表。或者你的意思是复选框而不是单选按钮? "Defect-Configuration" 使用单选按钮将只允许选择一个 "defect"。