When trying to "port" code, it's important to know the basis of the source language and have a deeper knowledge of the target.
For instance, taking the first lines of your code and the referenced question:
QCheckBox *cb = new QCheckBox("Okay I understand");
The line above in C++ means that a new object (cb) of type QCheckBox is being created, and it's assigned the result of QCheckBox(...)
, which returns an instance of that class. To clarify how objects are declared, here's how a simple integer variable is created:
int mynumber = 10
This is because C++, like many languages, requires the object type for its declaration.
In Python, which is a dynamic typing language, this is not required (but it is possible since Python 3.6), but you still need to create the instance, and this is achieved by using the parentheses on the class (which results in calling it and causes both calling __new__
and then __init__
). The first two lines of your code then should be:
mb = qtw.QMessageBox()
cb = qtw.QCheckBox()
Then, the problem is that you're calling the other methods with new instances of the above classes everytime.
An instance method (such as setCheckBox
) is implicitly called with the instance as first argument, commonly known as self
.
checkboxInstance = QCheckBox()
checkboxInstance.setText('My checkbox')
# is actually the result of:
QCheckBox.setText(checkboxInstance, 'My checkbox')
The last line means, more or less: call the setText
function of the class QCheckBox, using the instance and the text as its arguments.
In fact, if QCheckBox was an actual python class, setText()
would look like this:
class QCheckBox:
def setText(self, text):
self.text = text
When you did cb = qtw.QCheckBox
you only created another reference to the class, and everytime you do cb()
you create a new instance; the same happens for mb
, since you created another reference to the message box class.
The following line:
mb.setCheckBox(mb(), cb())
is the same as:
QMessageBox.setCheckBox(QMessageBox(), QCheckBox())
Since you're creating new instances every time, the result is absolutely nothing: there's no reference to the new instances, and they will get immediately discarded ("garbage collected", aka, deleted) after that line is processed.
This is how the above should actually be done:
mb = qtw.QMessageBox()
cb = qtw.QCheckBox()
mb.setCheckBox(cb)
cb.setText("Don't show this message again")
Now, there's a fundamental flaw in your code: question()
is a static method (actually, for Python, it's more of a class method). Static and class methods are functions that don't act on an instance, but only on/for a class. Static methods of QMessageBox like question
or warning
create a new instance of QMessageBox using the provided arguments, so everything you've done before on the instance you created is completely ignored.
These methods are convenience functions that allow simple creation of message boxes without the need to write too much code. Since those methods only allow customization based on their arguments (which don't include adding a check box), you obviously cannot use them, and you must code what they do "under the hood" explicitly.
Here is how the final code should look:
# create the dialog with a parent, which will make it *modal*
mb = qtw.QMessageBox(self)
mb.setWindowTitle('Close application')
mb.setText('Do you really want to quit?')
# you can set the text on a checkbox directly from its constructor
cb = qtw.QCheckBox("Don't show this message again")
mb.setCheckBox(cb)
mb.setStandardButtons(mb.Yes | mb.No)
ret = mb.exec_()
# call some function that stores the checkbox state
self.storeCloseWarning(cb.isChecked())
if ret == mb.No:
return
self.close()