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.
- QCheckBox documentation:
state contains the checkbox’s new CheckState
.
- PySide6.QtCore.Qt.CheckState documentation:
This enum describes the state...
Qt.Checked: The item is checked.
.
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?
2
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
forstateChanged
: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 fromenum.IntEnum
, which is not the case forQt.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:Otherwise get the
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;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: