Reputation: 63
My goal is simply to switch the dialog in application to another by clicking "Next" button and and close the previous one. So, I have a starting script:
from PyQt5.QtWidgets import QApplication, QDialog
from gui.Ui_base import Ui_Base
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = QDialog()
ui = Ui_Base()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Then it enters this dialog, it's GUI was created by pyuic5:
from PyQt5 import QtCore, QtGui, QtWidgets
from gui.Ui_scripts import Ui_Scripts
class Ui_Base(QtWidgets.QDialog):
def setupUi(self, Base):
"""Here goes a lot of code for creating gui like size, place and etc."""
self.nextButton = QtWidgets.QPushButton(Base)
self.nextButton.clicked.connect(self.openScripts)
QtCore.QMetaObject.connectSlotsByName(Base)
def openScripts(self, Base):
scriptsWindow = QDialog()
scriptsUi = Ui_Scripts()
scriptsUi.setupUi(scriptsWindow)
Base.close()
scriptsWindow.show()
scriptsWindow.exec_()
And I get an error:
File "/Users/max/Project/gui/Ui_base.py", line 125, in openScripts Base.close()
AttributeError: 'bool' object has no attribute 'close'
So, actually it does open next dialog, but doesn't hide the current one. I tried other methods of QDialog like hide() and other, but nothing works. And I don't really understang with is Base (which is a window actually) bool?? Thanks.
Upvotes: 2
Views: 5381
Reputation: 9115
First, you don't (and should NOT) need to call both show()
and exec_()
on a dialog. exec_()
will call show()
as part of its operation, and blocks until the dialog is Accepted
or Rejected
Which brings me to: QDialog
has a special semantic for its closing, the concept of being Accepted
or Rejected
. If you want a button to close a QDialog
, you simply need to connect it to the accept
slot or the reject
slot. When that signal is emitted, the Dialog will close and its return code will be set to either accepted
or rejected
:
self.nextButton.clicked.connect(self.accept)
Another problem with your code is that QPushbutton.clicked
emits a signal to a slot expecting that slot to accept a bool
as the parameter (which represents the checkState
of a radio/check button). It doesn't send a class reference. This is why you get the exception you do.
Generally speaking, you don't chain dialogs from within themselves. For one thing, once the first dialog is closed, it will also close its children, which is not what you want because that will close your new dialog. Dialogs can pop up other dialogs, but that should only be used when the new dialog is a 'child' of the old one, since by default it will be modal and block the parent dialog (this is the behavior you are seeing). The correct way to implement your behavior would be to check the return code of calling window.exec_()
like so:
accepted = window.exec_()
if accepted == QDialog.Accepted:
# open the next dialog, user accepted
accepted = scriptsWindow.exec_()
else:
# Do what you should if the user rejects the dialog, if that's possible.
Basically, you should create a separate controlling state machine that cycles through the dialog set based on if each dialog is accepted or rejected. In general, I recommend you give the QDialog Documentation another once-over, it describes in pretty solid detail how to treat dialogs and what the common use/implementation patterns are for them.
Upvotes: 2