'How to limit the number of QCheckboxes checked at the same time?

I'm in the process of creating a QT application which is using multiple (14) qcheckboxes. I need to have a limit (preferably set as a variable that i can change) to the number of checkboxes that can be checked at the same time, is there any way to achieve this cleanly ? Thanks for your time.



Solution 1:[1]

There is no simple way of doing this, you have to write your code to do it. I suppose you have the checkboxes in some parent widget class. So I would create a slot which looks like this.

void SomeParentWidget::onCheckBoxToggled(bool value)
{
    // when we unchecked the checkbox, 
    // we do not need to count the number of checked ones
    if (!value)
        return;

    int total = 0;
    int limit = 15; // your "magic" number of maximum checked checkboxes

    for (auto chb : allCheckBoxes()) // allCheckBoxes() is some method which returns all the checkboxes in consideration
    {
        if (chb->isChecked())
        {
            ++total;
            if (total > limit)
            {
                // too many checkboxes checked! uncheck the sender checkbox
                // Note: you may want to add some nullptr checks or asserts to the following line for better robustness of your code.
                qobject_cast<QCheckBox*>(sender())->setChecked(false);
                return;
            }
        }
    }
}

And when creating each of your checkboxes inside some parent widget, connect this slot to their signal:

auto chb = new QCheckBox();
connect(chb, &QCheckBox::toggled, this, &SomeParentWidget::onCheckBoxToggled);

Implementation of allCheckBoxes() is up to you, I do not know how you can retrieve the collection of all your check boxes. Depends on your design.

Solution 2:[2]

I found another, even simpler solution. Use this slot.

void SomeParentWidget::onCheckBoxToggled(bool value)
{
    static int totalChecked = 0; // static! the value is remembered for next invocation
    totalChecked += value ? 1 : -1;
    Q_ASSERT(totalChecked >= 0);
    int maxChecked = 15; // any number you like
    if (value && totalChecked > maxChecked)
    {
        qobject_cast<QCheckBox*>(sender())->setChecked(false);
    }
}

... and connect it to checkboxes' toggled() signal. Note that in order to work correctly, all check boxes must be unchecked at the time when you make the signal-slot connection because this function starts counting from zero (0 is the initial value of the static variable).

Solution 3:[3]

You can store all your checkboxes in a map (either in an std::map, an std::unordered_map or an QMap). Your keys will be your checkboxes, and your values will be their states, so something like this:

std::unordered_map<QCheckBox*, bool> m_checkBoxStates;

Here's what your connected to your toggled signal of all your checkboxes look like (keep in mind that all the signals will be connected to the same slot):

void MainWindow::onToggled(bool checked) {
    QCheckBox* checkBox = sender(); //the checkbox that has been toggled

    m_checkBoxStates[checkBox] = checked;
    if (!checked) {
        return;
    }

    const int count = std::count_if(m_checkBoxStates.begin(), m_checkBoxStates.end(), 
        [](const auto pair) {
            return pair.second == true;
    });

    if (count > maxCount) {
        checkBox->setChecked(false);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3