Issue
I want a checkbox being automatically checked when I check another checkbox and not being uncheckable until I uncheck the other checkbox. I thought "freezing" would be an easy way to do this but I'm also interested in other solutions. An example program try this out would be:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QCheckBox
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(500, 50, 500, 500)
self.box1 = QCheckBox('Box1', self)
self.box1.setGeometry(250, 10, 50, 50)
self.box1.stateChanged.connect(self.dothething)
self.box2 = QCheckBox('Box2', self)
self.box2.setGeometry(10, 10, 50, 50)
self.show()
def dothething(self):
if not self.box2.isChecked():
self.box2.toggle()
self.box2.freeze()
else:
self.box2.unfreeze()
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Window()
sys.exit(app.exec_())
Obviously the .freeze()
and .unfreeze()
functions don't exist.
I also tried .setCheckable
but with this the CheckBox can only be frozen in an unchecked state so that's the opposite of what I want.
Solution
There are various available options.
The most obvious is to disable the checkbox, which is the best option as it makes clear to the user that it cannot be unchecked while still showing that it is checked.
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(500, 50, 500, 500)
central = QWidget()
self.setCentralWidget(central)
self.box1 = QCheckBox('Box1', self)
self.box1.toggled.connect(self.dothething)
self.box2 = QCheckBox('Box2', self)
layout = QHBoxLayout(central)
layout.addWidget(self.box1)
layout.addWidget(self.box2)
self.show()
def dothething(self, checked):
if checked:
self.box2.setChecked(True)
self.box2.setEnabled(False)
else:
self.box2.setEnabled(True)
Note that in the above example I'm using a central widget and set a layout; this is because you should always use a central widget in a QMainWindow and also because using fixed geometries has lots of issues and layout managers should always be preferred; in this case, for example, I wasn't able to tell apart box1 from box2 because the geometries you used for them resulted in hiding the number in their label. Remember that what you see in your screen rarely is what other people will see.
The simpler alternative is to check the box again if the other is checked; this will work in any case, no matter if the user uses the mouse or the keyboard:
class Window(QMainWindow):
def __init__(self):
# ...
self.box2.toggled.connect(self.verifyBox2)
def verifyBox2(self, checked):
if not checked and self.box1.isChecked():
self.box2.setChecked(True)
def dothething(self, checked):
if checked:
self.box2.setChecked(True)
Just for the sake of completenes, there are other two possibilities, but remember that both rely on mouse events, so if the user uses keyboard navigation (through tab or mnemonics) and presses Space the checkbox will still be toggled.
The first possibility is to set the WA_TransparentForMouseEvents
flag, which will ignore all mouse events:
class Window(QMainWindow):
# ...
def dothething(self, checked):
if checked:
self.box2.setChecked(True)
self.box2.setAttribute(Qt.WA_TransparentForMouseEvents, True)
else:
self.box2.setAttribute(Qt.WA_TransparentForMouseEvents, False)
Alternatively, you can ignore left click events (including double click, as QCheckBox is able to toggle with them too) by using an event filter:
class Window(QMainWindow):
def __init__(self):
# ...
self.box2.installEventFilter(self)
def eventFilter(self, source, event):
if source == self.box2:
if event.type() in (QEvent.MouseButtonPress, QEvent.MouseButtonDblClick):
return event.button() == Qt.LeftButton and self.box1.isChecked()
return super().eventFilter(source, event)
def dothething(self, checked):
if checked:
self.box2.setChecked(True)
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.