PyQt5: multiple instances of same window

扶醉桌前 提交于 2020-05-16 07:00:10

问题


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

回答1:


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

# ...


来源:https://stackoverflow.com/questions/61695268/return-to-main-window-from-second-window

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!