【问题标题】:Execute a function after closing a window (not a child window)?关闭窗口(不是子窗口)后执行函数?
【发布时间】:2021-05-13 20:51:07
【问题描述】:

我的应用程序中有一个按钮,点击后会打开另一个窗口(这是一个单独的 python 文件)。

我想在第二个窗口关闭后执行一个函数。有没有办法可以捕获该窗口的“关闭”信号或类似的信号?

这是我的代码:(主窗口)

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore    import Qt
from PyQt5.QtGui     import QPainter, QColor
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton
import second_dialog  # the second window I am importing

from sys import exit as sysExit

class Marker(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.resize(350, 250)
        self.openbtn = QPushButton('open')
        self.openbtn.clicked.connect(self.open_dialog)
        self.label_1 = QtWidgets.QLabel()
        self.label_1.setGeometry(QtCore.QRect(10, 20, 150, 31))
        self.label_1.setObjectName("label_1")
        self.label_1.setText("HEy")

        HBox = QHBoxLayout()
        HBox.addWidget(self.openbtn)
        HBox.addWidget(self.label_1)
        HBox.addStretch(1)

        VBox = QVBoxLayout()
        VBox.addLayout(HBox)
        VBox.addStretch(1)

        self.setLayout(VBox)
      
    def open_dialog(self):
        self.dialog = QtWidgets.QWidget()
        self.box = second_dialog.Marker()
        self.box.show()
        

    def do_something(self):
        self.label_1.setText("Closed")
    
    def paintEvent(self, event):
        p = QPainter(self)
        p.fillRect(self.rect(), QColor(128, 128, 128, 128))
      
if __name__ == "__main__":
    MainEventThred = QApplication([])

    MainApp = Marker()
    MainApp.show()

    MainEventThred.exec()

这是第二个窗口的代码:

from PyQt5 import QtWidgets
from PyQt5.QtCore    import Qt
from PyQt5.QtGui     import QPainter, QColor
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtWidgets import QPushButton
import first_window

from sys import exit as sysExit

class Marker(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.resize(350, 250)
        self.openbtn = QPushButton('close')
        self.openbtn.clicked.connect(self.Close)

        HBox = QHBoxLayout()
        HBox.addWidget(self.openbtn)
        HBox.addStretch(1)

        VBox = QVBoxLayout()
        VBox.addLayout(HBox)
        VBox.addStretch(1)

        self.setLayout(VBox)
      
    def Close(self):
        TEST_draggable.Marker.do_something(first_window.Marker)
        self.close()
        

    def paintEvent(self, event):
        p = QPainter(self)
        p.fillRect(self.rect(), QColor(128, 128, 128, 128))
      
if __name__ == "__main__":
    MainEventThred = QApplication([])

    MainApp = Marker()
    MainApp.show()

    MainEventThred.exec()

代码没有运行并抛出此错误:

Traceback (most recent call last):
  File "some/path/second_dialog.py", line 28, in Close
    TEST_draggable.Marker.do_something(first_window.Marker)
  File "some/path/first_window.py", line 39, in do_something
    self.label_1.setText("clicked")
AttributeError: type object 'Marker' has no attribute 'label_1'
[1]    7552 abort (core dumped)  /usr/local/bin/python3 

我该如何解决这个问题?我查了很多论坛怀疑循环进口是罪魁祸首,但我不确定。请帮忙。

【问题讨论】:

    标签: python pyqt pyqt5


    【解决方案1】:

    问题与导入无关,而是因为您尝试在 class 上运行 instance 方法。

    “罪魁祸首”在这里:

    TEST_draggable.Marker.do_something(first_window.Marker)
    

    first_window.Marker 将用于do_something 中的self 参数,但由于它是类,它没有label_1 属性(只有该类的实例具有该属性)。我建议你研究一下类和实例的一般工作原理,以及如何在 Python 中处理它们。

    最简单的解决方案是为第二个窗口创建自己的信号,并将该信号连接到将“做某事”的函数上。然后,我们没有连接到新函数,而是将closeEvent() 子类化并从那里发送信号,这样即使用户单击标题栏上的专用按钮,我们也可以捕获关闭。请注意,如果您想更改 close 的行为,您可以覆盖它,然后调用基本实现 (super().close()),而不是使用另一个函数名称(不应使用大写的名称,顺便说一下,因为它们应该只用于类和常量)。

    这是第二类;请注意,为不同的类使用相同的名称是一个非常糟糕的主意。

    from PyQt5.QtCore import pyqtSignal
    
    class Marker(QWidget):
        closed = pyqtSignal()
        def __init__(self):
            QWidget.__init__(self)
            self.resize(350, 250)
            self.openbtn = QPushButton('close')
            self.openbtn.clicked.connect(self.close)
            # ...
    
        def closeEvent(self, event):
            self.closed.emit()
    

    然后,在第一个:

    class Marker(QWidget):
        # ...
        def open_dialog(self):
            self.dialog = QtWidgets.QWidget()
            self.box = second_dialog.Marker()
            self.box.closed.connect(self.do_something)
            self.box.show()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 1970-01-01
      • 2014-03-14
      • 2013-02-14
      相关资源
      最近更新 更多