I created a QMainWindow GUI that uses a toolbar of radio buttons to select the main display (i.e. which widget of a QStackedWidget is displayed). I finally got a QButtonGroup's signal to be detected, but I don't fully understand why my fix worked.
Here is a minimal working example; the focus is the modelButtonGroup
method.
class myGui(QMainWindow):
def __init__(self, parent=None):
super(myGui, self).__init__(parent)
self.setupCentral()
self.setupButtonToolBar()
def setupCentral(self):
self.stackedWidget = QStackedWidget()
self.setCentralWidget(self.stackedWidget)
windowA = QWidget()
windowALayout = QGridLayout()
windowALayout.addWidget(QLabel('Window A'))
windowB = QWidget()
windowBLayout = QGridLayout()
windowBLayout.addWidget(QLabel('Window B'))
windowA.setLayout(windowALayout)
windowB.setLayout(windowBLayout)
self.stackedWidget.addWidget(windowA)
self.stackedWidget.addWidget(windowB)
self.stackedWidget.setCurrentIndex(0)
def setupButtonToolBar(self):
buttonBar = QToolBar()
buttonBar.addWidget(self.modelButtonGroup())
self.addToolBar(buttonBar)
def modelButtonGroup(self):
modelsWidget = QWidget()
modelsLayout = QVBoxLayout()
self.ButtonGroup = QButtonGroup()
windowA_Button = QRadioButton('Window A')
windowA_Button.setChecked(True)
self.ButtonGroup.addButton(windowA_Button, 0)
windowB_Button = QRadioButton('Window B')
self.ButtonGroup.addButton(windowB_Button, 1)
self.ButtonGroup.buttonClicked[int].connect(self.switchdisplay)
modelsLayout.addWidget(windowA_Button)
modelsLayout.addWidget(windowB_Button)
modelsWidget.setLayout(modelsLayout)
return modelsWidget
def switchdisplay(self, id):
print('button %d has been pressed' % id)
self.stackedWidget.setCurrentIndex(id)
My understanding is that, if a name in one method is only referenced within that method, and isn't referred to elsewhere in the class, then self.
is not needed as a prefix. However, if ButtonGroup
is used instead of self.ButtonGroup
, its .buttonClicked
signal doesn't get processed by switchdisplay
.
While writing this question, I think I determined why this is, but would appreciate confirmation. modelButtonGroup
returns only the widget of buttons, and is only called when setting up the GUI. The ButtonGroup
is not passed out of the function, and is garbage collected. The 'self.' prefix is required for it to 'live on', even if it's not directly referred to by name.
Am I understanding this correctly?
I see that you already figured it out yourself:
The
ButtonGroup
is not passed out of the function, and is garbage collected. The 'self.' prefix is required for it to 'live on', even if it's not directly referred to by name.Am I understanding this correctly?
Yes. That is exactly what is happening here. If you don't retain a reference to ButtonGroup
, then it is deleted as soon as it goes out of scope (at the function exit). It will never emit any signals.
I think @eyllanesc's answer might work, too. In that case, the reference to the ButtonGroup
object would be retained implicitly, as a child within the parent
class.
FWIW, I typically encounter bugs like this when I'm dealing with QMenu
objects.
ButtonGroup
must be a member of the class, if you do not want to use self.ButtonGroup
, you can use ButtonGroup = QButtonGroup(self)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With