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

PySide6 QML应用重写QMainWindow的closeEvent未触发问题求助

问题根因

事件不触发的核心原因是混用了两套完全独立的Qt窗口体系,代码逻辑和实际显示的窗口没有绑定关系:

  • 定义的DetectQuit类继承自QMainWindow,属于Qt Widgets模块的窗口类,只有当这个Widgets类自身实例化的窗口被显示、接收窗口系统调度的事件时,重写的closeEvent、hideEvent才会被调用。
  • 通过QQmlApplicationEngine加载的QMLWindow属于Qt Quick模块的独立渲染窗口,和实例化的DetectQuit对象没有任何归属关系——只是把这个对象作为上下文属性暴露给QML层访问,它既不是QML窗口的封装类,也接收不到QML窗口的任何生命周期事件。
  • 构造函数加self.show()后弹出的第二个窗口,本质是把DetectQuit对应的Widgets窗口单独显示出来了,所以这个独立窗口的事件可以正常触发,和看到的QML黑色主窗口完全无关。
  • 额外代码问题:DetectQuit类中重复定义了两次closeEvent方法,Python中后定义的同名方法会直接覆盖前一个,就算事件正常触发,调用父类默认实现的逻辑也不会生效。
解决方案

根据选用的界面技术栈二选一即可:

方案1:保留QML界面,监听对应生命周期信号

如果主界面用QML开发,不需要继承QMainWindow,直接通过Qt提供的信号绑定退出逻辑即可,修改后的代码如下:
Main.py

# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys

from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtCore import QObject, Slot

class Backend(QObject):
    def __init__(self):
        super().__init__()
        print("From Constructor")
    
    @Slot()
    def on_app_quit(self):
        # 此处写入应用退出时需要执行的自定义逻辑
        print("Exiting Application")
    
    @Slot()
    def on_window_hide(self):
        # 此处写入窗口隐藏/最小化时需要执行的自定义逻辑
        print("Minimizing Application")

if __name__ == "__main__":
    # 纯Qt Quick项目用QGuiApplication即可,无需引入Widgets模块的QApplication
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    backend = Backend()
    engine.rootContext().setContextProperty("backend", backend)
    
    # 绑定应用全局退出信号
    app.aboutToQuit.connect(backend.on_app_quit)

    qml_path = os.fspath(Path(__file__).resolve().parent / "main.qml")
    engine.load(qml_path)
    if not engine.rootObjects():
        sys.exit(-1)
    
    # 绑定QML根窗口的显示状态变化信号
    root_window = engine.rootObjects()[0]
    root_window.visibleChanged.connect(
        lambda: backend.on_window_hide() if not root_window.visible else None
    )
    
    sys.exit(app.exec())

Main.qml

import QtQuick
import QtQuick.Window

Window {
    id: mainwindow
    width: 640
    height: 480
    visible: true
    color: "#000000"
    flags: Qt.Window
    title: qsTr("Hello World")

    // 如果需要在关闭前拦截逻辑(比如弹出保存确认),可以添加以下代码
    // onClosing: {
    //     // 调用后端校验逻辑,根据返回值决定是否取消关闭
    //     // close.accepted = backend.checkCanQuit()
    // }
}

方案2:保留QMainWindow事件重写逻辑

如果需要依赖QMainWindow的事件重写机制,就不要用QQmlApplicationEngine加载独立的QML窗口,改用QQuickWidget把QML内容嵌入到QMainWindow的中心区域,此时DetectQuit作为顶层主窗口,重写的各类事件方法就可以正常触发。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 16:27:21