Markus-Hermann
Markus-Hermann

Reputation: 997

QCheckBox stateChanged not triggered reliably

Here is a Qt riddle: PythonQt. Win10. Within Slicer 3d (I am hoping, that this is not the issue).

The callback:

def _on_checkbox(val: int):
  print(f"Value: {val}.")
  ui.checkBox.setValue(0)

Expected: Either an endless loop, forever setting that checkbox to False, or (hoped-for) a behavior that simply enforces False (not my ultimate use-case. This is just research-code, trying to understand checkboxes).

Instead I observe:

a.: Starting out at state 0 (not checked). Click!

b.: Callback is triggered: Value: 2., checkbox remains unchecked. Click!

c.: Callback is not triggered, checkbox turns checked! Click! -> Back to (a), triggering the callback, printing Value: 0..

Are there two distinct checkstate properties to such a checkbox? So, that the checkBox.setValue(0) does not reset the 2 that has been received in (b), leading to setting it to 2 for (c) is not a state change, thus omitting the callback?

And the core question, how do I get to my desired behavior: A callback that is triggered every time a user clicks on the checkbox while it is enabled?

Upvotes: 0

Views: 1179

Answers (1)

relent95
relent95

Reputation: 4732

You must be calling setChecked() instead of that non-existing method setValue(). Calling an event(signal) handler endlessly is a bad behavior and most UI frameworks including Qt avoid that. See the implementation for detail.

It's not a good idea to pair the stateChanged signal of the QCheckBox with the setChecked() method of the base class(QAbstractButton). Rather, you should pair it with the setCheckState() method.(You can pair the toggled signal with the setChecked() method.)

For a signal emitted every time a user clicks, use the clicked signal.

See the following example.

from PySide6.QtCore import *
from PySide6.QtWidgets import *

app = QApplication()

c = QCheckBox('test')
c.clicked.connect(lambda: print('clicked'))

def on_change(v):
    print('on_change, v:', v)
    c.setCheckState(Qt.Unchecked)
c.stateChanged.connect(on_change)

c.show()

app.exec()

Upvotes: 3

Related Questions