m170115
m170115

Reputation: 121

Resetting a bunch of radio buttons

I have a dialog box with over 500 radio buttons. I want to create a button for users to click to reset all the radio buttons in case he/she made too many mistakes.

I have tried doing them individually.

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

This way works, but I was wondering if there is a simpler way? Any help would be appreciated. Thank you!

Upvotes: 1

Views: 863

Answers (3)

Constantine Georgiou
Constantine Georgiou

Reputation: 3401

I would rather use the CheckRadioButton() Win32 function:

CheckRadioButton(m_hWnd, IDC_AAAA, IDC_AAAA + 500 - 1, -1);

Haven't tested it but pls check these two points:

  • The documentation dosn't specifically mention it, but the nIDLastButton argument seem to be inclusive, so I used IDC_AAAA + 500 - 1.
  • I set nIDCheckButton to -1, this should cause no radio button to be checked.

You could instead elect to use DDX/DDV, the DDX_Radio() function does all the work for you (write AND read data). Set the variable to -1 before calling UpdateData(FALSE). Remember, this is an index into the radio-group, not a control identifier.

As a sidenote, isn't a UI with 500 radio-buttons really VERY cluttered? Consider using a drop-down list instead. Or you mean check-boxes instead of radio buttons? A "Defect-Configuration" using radio-buttons would allow only one "defect" to be selected.

Upvotes: 0

EylM
EylM

Reputation: 6103

The recommended way in MFC for exchanging data between the controls and variables is 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 function.

The general idea is to have a variable in your dialog class that holds the current state of the radio group (nothing checked or index of the button that is checked). This is done by DDX_Radio function. You have a simple example in this article.

Back to your question:

If you have 500 radio buttons, they are probably splited into different groups. The first radio in the group has WS_GROUP style and all following radio buttons in the same group must NOT have WS_GROUP style. More info about MFC radio button and DDX here.

Implementation:

  1. Declare a CMap in your dialog header that will hold the state of the radio buttons. It maps between the dialog control ID and the state.

    CMap <UINT, UINT, int, int> m_Radios;
    
  2. Here is the DDX function:

    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. Add a call to DoDataExchange:

    void CMFC1Dlg::DoDataExchange(CDataExchange* pDX)
    {
        CDialogEx::DoDataExchange(pDX); 
    
        DDX_CustomRadios(pDX);
    }       
    

Usage:

Clear all radio buttons:

    void CMFC1Dlg::OnBnClearAll()
    {
        m_Radios.RemoveAll();

        UpdateData(FALSE); // this updates the ui
    }

Save all buttons state from UI to the variables:

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

Upvotes: 0

acraig5075
acraig5075

Reputation: 10756

The IDC_ control id's are just numbers in the resource.h file. So ensure IDC_AAAA, IDC_BBBB ... IDC_ZZZZ, etc. are sequential with no interruptions. Then just iterate in a for loop:

for (UINT nID = IDC_AAAA; nID <= IDC_ZZZZ; ++nID)
{
   CButton* pBtn = static_cast<CButton *>(GetDlgItem(nID));
   pBtn->SetCheck(BST_UNCHECKED);
}

If you want to be cautious then you could replace static_cast with dynamic_cast to have runtime type checking and then check for null pointer.

Upvotes: 1

Related Questions