You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt(PySide6):QMdiSubWindow点击X不触发closeEvent且未销毁

MDI子窗口closeEvent不触发及对象未销毁问题解决

问题根源

你定义的closeEvent属于ExampleWindow类,但MDI区域中实际响应用户关闭操作的是QMdiSubWindow容器,而非作为其widget的ExampleWindow。此外,Qt默认设置下,QMdiSubWindow点击关闭仅会隐藏窗口,不会销毁对象,因此destroyed信号也不会触发。

解决方案

方案1:给QMdiSubWindow安装事件过滤器

在ExampleWindow中捕获QMdiSubWindow的关闭事件,同时设置关闭时销毁对象:

from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtWidgets import QMainWindow, QMdiSubWindow

class ExampleWindow(QMainWindow):
    def __init__(self, parent):
        super(ExampleWindow, self).__init__(parent)

        self.parent_window = parent
        self.ui = self.parent_window.loader.load("Code/UI/example.ui", None)
        self.ui.setWindowTitle("ExampleTitle")
        self.example_subwindow = None

    def loadWindow(self):
        self.example_subwindow = QMdiSubWindow()
        self.example_subwindow.setWidget(self.ui)
        self.parent_window.ui.mdiArea.addSubWindow(self.example_subwindow)
        # 为子窗口安装事件过滤器
        self.example_subwindow.installEventFilter(self)
        self.example_subwindow.show()
    
    def eventFilter(self, obj, event):
        if obj == self.example_subwindow and event.type() == QEvent.Close:
            # 在这里执行销毁前的操作
            print("执行关闭前的清理逻辑")
            # 设置关闭时自动销毁对象
            self.example_subwindow.setAttribute(Qt.WA_DeleteOnClose)
            event.accept()
            return True
        return super().eventFilter(obj, event)

方案2:自定义QMdiSubWindow子类并重写closeEvent

创建继承自QMdiSubWindow的子类,在其中重写关闭事件:

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QMdiSubWindow

class CustomMdiSubWindow(QMdiSubWindow):
    def closeEvent(self, event):
        # 执行关闭前的操作
        print("自定义子窗口关闭前的处理")
        # 开启关闭销毁属性
        self.setAttribute(Qt.WA_DeleteOnClose)
        event.accept()

class ExampleWindow(QMainWindow):
    def __init__(self, parent):
        super(ExampleWindow, self).__init__(parent)

        self.parent_window = parent
        self.ui = self.parent_window.loader.load("Code/UI/example.ui", None)
        self.ui.setWindowTitle("ExampleTitle")

    def loadWindow(self):
        self.example_subwindow = CustomMdiSubWindow()
        self.example_subwindow.setWidget(self.ui)
        self.parent_window.ui.mdiArea.addSubWindow(self.example_subwindow)
        self.example_subwindow.show()

方案3:绑定destroyed信号(需先开启销毁属性)

通过设置WA_DeleteOnClose让窗口关闭时销毁,再绑定destroyed信号执行后续操作:

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QMdiSubWindow

class ExampleWindow(QMainWindow):
    def __init__(self, parent):
        super(ExampleWindow, self).__init__(parent)

        self.parent_window = parent
        self.ui = self.parent_window.loader.load("Code/UI/example.ui", None)
        self.ui.setWindowTitle("ExampleTitle")

    def on_subwindow_destroyed(self):
        # 窗口销毁时执行的操作
        print("子窗口已销毁,执行清理")

    def loadWindow(self):
        self.example_subwindow = QMdiSubWindow()
        self.example_subwindow.setWidget(self.ui)
        self.parent_window.ui.mdiArea.addSubWindow(self.example_subwindow)
        # 开启关闭自动销毁
        self.example_subwindow.setAttribute(Qt.WA_DeleteOnClose)
        # 绑定销毁信号
        self.example_subwindow.destroyed.connect(self.on_subwindow_destroyed)
        self.example_subwindow.show()

关键说明

  • 必须设置Qt.WA_DeleteOnClose属性,否则QMdiSubWindow关闭后仅隐藏,不会触发对象销毁。
  • 关闭事件的处理目标是QMdiSubWindow容器,而非其内部的widget,因此需要针对容器类处理事件。

内容的提问来源于stack exchange,提问作者phill_c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:33:34