PyQt5: несколько экземпляров одного и того же окна - PullRequest
1 голос
/ 10 марта 2020

У меня проблема с pyqt5. У меня есть этот кусок кода для создания экземпляра моего класса и открытия моего окна без закрытия после метода show (потому что g c).

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

это работает хорошо, но в классе TCrudUsuario у меня есть некоторые кнопки, которые подключаются к методу с аргументами, поэтому я использую лямбду (пробовал с частичным, но такая же проблема возникает), примерно так:

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

проблема в том, что если я использую лямбду или частично, чтобы подключиться к моему методу manage_user () , он позволяет мне открывать несколько экземпляров класса TCrudUsuario, открывая два или более windows. но, если я удаляю метод подключения, он открывает только 1 окно. Моя цель - разрешить только один экземпляр / одно окно. Кто-нибудь знает, почему это происходит?

Воспроизводимый код:

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 Ответ

1 голос
/ 11 марта 2020

Объяснение:

Чтобы понять проблему, необходимо проанализировать следующие 2 кода и их выходные данные:

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

В первом примере переменной "o" назначается объект QObject, а когда назначается другой объект QObject, исходный объект QObject удаляется, поэтому " destroy "печатается перед" quit ".

Во втором примере он имеет разницу" p = o ", когда делается ссылка на QObject, то есть в этой строке" p "и" o " представляют один и тот же объект, поэтому, присваивая "или" новый QObject, исходный QObject не уничтожается, а уничтожается только тогда, когда заканчивается l oop и G C выполняет свою работу.

Это то, что происходит в вашем случае тонким способом, логика c из "p = o" заключается в том, что объект QObject хранится в другом "месте", а в вашем примере это "место" - это лямбда, которая имеет свою собственную сфера (аналогично с частичной). В частности, в вашем примере было создано новое окно, разрушающее предыдущее, в результате чего все время отображается одно окно.

Решение:

Одним из возможных решений является предотвращение первого окна от удаления и создания нового окна с использованием флага:

from PyQt5 import QtCore, QtGui, QtWidgets

<b>flag = False</b>

# ...

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

# ...
...