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
相关产品推荐
相关产品推荐

