river
river

Reputation: 13

PyQt5: multiple instances of same window

I'm having a problem with pyqt5. I have this piece of code to instantiate my class and open my window without closing after the show method (because gc).

def user_crud():
  global crud
  crud = TCrudUsuario()
  crud.show()

it works well, but on the TCrudUsuario class, I have some buttons that connects to a method with arguments, so I'm using a lambda (tried with partial, but the same problem happens), something like this:

self.btnNovo.clicked.connect(lambda: self.manage_user(1))

the problem is: if I use a lambda or partial to connect to my method manage_user(), it allows me to open multiple instances of TCrudUsuario class, opening two or more windows. but, if I remove the connect method, it only opens 1 window. My goal is to allow only one instance/one window. does anyone know why this happens?

reproducible code:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_test(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setObjectName("test")
        self.resize(380, 250)
        self.btntest = QtWidgets.QPushButton(self)
        self.btntest.setGeometry(QtCore.QRect(70, 190, 100, 40))
        self.btntest.setText('open other window')
        self.btntest.clicked.connect(open_otherwindow)

class OtherWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setObjectName("otherwindow")
        self.resize(250, 250)
        self.button = QtWidgets.QPushButton(self)
        self.button.setGeometry(QtCore.QRect(70, 100, 100, 40))
        self.button.setText('hello')
        self.button.clicked.connect(lambda: self.nothing(1))

    def nothing(self, arg):
        pass

def open_otherwindow():
    global w
    w = OtherWindow()
    w.show()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('Fusion')
    test = Ui_test()
    test.show()
    sys.exit(app.exec_())

Upvotes: 1

Views: 1499

Answers (1)

eyllanesc
eyllanesc

Reputation: 243955

Explanation:

To understand the problem, the following 2 codes and their outputs must be analyzed:

Example1

from PyQt5 import QtCore


if __name__ == "__main__":
    app = QtCore.QCoreApplication([])

    o = QtCore.QObject()
    o.destroyed.connect(lambda: print("destroyed o"))

    o = QtCore.QObject()

    def on_timeout():
        print("quit")
        QtCore.QCoreApplication.quit()

    QtCore.QTimer.singleShot(1000, on_timeout)

    app.exec_()
destroyed o
quit

Example2

from PyQt5 import QtCore


if __name__ == "__main__":
    app = QtCore.QCoreApplication([])

    o = QtCore.QObject()
    o.destroyed.connect(lambda: print("destroyed o"))

    p = o

    o = QtCore.QObject()

    def on_timeout():
        print("quit")
        QtCore.QCoreApplication.quit()

    QtCore.QTimer.singleShot(1000, on_timeout)

    app.exec_()
quit
destroyed o

In the first example, the variable "o" is assigned a QObject and when another QObject is assigned, the initial QObject is deleted, so "destroyed" is printed before "quit".

In the second example, it has the difference "p = o" where reference is made to the QObject, that is, in that line "p" and "o" represent the same object, so by assigning "or" a new QObject the initial QObject is not it destroys, and it is only destroyed when the loop ends and the GC does its job.

That is what happens in your case in a subtle way, the logic of "p = o" is that the QObject is stored in another "place", and in your example that "place" is the lambda that has its own scope ( similarly with partial). Specifically, in your example, a new window was created destroying the previous one, causing a single window to be displayed at all times.

Solution:

One possible solution is to prevent the first window from being removed and a new window created using a flag:

from PyQt5 import QtCore, QtGui, QtWidgets

flag = False

# ...

def open_otherwindow():
    global w, flag
    if not flag:
        w = OtherWindow()
        w.show()
    flag = True

# ...

Upvotes: 1

Related Questions