Search code examples
c++qtqmlqqmlcomponentqmdiarea

QQuickWidget's content disappears when parent's parent changes


I'm trying to build an application consisting of multiple QMdiSubWindows that each contain a QQuickWidget and can be moved between different QMdiAreas. I'm able to create subwindows and display QML content inside them, but this content disappears when the subwindow is moved to a new MDI area. Example code follows.

// 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();
}

I'm using a simple QML component that contains a colored rectangle to test. I can see the rectangle when MySubWindow is created, but I get a blank white window after set_area() is called. I've tried to reparent my QML object after the move to contentItem like shown in the constructor, but this causes a segfault. Any thoughts?


Solution

  • I'm not sure why, but I was able to fix the issue by switching from QQuickWidget to QQuickView. The modified code follows:

    // 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_view = new QQuickView();
      auto* qml_widget = QWidget::createWindowContainer(qml_view, this);
      setWidget(qml_widget);
    
      // Add QML content
      auto* qml_obj = qobject_cast<QQuickItem*>(qml_component->create(engine->rootContext()));
    
      auto* root_item = qml_view->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();
    }