I have created a little pyqt5 project. Here is a printscreen of the application while running:

When the user clicks on the QPushButton from the main window, the dialog window appears and the user writes something in the QlineEdit. Then while clicking on the QPushButton of the dialog window, the dialog window sends a signal to the main window and is deleted. The signal contains the text typed by the user.
Here are the descriptions of my two classes which are very simple:
The MainWindow class.
The DialogWindow class (I want to make my own Dialog Class without using the pre existing Dialog windows).
My main script

I have several questions:
Is it the right way of using signals in order to communicate between windows? I do not think that I violate the class encapsulation. However I do not like to connect the signal on the child class by writing:
self.mySignal.connect(parent.updatelabelAnswer)
In this line I use the attribute parent - is it okay? It seems to me that it is not a good way to use signals.
My second question is:
Am I right to call self.deleteLater() in the on_pushButton_clicked slot of DialogWindow? It seems not, as I have checked with the python interactive shell and the object myDialogWindow is still accessible.
Generally, the parent should always be the one performing the signal connecting. Having the child widget make connections on the parent is problematic because it places limitations on the parent and causes side effects, and completely breaks in cases where parent ownership is transfrerred for the child widget.
In your example, there are two options I would consider "correct". If the dialog was meant to be at least somewhat persistent, and not meant to be run modally, then it should define a signal that the parent class connects to. The dialog should not delete itself, that should be the responsibility of the parent class after the signal is received.
MainWindow
def on_pushbutton_clicked(self):
if not self.dlg:
self.dlg = DialogWindow(self)
self.dlg.mySignal.connect(self.on_mySignal)
self.dlg.show()
def on_mySignal(value):
self.dlg.mySignal.disconnect()
self.dlg.close()
self.dlg.deleteLater()
self.dlg = None
self.updateLabelAnswer(value)
Your dialog seems to be a temporary dialog that exists just to gather input and should probably be run modally. In that case, you don't even have to define any signals. Just create the class and provide an API to get the value of the text box.
DialogWindow
class DialogWindow(...)
...
def on_pushbutton_clicked(self):
self.accept()
def getValue(self):
return self.lineEdit.text()
In MainWindow
def on_pushbutton_clicked(self):
dlg = DialogWindow(self)
if dlg.exec_():
value = dlg.getValue()
Okay so I guess I should post an answer instead of writing bloated comments :P
About the deletion I will quote the Qt documentation:
As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set. If the dialog is the application's main widget, the application terminates. If the dialog is the last window closed, the QApplication::lastWindowClosed() signal is emitted.
However if you want to handle the closing (and deletion) of the dialog window from your other widget that opens it, slots and signals should be used. Simply connect a button or whatever from your main widget and its clicked() signal to the done() slot of your dialog and you are good to go.
At this point I would also like to point out that deleting a dialog may not be necessary. Based on the memory footprint of the dialog (how much memory is used to create and run it) you may wish to consider creating the dialog at the beginning and leaving it in your memory until the main application is closed. In addition to that you can use hide() and show() to display it on the screen. This is actually a generally good practice for things that are small enough since the deletion and then creation of a window takes more time compared to simply hiding and showing it.
Now about the signals and slots these have pretty straight-forward semantics. As I've posted in the comments and my other answer in order to connect a slot to a signal you need to have them present in the same scope. If that's not the case pass one (or both) to a place where the situation is fixed. In your case you have to have a common place for both. If both are top-level widgets you have to do the connections inside your main(). I would rather add the dialog as an extension to your MainWindow class (as a class member) and to the instantiation plus the connections there - for example in the constructor of your MainWindow:
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.dialog = DialogWindow(self)
# Connect mainwindow's signals to dialog's slots
# Connect dialog's signals to mainwindow's slots
# And even connect dialog's signals to dialog's slots
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