0

I have a main window which creates a second window when a button is pressed. I have two problems that occur but for now I will focus on the first one: I cannot get it to completely close the old window when I close it. It closes it visually but the window is still running in the background. To illustrate this I put in a counter. Below is generic code which illustrates this issue.

Here is my dialog window:

from PyQt5 import QtCore, QtGui, QtWidgets
from form_test import Ui_Form

class formTest(QtWidgets.QWidget, Ui_Form):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        flags = QtCore.Qt.Drawer | QtCore.Qt.WindowStaysOnTopHint 
        self.setWindowFlags(flags)
        self.setupUi(self) 

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(507, 305)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.btnOpenForm = QtWidgets.QPushButton(self.centralwidget)
        self.btnOpenForm.setGeometry(QtCore.QRect(170, 30, 93, 28))
        self.btnCloseForm = QtWidgets.QPushButton(self.centralwidget)
        self.btnCloseForm.setGeometry(QtCore.QRect(170, 160, 93, 28))
        MainWindow.setCentralWidget(self.centralwidget)

        self.btnOpenForm.clicked.connect(self.openClicked)
        self.btnCloseForm.clicked.connect(self.closeClicked)


        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.btnOpenForm.setText(_translate("MainWindow", "Open Form"))
        self.btnCloseForm.setText(_translate("MainWindow", "Close Form"))

    def openClicked(self):
        print('open')
        self.popForm = formTest()
        self.popForm.show()

    def closeClicked(self):
        print('close')
        self.popForm.close()


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Here is my spawning windows code (form_test.py):

from PyQt5 import QtCore, QtGui, QtWidgets
import time, threading

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(190, 170, 93, 28))
        self.pushButton.setObjectName("pushButton")

        self.pushButton.clicked.connect(self.pushButtonClicked)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

        self.loopThread = threading.Thread(target = self.looping)
        self.loopThread.daemon = True
        self.loopThread.start()

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "PushButton"))

    def pushButtonClicked(self):
        print("clicked")

    def looping(self):
        count = 0
        while(True):
            print('looping... ' + str(count))
            count = count + 1
            time.sleep(1)

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_())

When I close the second window it is still running in memory. When I try to open it again another one begins running and then I have two running. Is there a different window I should use which will destroy all memory when it is closed? The second issue I am having is which my actual code (not this generic code) it causes a crash when I try to launch a second time. That issue may go away with the fixing of this issue and since I am not able to share my code online I have to stay as generic as possible for now so I am hoping to solve this issue first and maybe get resolution too.

PLEASE help ... I've worked on this FAR too long!!! Thanks, in advance, for any assistance on this.

Scott
  • 61
  • 2
  • 9
  • Unfortunately the code you present isn't close to being testable. Qt Dialogs aren'r removed from memory when they are closed. There is another concept called "delete" which actually destroys the resources of the dialog. You say that the app crashes when you "try to open it again" but I don't see that you're ever doing that: you create a brand new dialog each time the open button is clicked. You are also using multiple inheritance, but QDialog is actually built somehow on top of a C++ library class. Does this work the way you intend? Does "in closeEvent" ever get printed? – Paul Cornelius Jun 30 '17 at 23:00
  • Is there an alternative window type I should be using instead of Qt Dialogs which would remove all memory when closed? And to answer your question ... yes, the print statement "in closeEvent" does work since I am spawning this dialog from a main window. – Scott Jul 05 '17 at 15:28
  • Hopefully this will help demo the problem ... I changed the code above to be very generic but still illustrate the problem. – Scott Jul 05 '17 at 20:20
  • Why do you want to remove it from memory? – eyllanesc Jul 05 '17 at 20:43
  • Because in the actual application it makes connections with an outside application. We do not want it to create multiple connections to the same application. And we also want to make sure that when it disconnects that it is completely disconnected. It becomes a security issue. We can do all the socket disconnects and so forth (which we do) ... but this application could be running for weeks on end between restarts. The window we spawn can be opened/closed hundreds of times over that period. We don't want to have hundreds of "dead" disconnected pieces in the background for no reason. – Scott Jul 05 '17 at 21:23
  • Maybe "delete from memory" isn't the correct term here. What I am trying to ensure is that when the window is closed ... everything is closed. Threads in that window close, variables and so forth are killed and so forth. Basically, it comes down to this ... when you close your main window everything associated with that window is gone. Why doesn't it do that for the spawned windows as well? Why is it that when I close it ... that things can still be running. Hell, I can even .show() it again and it is there. – Scott Jul 05 '17 at 21:33
  • The old window has closed, what happens is that you have called the timer and it is executed in another plane, that is the asynchronous way of working Qt, in addition you talk about threads, but that window does not have any thread. – eyllanesc Jul 05 '17 at 21:50
  • What you can do is reset all the variables to default values to not have those security problems, if you know how to handle the threads can close them properly and you will not generate those problems. – eyllanesc Jul 05 '17 at 21:53
  • The thread that you launch in `Ui_Form` runs forever - you have provided no way for it to terminate. It doesn't matter if you close the window; the loop is still running. Its thread retains a reference to the instance of `Ui_Form` where the thread was launched, so that object remains alive in memory. You must return from the method `looping` in order to terminate the thread. – Paul Cornelius Jul 05 '17 at 22:24
  • 2 things ... 1) I realize I don't have code in place to end the infinite loop. My thought was that if put in a bLoop value and properly end the loop when I have a closeEvent I would not be able to easily tell if the window completely closed everything down. 2) I realize I am creating a new instance of the spawned window (that is a desired operation since the hope is that the last window was completely closed down and no longer available). – Scott Jul 05 '17 at 22:46
  • When I "close()" the previous window the code is still going to be in memory. Does that mean it is tying up that section of memory or is it feeded up in memory and may be eventually overwritten? The reason I ask is because multiple opening and closing of the windows would cause a memory leak if it keeps creating new ones and not freeing up the old ones in memory. Another desirable reason for this to completely close the window and create an entire new window is that it helps force a close down and reconnection if issues are being seen. – Scott Jul 05 '17 at 22:47
  • Every QObject has a method `deleteLater` that tells Qt that the object is no longer needed. Its resources and memory can then be freed. For QDialogs, `close` does not call `deleteLater`. The reason: you might need to get user-entered data from a QDialog after it is dismissed. In your case, you can call `deleteLater` in the last line of `looping` - but not before. You can't delete the window when the button is clicked because the loop is still going. Deleting a `QObject` and then trying to run Python code that references it will crash your program. I've done it (too many times). – Paul Cornelius Jul 05 '17 at 23:13

0 Answers0