0

I think I've run into a problem similar to [StackOverflow -- How to close a QDialog][1] but I'm not seeing a solution if one was given. I've mocked two scripts similar to what I am having troubles with below.

mainWidget.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox
import shelve

from calledWidget import Ui_CalledWindow

class Ui_Form(object):    
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(640, 170)
        Form.setWindowTitle("Form")
        
        
        self.verticalLayout = QtWidgets.QVBoxLayout(Form)
        self.verticalLayout.setObjectName("verticalLayout")
        
        
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setObjectName("lineEdit")
        self.verticalLayout.addWidget(self.lineEdit)
        
        
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText("PushButton")
        self.verticalLayout.addWidget(self.pushButton)
        self.pushButton.clicked.connect(self.passString)       
        
    def passString(self):
        stringToPass = self.lineEdit.text()
        
        openingDialog = QMessageBox()
        openingDialog.setWindowTitle("Warning")
        openingDialog.setText("Are sure you want to pass the string: {}?".format(stringToPass))
        openingDialog.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        reply = openingDialog.exec()
        
        if reply == QMessageBox.Yes:
            s = shelve.open("tempPass")
            s["stringOut"] = stringToPass
            s.close()
            
            self.newWindow = QtWidgets.QDialog()
            self.ui = Ui_CalledWindow()
            self.ui.setupUi(self.newWindow)
            self.newWindow.show()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

calledWidget.py

from PyQt5 import QtCore, QtGui, QtWidgets
import shelve

class Ui_CalledWindow(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(612, 178)
        Dialog.setWindowTitle("Dialog")
        
        
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        
        
        s = shelve.open("tempPass")
        stringIn = s["stringOut"]
        
        self.listView = QtWidgets.QListWidget(Dialog)
        self.listView.setObjectName("listView")
        self.verticalLayout.addWidget(self.listView)
        self.listView.addItem(stringIn)
        
        
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        
        
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.verticalLayout.addWidget(self.buttonBox)
        
        
        self.buttonBox.accepted.connect(self.closePlz)
        
    def closePlz(self):
        print("Code to close current window goes here.")
        self.close()

In short, mainWidget.py takes in a string and passes it to calledWidget.py. Eventually the latter will perform operations on the passed string and give the user the option to keep the changes or modify them. For now it simply displays the string in a list and has an 'Ok' button which I would like to have close the QDialog window when clicked. I've tried using the .close() method, sys.exit(), and even a signal to the .closeEvent() to try to find a work around but nothing has worked yet. Any help is appreciated.

Edit: I get that Designer has its own set of rules for how to go about editing it but I am using the results as an example to quickly illustrate the point. If I've made a mistake as a result of using Designer please let me know so I can learn for the future but my main question is how does closing a QDialog box work when it is called from another widget. [1]: How to close a QDialog

  • "Nothing has worked yet" because you're making a common mistake, which is ignoring the warning on top of those files: "don't edit it if you don't know what you're doing". Follow the official guidelines about [using Designer](//www.riverbankcomputing.com/static/Docs/PyQt5/designer.html) and you'll be able to call `close()`, override the `closeEvent()` and do all other things that *actual* Qt subclassing allows. – musicamante Nov 01 '22 at 17:16
  • This doesn't help. I am using Designer to create a quick mock up of the problem, if I've made a mistake in Designer then it was unintentional, please point it out as opposed to attributing it to "a common mistake". Also, Designer does not have a way to connect two windows so I can't use the output code to see the format of what I am trying to get at if that is your point. Finally, "don't edit if you don't know what you're doing" seems like a poor learning methodology. Breaking and finding fixes so you don't repeat the mistake is how people find out what they don't know. – ARChalifour Nov 01 '22 at 18:14
  • 1
    The point is that those files are ***not*** intended for editing, not even to be opened (if not for strict learning purposes, in order to understand what they do). The program logic should be in *another* file(s), which will use QWidget-based subclasses to add all the needed implementation, and those subclasses will use the pyuic files as *imports* (either for multiple inheritance, or with composition), as shown in the link above. The instances you're creating cannot use things like `self.close()` or overrides like `closeEvent()` because they are not QWidgets, and those functions don't exist. – musicamante Nov 01 '22 at 18:35
  • Your main script should import the original pyuic generated files, and have two subclasses, with the "main widget" inheriting from QWidget, and the other from QDialog (eventually also inheriting from the ui classes if you use multiple inheritance, which is the common practice). In those subclasses then you can implement all the things you tried to add, such as `self.close()` or override the `closeEvent()` handler. – musicamante Nov 01 '22 at 18:42
  • Fair enough, that makes sense and I now understand the implementation of how to do it in standard practice, so thank you for that. My question now (assuming we can look past that the above is clearly written in Designer): is there no way to make what is written above work the way it is intended. That is to close the window that pops up from `calledWidget.py` when the 'Ok' button is clicked. Or is that just not possible? – ARChalifour Nov 01 '22 at 19:00
  • Your updated code doesn't work because you're creating *two* instances, a QDialog and Ui_CalledWindow: `self.close()` refers to the second, but you're actually showing the first. If you directly inherit from a Qt widget, there's no need to create a further instance, just use the one you already have: `self.newWindow = Ui_CalledWindow()` `self.newWindow.setupUi(self.newWindow)`. Note that if you properly create a subclass that *does* use the pyuic files (as they are), you normally just call `self.setupUi(self)` in its `__init__` (as shown in the multiple inheritance example of the link). – musicamante Nov 01 '22 at 19:28
  • Gotcha! That makes sense. But that implies `self` doesn't follow the modal window? That seems odd. – ARChalifour Nov 01 '22 at 19:49
  • Can you clarify what you mean with that phrase about `self`? – musicamante Nov 01 '22 at 22:35

1 Answers1

0

Current work around: in method passString of script mainWidget.py

def passString(self):
        stringToPass = self.lineEdit.text()
        
        openingDialog = QMessageBox()
        openingDialog.setWindowTitle("Warning")
        openingDialog.setText("Are sure you want to pass the string: {}?".format(stringToPass))
        openingDialog.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        reply = openingDialog.exec()
        
        if reply == QMessageBox.Yes:
            s = shelve.open("tempPass")
            s["stringOut"] = stringToPass
            s.close()
            
            self.newWindow = QtWidgets.QDialog()
            self.ui = Ui_CalledWindow()
            self.ui.setupUi(self.newWindow)
            self.newWindow.show()
        
        # The following connects to the Ok button in the new window and closes it    
        self.ui.buttonBox.clicked.connect(self.newWindow.close)