qtradio-buttonqpushbutton

Uncheck a QPushButton with autoExclusive


Ubuntu 22.04, Qt 6.4.0.

I have some QPushButtons that belong to the same parent. I set all of them with checkable and autoExclusive properties to true. The doc about the latter states:

If auto-exclusivity is enabled, checkable buttons that belong to the same parent widget behave as if they were part of the same exclusive button group. In an exclusive button group, only one button can be checked at any time;

Emphasis is mine. From what I understand, they say that only one button "can" be checked. This means that more than one button can never be checked. But it allows to no buttons checked. Otherwise I was expecting something like: "only one button must be checked at any time".

Anyway, my problem is I cannot uncheck a button after it was checked. It remains checked no matter I click on it.

I also tried programmatically:

ui->myCheckableButton->setChecked(false);

no way. Disabling the autoExclusive property I can disable them, but of course is not the intended behavior.

What am I missing here? How to uncheck a button when autoExclusive property is active?


Solution

  • Sadly, you are experiencing the intended behavior of Qt.

    1. The source code for QAbstractButton::setChecked contains lines that makes it clear a button belonging to an exclusive group cannot be unchecked (unless it is the only button in that group).

      if (!checked && d->queryCheckedButton() == this) {
          // the checked button of an exclusive or autoexclusive group cannot be  unchecked
      #if QT_CONFIG(buttongroup)
          if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
              return;
          if (d->group)
              d->group->d_func()->detectCheckedButton();
      #else
          if (d->autoExclusive)
              return;
      #endif
      }
      

      d->queryCheckedButton() returns nullptr if only 1 button belongs to the group. The rest is straight forward:

      1. If Qt was compiled to use button groups and the button group is exclusive, do not uncheck the button (return; instead).
      2. Otherwise, if the button itself is autoexclusive, do not uncheck it.
    2. I checked the exclusive property of QButtonGroup, the description makes the behavior clear:
      In an exclusive group, the user cannot uncheck the currently checked button by clicking on it; instead, another button in the group must be clicked to set the new checked button for that group..

    It is unfortunate the description for QAbstractButton does not contain that sentence too, although I will say it is not incorrect since 0 buttons may initially be checked (then, when 1 is checked, it will never allow to uncheck everything, which is the missing part).

    Your modified sentence using must would have a meaning in the lines of:
    When using the QAbstractButton class, you must make sure not to allow more than 1 button to be checked.
    There are several instances of sentences built this way and AFAICT, all of them describe things you must do for your implementation to work.

    The good news in all of that is that your solution of disabling the autoExclusive property seems no have no impact whatsoever on the signals emitted by the button.
    You may for instance create a subclass of QPushButton (if that is what you are using), remove the autoExclusive property, first thing in the mousePressEvent and re-enable it last thing in the mouseReleaseEvent.

    Alternatively, you can make your button non autoexclusive and connect signals when it is toggled (to true) to unckeck the other buttons.
    This is probably how I would do it.