3

In my Qt5 program I'm working on multiple objects and it's taking a lot of time and code to disable or change state of 20 checkboxes. Is there any option to make a group of checkboxes (or any other objects) and perform commands on it with one line?

For instance:

QCheckBox b1, b2, b3, b4, b5;
QCheckBox_Group Box_1to5 = {b1, b2, b3, b4, b5};
ui->Box_1to5->setEnabled(false);

Is it possible?

Craig Scott
  • 9,238
  • 5
  • 56
  • 85
km2442
  • 779
  • 2
  • 11
  • 31
  • 1
    Depends on what you want to achieve exactly. There's QButtonGroup: http://doc.qt.io/qt-5/qbuttongroup.html, but that's more for exclusive groups where only one button can be checked at a time. If it's about enabling/disabling: if all checkboxes are inside the same parent, you could just enable/disable the parent. Or put the checkboxes into vectors and iterate over them. – Frank Osterfeld Dec 06 '15 at 16:28
  • 1
    @Frank, that should be an answer, not a comment, because you've about covered it. I'd just add that another way is to create a custom group class by wrapping those vectors (or, rather, `QList`s). – Sergei Tachenov Dec 06 '15 at 17:51
  • 1
    Make your own checkbox manager and implement any operationon the over the group of object. If you don't want separate class then just do it in simple loop. – Alexander Tyapkov Dec 06 '15 at 20:09

2 Answers2

2

Frank's comment is what you want for simply enabling/disabling a set of widgets, but I'll answer your more general question of how to apply a change of state to a set of objects. If you are free to use C++11, then the following will give you the general ability to call any member function on any object with a common set of function arguments:

// Member functions without arguments
template<typename ObjectPtrs, typename Func>
void  batchApply(ObjectPtrs objects, Func func)
{
    for (auto object : objects)
    {
        (object->*func)();
    }
}

// Member functions with 1 or more arguments
template<typename ObjectPtrs, typename Func, typename ... Args>
void  batchApply(ObjectPtrs objects, Func func, Args ... args)
{
    for (auto object : objects)
    {
        (object->*func)(args ...);
    }
}

With the above, you can achieve your goal of being able to call a function on a set of objects with a single line of code. You would use it something like this:

QCheckbox  b1, b2, b3, b4, b5;
auto Box_1to5 = {b1, b2, b3, b4, b5};

batchApply(Box_1to5, &QCheckbox::setChecked, false);
batchApply(Box_1to5, &QCheckbox::toggle);

The one limitation of the above method is that it doesn't handle default function arguments, so even if a function has a default argument, you have to explicitly provide one. For example, the following will result in a compiler error because animateClick has one argument (its default value is ignored):

batchApply(Box_1to5, &QCheckbox::animateClick);

The above technique uses variadic templates to support any number and type of function arguments. If you are not yet familiar with these, you may find the following useful:

https://crascit.com/2015/03/21/practical-uses-for-variadic-templates/

Craig Scott
  • 9,238
  • 5
  • 56
  • 85
2

You can define a single signal and connect that to all of the checkboxes:

/* In the constructor or at the start*/
QVector<QCheckbox*> boxes{b1, b2, b3, b4, b5};
for(QCheckbox* box: boxes) {
    connect(this, &MyWidget::setBoxCheckedState, box, &QCheckbox::setChecked); 
}

/* Somewhere in the code where the state should change */
emit setBoxCheckedState(true); // <- custom signal on your class

or you can use the for_each algorithm:

bool checked = true; 
std::for_each(boxes.begin(), boxes.end(), [checked](QCheckbox* box) { 
    box->setChecked(checked);
});
CJCombrink
  • 3,738
  • 1
  • 22
  • 38