PySide6 QCheckBox stateChanged() generates state event int instead of Qt.CheckState

Question:

PySide6 6.4.1 PIP on Ubuntu and Windows contains a QCheckBox with stateChanged() API call to generate an event when the checkbox state changes.

The QCheckBox generated event argument state is type int instead of enum CheckState:

Testcase below demonstrates not working checkbox event state:

from PySide6.QtWidgets import QApplication, QWidget, QCheckBox
from PySide6.QtCore import Qt
import sys

class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('QCheckBox')

        checkbox = QCheckBox('Show title', self)
        checkbox.move(20, 20)
        checkbox.toggle()
        checkbox.setTristate(True)
        checkbox.stateChanged.connect(self.onCheckboxChange)

    def onCheckboxChange(self, state):
        # state = int and not Qt.Checked or Qt.Unchecked
        # This is not matching with the documentation

        print('Qt.Checked type: {}'.format(type(Qt.Checked)))
        print('Event: {}, type: {}'.format(state, type(state)))

        # Always setting title to UNKNOWN as this is an incorrect type comparison
        if state == Qt.Unchecked:
            self.setWindowTitle('Unchecked')
        elif state == Qt.PartiallyChecked:
            self.setWindowTitle('PartiallyChecked')
        elif state == Qt.Checked:
            self.setWindowTitle('Checked')
        else:
            self.setWindowTitle('UNKNOWN')

def main():
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()

Output:

# When unchecking checkbox:
Qt.Checked type: <enum 'CheckState'>
Event: 0, type: <class 'int'>    <= Expected Qt.Unchecked:

# When partially checking checkbox:
Qt.Checked type: <enum 'CheckState'>
Event: 1, type: <class 'int'>    <= Expected Qt.PartiallyChecked:

# When checking checkbox:
Qt.Checked type: <enum 'CheckState'>
Event: 2, type: <class 'int'>    <= Expected Qt.Checked:

I don’t know how to convert the Qt.Checked , Qt.PartiallyChecked or Qt.Unchecked to an int.
Casting with if state == int(Qt.Checked) generates:

  • TypeError: int() argument must be a string, a bytes-like object or a real number, not 'CheckState'

Is this expected behavior?

Asked By: Erriez

||

Answers:

It is not wrong, and it is the expected behavior.

If you read the documentation more carefully, the type of the argument is int for stateChanged:

PySide6.QtWidgets.QCheckBox.stateChanged(arg__1)
    PARAMETERS
        arg__1 – int

While it might seem unexpected and inconsistent, that’s what we have. I don’t know why, but my suspect is that it’s for historical reasons.

Starting with Qt6, both python bindings (PySide and PyQt) have switched to actual python enums, and this can create some level of confusion.

int() conversion is now only possible for enums that actually inherit from enum.IntEnum, which is not the case for Qt.CheckState, but it is for some others (for example, Qt.ItemDataRole).

If you want to compare the result of stateChanged, then either convert the value to the enum:

if Qt.CheckState(state) == `Qt.Checked`:

Otherwise get the value:

if state == Qt.Checked.value:

Some important notes about terminology: 1. stateChanged is a signal, not an "API call" (in fact, signals are not even callable); 2. signals are not events, at least in Qt terms: events are system (or synthesized) events that are normally generated by the system, either by user interaction or caused by the system itself;

Answered By: musicamante

The stateChanged signal sends an int as indicated in the docs, so the behavior is as expected. The solution is to convert to Qt.CheckState:

def onCheckboxChange(self, state_int):
    state = Qt.CheckState(state_int)
Answered By: eyllanesc
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.