3

I've subclassed the QGroupBox class, with the checkable property enabled. I'm trying to override the behaviour of the toggle/checked events.

Here's the code:

class SideWidgetGroupBox: public QGroupBox
{
    Q_OBJECT
public:
    SideWidgetGroupBox(QWidget* parent = 0): QGroupBox(parent)
    {
        this->setCheckable(true);
        connect(this, SIGNAL(toggled(bool)), this, SLOT(my_toggled(bool)));
    }

private slots:
    void my_toggled (bool on)
    {
        std::cout << "my toggled method" <<std::endl;
    }
};

So far so good, my slot gets executed. However the groupboxs' contents also get enabled/disabled. Is there a way to prevent that? Or do I have to manually reset the original enabled/disabled state?

Istvan Szasz
  • 1,307
  • 17
  • 31

1 Answers1

6

Is there a way to prevent enabling/disabling of a content?

Yes, but this way is not easy, because there is no QCheckBox there. What looks like a check box is an area of QGroupBox. And all events are processed by QGroupBox:
1. Override event method and prevent processing of QEvent::KeyRelease and QEvent::MouseRelease events by the base class.

bool SideWidgetGroupBox::event(QEvent *e)
{
  switch (e->type()) {
   case QEvent::KeyRelease:
   case QEvent::MouseButtonRelease:
     myHandler(e);
     return true;
  }
 return QGroupBox::event(e);
}

2. In myHandler check whether space pressed or the mouse clicked on the checkbox. Store checkBox value and do what you need. Use this code to check what is under cursor:

QStyleOptionGroupBox box;
initStyleOption(&box);
QStyle::SubControl released = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
                                                             event->pos(), this);
bool toggle = released == QStyle::SC_GroupBoxLabel || released == QStyle::SC_GroupBoxCheckBox;
if (toggle)
{
    m_state = !m_state;
    update();
}

3. Add method initStyleOption and set state to the state of the checkBox (you should store it by yourself):

void SideWidgetGroupBox::initStyleOption(QStyleOptionGroupBox *option) const
{
    QGroupBox::initStyleOption(option);
    QStyle::State flagToSet = m_state ? QStyle::State_On : QStyle::State_Off;
    QStyle::State flagToRemove = m_state ? QStyle::State_Off : QStyle::State_On;

    option->state |= flagToSet;     
    option->state &= ~flagToRemove;
    option->state &= ~QStyle::State_Sunken;
}

4.Method initStyleOption in QGroupBox is not virtual that is why you need to reimplement paintEvent also:

void paintEvent(QPaintEvent *)
{
    QStylePainter paint(this);
    QStyleOptionGroupBox option;
    initStyleOption(&option);
    paint.drawComplexControl(QStyle::CC_GroupBox, option);
}

do I have to manually reset the original enabled/disabled state?
You can't do this with setEnabled because it checks current checked state and prevents enabling of children. Although you can call setEnabled for children directly using this->findChildren<QWidget*>

Suggestion
You can use ways described above or remove standard checkBox and(or) label and put your own QCheckBox over the group (without layout, of course) and use it as you want. If you group can be moved you will need to move the check box also.

Ezee
  • 4,214
  • 1
  • 14
  • 29
  • Wow, I tought this would be easier. I'm trying to use your solution, but I can't set the state of the checkBox. I guess this line should do it: `option->state |= (state ? QStyle::State_On : QStyle::State_Off);` , I've tried with true/false values, but it doesn't seem to do anything. – Istvan Szasz Aug 29 '14 at 10:56
  • 1
    @istee Updated 2,3 in the answer. And added 4. There was one more difficulty: initStyleOption is not virtual. – Ezee Aug 29 '14 at 12:27
  • If I understand all of this correctly, there is no way of using a standard checkable QGroupBox, and overriding the "enable/disable"-behaviour the easy way. The only possibility would be to re-enable all child widgets one by one? – St0fF Dec 04 '14 at 14:47
  • You can re-enable the children or use the way described above to remove standard behavior. – Ezee Dec 05 '14 at 07:01