且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

parentWidget 关闭时浮动 QDockWidget 不会关闭

更新时间:2023-02-17 14:43:01

您可以使用 event-filter 监视给定窗口的所有事件.就在窗口关闭之前,它会总是发布一个关闭事件.窗口是否修改了正常关闭过程并不重要.如果最终关闭,则相应关闭的 accept 属性-event 保证True.所以,如果你关注这个事件,你可以简单地检查它是否被接受,然后采取相应的行动.

You can use an event-filter to monitor all the events of a given window. Just before a window closes, it will always post a close-event. It doesn't matter whether the window has modified the normal closing process or not. If and when it eventually closes, the accept property of the corresponding close-event is guaranteed to be True. So, if you watch for this event, you can simply check to see if it was accepted, and then act accordingly.

要解决的主要问题是如何找到合适的窗口观看.在创建停靠小部件时,这可能无法访问.因此,一种方法是等到首次显示停靠小部件的父级,然后查找***窗口并在其上安装事件过滤器.以这种方式做事意味着停靠小部件永远不需要知道它最终依赖的窗口的任何信息.

The main problem to solve is how to find the right window to watch. At the time the dock-widget is created, this may not be accessible. So one approach is to wait until the parent of the dock-widget is first shown, then look for the top-level window and install an event-filter on that. Doing things this way means the dock-widget never needs to know anything about the window it is ultimately dependant upon.

以下是基于您的示例的此方法的工作演示(删除了大部分不相关的内容):

Below is a working demo of this approach based on your example (with most of the irrelevant stuff removed):

import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QApplication, QDialog, QMainWindow

class EventWatcher(QtCore.QObject):
    def __init__(self, parent):
        QtCore.QObject.__init__(self, parent)
        parent.installEventFilter(self)

    def eventFilter(self, source, event):
        if source is self.parent():
            if event.type() == QtCore.QEvent.Show:
                target = source.parent()
                while target.parent() is not None:
                    target = target.parent()
                print('found target window: %r' % target)
                source.removeEventFilter(self)
                target.installEventFilter(self)
        elif event.type() == QtCore.QEvent.Close:
            source.closeEvent(event)
            print('test filter accepted: %s' % event.isAccepted())
            if event.isAccepted():
                self.parent().close()
            return True
        return QtCore.QObject.eventFilter(self, source, event)

class Ui_MainWindowWithDock(object):
    def setupUi(self, MainWindowWithDock):
        self.theDock = QtGui.QDockWidget(MainWindowWithDock)
        MainWindowWithDock.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.theDock)
        # add the event watcher
        EventWatcher(self.theDock)

class MainWindowWithDockDlg(QMainWindow):
    pass

# mock-up class for testing
class MockDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        windowWithDock = MainWindowWithDockDlg()
        windowWithDockUi = Ui_MainWindowWithDock()
        windowWithDockUi.setupUi(windowWithDock)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(windowWithDock)
        self.canClose = False

    def reject(self):
        if not self.canClose:
            self.canClose = True
            return
        QDialog.reject(self)

    def closeEvent(self, event):
        QDialog.closeEvent(self, event)
        print('test close accepted: %s' % event.isAccepted())

def main():
    app = QApplication(sys.argv)

    dialog = MockDialog()
    dialog.show()
    app.exec_()

    # the dock widget should be closed by now

    window = QMainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()