0

I am trying to add checked gropuboxes, and if one groupbox is checked the other should be unchecked.

So I thought, I add

    connect(m_grp1, SIGNAL(toggled(bool)), this, SLOT(grp1Changed(bool)));
    connect(m_grp2, SIGNAL(toggled(bool)), this, SLOT(grp2Changed(bool)));

But if I change the check on grp2 when grp1 changes, that will trigger a change in grp2, which will trigger a change in grp1...

Is there anything built-in that I can use - like radio buttons ? Or I can't use the checked group boxes and must implement the behavior with radio buttons myself ?

My code (Qt 4.8):
Should add in a grid layout 2 checked group boxes, each with some items inside in a grid layout, both boxes checkable and one of them checked.

groupboxes.h

#ifndef GROUPBOXES_H
#define GROUPBOXES_H

#include <QtGui>

class GroupBoxes : public QWidget
{
    Q_OBJECT

public:
    GroupBoxes(QWidget *parent = 0);

private slots:
    void grp1Changed(bool _on);
    void grp2Changed(bool _on);

private:
    QGroupBox *m_grp2;
    QGroupBox *m_grp1;

    void setGroup1();
    void setGroup2();
};

#endif // GROUPBOXES_H


groupboxes.cpp

#include "groupboxes.h"

GroupBoxes::GroupBoxes(QWidget *parent)
    : QWidget(parent)
{
    setGroup1();
    setGroup2();

    connect(m_grp1, SIGNAL(toggled(bool)), this, SLOT(grp1Changed(bool)));
    connect(m_grp2, SIGNAL(toggled(bool)), this, SLOT(grp2Changed(bool)));
    QGridLayout *grid = new QGridLayout;

    grid->addWidget(m_grp1, 0, 0);
    grid->addWidget(m_grp2, 1, 0);
    setLayout(grid);

    setWindowTitle(tr("Group Boxes"));
    resize(480, 320);
}

void GroupBoxes::setGroup1()
{
    QLabel lbl1 = new QLabel(tr("def"));
    m_grp1 = new QGroupBox("DEF");
    m_grp1->setCheckable(true);
    m_grp1->setChecked(true);
    QGridLayout *boxLayout1 = new QGridLayout;
    boxLayout1->addWidget(lbl1, 0, 0, 1, 1);
    m_grp1->setLayout(boxLayout1);
}

void GroupBoxes::setGroup2()
{
    QLabel lbl1 = new QLabel(tr("abc"));
    m_grp2 = new QGroupBox("ABC");
    m_grp2->setCheckable(true);
    m_grp2->setChecked(false);
    QGridLayout *boxLayout = new QGridLayout;
    boxLayout->addWidget(lbl1, 0, 0, 1, 1);   
    m_grp2->setLayout(boxLayout);
}

void GroupBoxes::grp1Changed(bool _on)
{
    m_grp2->setChecked(!_on);  // but that would trigger grp2Changed and will lead to infinite loop
}
void GroupBoxes::grp2Changed(bool _on)
{
    m_grp1->setChecked(!_on);  // but that would trigger grp1Changed and will lead to infinite loop
}


main.cpp

#include <QApplication>
#include "groupboxes.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    GroupBoxes window;
    window.show();
    return a.exec();
}
Thalia
  • 13,637
  • 22
  • 96
  • 190

3 Answers3

2

You need to uncheck your checkbox and you need to use SignalBlocker for not getting in an infinite loop

void GroupBoxes::grp1Changed(bool _on){
QSignalBlocker(m_grp2);
QSignalBlocker(m_grp1);
m_grp2->setChecked(!_on);
m_grp1->setChecked(_on);
}

but you should use RadioButtons in the same Layout since it's not possible to check more than 1 RadioButton.

ale
  • 6,369
  • 7
  • 55
  • 65
Börkn
  • 38
  • 6
  • Thank you, this is interesting, but was introduced in Qt 5.3 - as I mentioned I have to use 4.8, so I can't even test if it works. I'll upvote because I learnt something. – Thalia Jul 13 '15 at 16:29
  • The reason I did not implement Radio buttons is because I wanted to use the built in checkable boxes, as I mentioned in my question. – Thalia Jul 13 '15 at 16:33
  • Sry I've didnt read that ... but you can use blockSignal see Doc http://doc.qt.io/qt-4.8/qobject.html or you can make your own class http://stackoverflow.com/questions/3556687/prevent-firing-signals-in-qt – Börkn Jul 13 '15 at 17:46
1

I'll do

void GroupBoxes::grp1Changed(bool _on)
{
    if(_on)
        m_grp2->setChecked(false);  
}

That way I seem to avoid infinite loop because I only change on true, and set change to false.

Thalia
  • 13,637
  • 22
  • 96
  • 190
0

You can add the QCheckBox widgets to a QButtonGroup. The QButtonGroup takes care of making sure only one of its members is set. Or use the autoExclusive property.

Or use a QRadioButton if that's what you really intended. You should only use checkboxes for this purpose if you want to be able to deselect both.

Hamish Moffatt
  • 826
  • 4
  • 12
  • Check boxes do not behave any differently in a button group - and I do not see an autoExclusive property for the QGroupBox. I do not want to deselect both boxes... I would rather NOT implement radio buttons OR check boxes separately, since QGroupBox already has the checked property. Adding more UI elements makes the UI bulky and ugly, so if there is anything BUILT-IN I want to use it. – Thalia Jul 14 '15 at 14:18
  • Check boxes do behave as I describe - try it. But I did not realise you were talking about exclusive QGroupBox widgets, not just QCheckBox widgets. Maybe it's not good UI design which is why it's not built-in? Anyway, use the signal blocker... – Hamish Moffatt Jul 15 '15 at 23:46