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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:50:34