如何在PyQT中检测父窗口的关闭?

5
我已经创建了一个包含多个其他小部件的QVBoxLayout。当QVBoxLayout的父窗口(当前为QDialog)关闭时,我需要通知所有小部件关闭事件,以便它们可以删除临时文件。这种方法是否符合惯例,我应该如何实现?
在我的应用程序中,我使用一个类对QLabel进行了子类化,使我能够存储构成它的pixMap的临时文件的引用。当其父窗口关闭时,我需要能够关闭该文件。
编辑:我已经尝试处理关闭事件:
def closeEvent(self, event):
    self.imgFile.close()

重写父窗口小部件的CloseEvent以发出信号,并将该信号连接到子窗口小部件中执行清理操作的函数。 - tacaswell
1个回答

3
以下是几种使用Qt惯用语实现此目的的方法:
1. 在父类的closeEvent中直接对每个子类执行清理操作。 2. 在父类的destroyed信号中调用每个子类的清理操作(间接实现)。 3. 在父类的closeEvent中发出自定义信号,将其直接连接到子类的清理操作。
选项#2/#3在下面被注释掉了。
from PyQt4 import QtCore, QtGui


class MainWidget(QtGui.QDialog):

    # Option #3 - Custom signal
    closing = QtCore.pyqtSignal()

    def __init__(self):
        super(MainWidget, self).__init__()

        self.layout = QtGui.QVBoxLayout(self)

        for i in xrange(5):
            label = ResourceLabel('label%02d' % i)
            self.layout.addWidget(label)

            # option #2
            # Let a signal trigger the cleanup on the children
            # self.destroyed.connect(label.close)

            # option #3
            # Use a custom signal emitted from the closeEvent,
            # wired directly to the cleanup slot on the object
            # self.closing.connect(label.close)

    def closeEvent(self, event):
        print "Closing main window"

        # option #1
        # if you want to trigger a cleanup specifically when
        # this widget is closed, as opposed to destroyed
        for i in xrange(self.layout.count()):
            item = self.layout.itemAt(i)
            widget = item.widget()       
            if widget:
                try:
                    widget.close()
                except:
                    pass

        # Or Option #3 - emit a custom signal
        self.closing.emit()

        super(MainWidget, self).closeEvent(event)


class ResourceLabel(QtGui.QLabel):

    def __init__(self, *args, **kwargs):
        super(ResourceLabel, self).__init__(*args, **kwargs)
        self.aResource = "FOO"

    def close(self):
        print "Cleaning up", self
        self.aResource = None


if __name__ == "__main__":
    app = QtGui.QApplication([])
    win = MainWidget()
    win.show()
    win.raise_()
    app.exec_()

任何一种都可以。我更喜欢选项#2,因为它让父窗口保持一定程度的不知道其子组件,并且只是在它们构建时将它们连接到将清理它们的插槽。
选项#3的原因是基于你在下面留言中提到的。在你发布的代码中,我的猜测是你的对话框根本没有被删除。它仍然存在,只是被关闭了。所以选项3在closeEvent中放置了一个自定义信号,模拟了如果正在删除它,destroyed信号会执行什么操作。

1
选项#2对我没用。我从未收到销毁信号。 - liamzebedee
你能在这里Pastebin你的代码,这样我就可以看一下吗?我的例子应该没问题。 - jdi
https://github.com/liamzebedee/misc/blob/master/gimg/gimg.py#L81 是我使用这个的那一行。 - liamzebedee
从您的代码中看来,似乎您并没有真正让对话框被销毁,因为您将其父级设置为另一个小部件。即使Python对象超出范围,该对象仍然存在,可能只是被隐藏而不是被销毁(我猜测)。您可能需要第三个选项,我会更新我的答案。 - jdi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接