Pyside uiLoader 捕获关闭事件信号

Posted

技术标签:

【中文标题】Pyside uiLoader 捕获关闭事件信号【英文标题】:Pyside uiLoader capture close event signals 【发布时间】:2018-10-10 19:10:26 【问题描述】:

如何正确捕获来自 PySide QtUiTools.QUiLoader() 设置的关闭事件?

我可以让实例化类连接到小部件和其他所有东西,但我不确定如何在此设置中拦截信号。

理想情况下,我希望所有关闭调用都通过我的 closeEvent(显然),以便我可以确保关闭窗口是安全的。但是由于我的 self.closeEvent() 与我的 View(QtWidgets.QMainWindow) 而不是 self._qt.closeEvent() 相关联,所以我不知道如何使用 self._qt.closeEvent() 方法来覆盖它在这种情况下。

或者有没有更好的方法来设置它来捕获那些窗口事件?

# Compatible enough with Pyside 2
from PySide import QtGui as QtWidgets
from PySide import QtUiTools
from PySide import QtCore

class View(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(View, self).__init__(parent=parent)
        self.setup()

    def closeEvent(self, event):

        # Do things
        event.accept()

    def setup(self):
        loader = QtUiTools.QUiLoader()
        fy = QtCore.QFile('example.ui')
        fy.open(QtCore.QFile.ReadOnly)
        self._qt = loader.load(fy, self)
        fy.close()

        self._qt.pCanceled.clicked(self._qt.close)

不适用:

PySide / PyQt detect if user trying to close window

关闭,但 PySide 不使用 PyQt 的 uic 并且似乎运行方式不同(并且没有工作):

PyQt: clicking X doesn't trigger closeEvent

【问题讨论】:

【参考方案1】:

closeEvent 不是信号,它是在发送QCloseEvent 事件时调用的方法。信号和事件是不同的东西。直奔问题,在 Qt 中有两种监听事件的方法,第一种是覆盖 fooEvent() 方法,第二种是使用事件过滤器,如下所示:

from PySide import QtGui as QtWidgets
from PySide import QtUiTools
from PySide import QtCore

class View(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(View, self).__init__(parent=parent)
        self._qt = None
        self.setup()

    def closeEvent(self, event):
        self.do_things()
        super(View, self).closeEvent(event)

    def do_things(self):
        print("do_things")

    def setup(self):
        loader = QtUiTools.QUiLoader()
        fy = QtCore.QFile('example.ui')
        fy.open(QtCore.QFile.ReadOnly)
        self._qt = loader.load(fy, self)
        fy.close()
        self._qt.pCanceled.clicked.connect(self._qt.close)
        self._qt.installEventFilter(self)

    def eventFilter(self, watched, event):
        if watched is self._qt and event.type() == QtCore.QEvent.Close:
            self.do_things()
        return super(View, self).eventFilter(watched, event)


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = View()
    w.show()
    sys.exit(app.exec_())

更新:

通常在eventFilter 中返回 True 即可忽略事件,但在 QCloseEvent 的情况下,您必须忽略该事件并返回 True,如下所示:

def eventFilter(self, watched, event):
    if watched is self._qt and event.type() == QtCore.QEvent.Close:
        self.do_things()
        event.ignore()
        return True
    return super(View, self).eventFilter(watched, event)

【讨论】:

这绝对有帮助,虽然如果确定窗口还不能关闭,我不能通过事件过滤器忽略该事件。这个阶段还有可能吗?通常,重写的 closeEvent 方法会处理这个问题,在这里我们只是捕获事件。 @ooklah 试试我的解决方案。 是的,这就是我想要的,我可以根据需要进行调整。

以上是关于Pyside uiLoader 捕获关闭事件信号的主要内容,如果未能解决你的问题,请参考以下文章

[No000090]C#捕获控制台(console)关闭事件及响应cmd快捷键

pyside窗口关闭触发事件

发送/捕获 SIGTERM 的 Win32 API 模拟

如何在 UILoader 中添加两个 UILoader 并使用 actionscript 3 保存 UILoader 的内容

Pyside (Qt) - 如何查询信号

带信号/插槽的 PySide IPC