QMdiSubWindow跨QMdiArea移动时QQuickWidget内容消失问题
问题描述
我正在开发一款包含多个QMdiSubWindow的应用,每个子窗口内都包含QQuickWidget,支持在不同QMdiArea间移动。创建子窗口时QML内容能正常显示,但调用set_area()将其移动到新QMdiArea后,QQuickWidget内容变为空白。测试用的QML组件仅包含一个彩色矩形,尝试按照构造函数的方式重新设置QML对象的父项到contentItem时会触发段错误。
相关代码
// Constructor MySubWindow::MySubWindow(QQmlComponent* qml_component, QQmlEngine* engine, QWidget* parent, Qt::WindowFlags flags) : QMdiSubWindow(parent, flags) { // Add to MDI area initial_area->addSubWindow(this); // Create child QML widget auto* qml_widget = new QQuickWidget(engine, this); setWidget(qml_widget); // Add QML content auto* qml_obj = qobject_cast<QQuickItem*>(qml_component->create(engine->rootContext())); auto* root_item = qml_widget->quickWindow()->contentItem(); qml_obj->setParent(root_item); qml_obj->setParentItem(root_item); // Show subwindow showMaximized(); } // Move subwindow to a new MDI area void MySubWindow::set_area(QMdiArea* new_area) { mdiArea()->removeSubWindow(this); new_area->addSubWindow(this); showMaximized(); }
解决方案
QMdiSubWindow移动时,QQuickWidget的quickWindow()可能会失效或重新创建,导致原QML对象的父项关联断裂。以下是可行的修复方案:
方案1:保存引用并重新绑定QML对象
- 在MySubWindow类中添加成员变量保存关键对象指针:
private: QQuickWidget* m_qml_widget = nullptr; QQuickItem* m_qml_obj = nullptr; - 构造函数中初始化这两个变量:
m_qml_widget = new QQuickWidget(engine, this); setWidget(m_qml_widget); ... m_qml_obj = qobject_cast<QQuickItem*>(qml_component->create(engine->rootContext())); auto* root_item = m_qml_widget->quickWindow()->contentItem(); m_qml_obj->setParent(root_item); m_qml_obj->setParentItem(root_item); ... - 修改
set_area()方法,移动后重新绑定QML对象:void MySubWindow::set_area(QMdiArea* new_area) { mdiArea()->removeSubWindow(this); new_area->addSubWindow(this); // 确保QQuickWidget完成窗口重建 m_qml_widget->ensurePolished(); if (auto* new_root = m_qml_widget->quickWindow()->contentItem()) { // 先解除原关联 m_qml_obj->setParentItem(nullptr); m_qml_obj->setParent(nullptr); // 重新绑定到新的contentItem m_qml_obj->setParent(new_root); m_qml_obj->setParentItem(new_root); // 强制刷新界面 m_qml_obj->forceActiveFocus(); m_qml_widget->update(); } showMaximized(); }
方案2:改用QQuickWidget内置方法加载QML
避免手动管理QML对象的父项,改用setSource()或setContent()方法加载QML,Qt会自动处理生命周期和关联:
// 构造函数中替换原QML对象创建逻辑 // 方式1:加载本地QML文件 m_qml_widget->setSource(QUrl::fromLocalFile("path/to/your.qml")); // 方式2:从已有的QQmlComponent加载 m_qml_widget->setContent(qml_component->url(), qml_component, nullptr);
这种方法稳定性更高,推荐优先使用。
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

