Qt Weekly #16: QQuickWidget

Combining Qt Quick 2 scenes with traditional QWidget-based user interfaces is a good path to choose if you want to transition your exisiting application to use more of the cool new functionality that Qt Quick provides. While Qt 5.2 introduced QWidget::createWindowContainer() for embedding native windows as a regular widget, a number of limitations remained: Most notably the inability to have a well-defined stacking order and various surprises regarding focus handling, drag and drop, etc., depending on the platform.

Such issues may sound familiar also to those who are working with the good old QGLWidget. It seems to work fine - until it becomes part of a more complex UI, gets added to scroll and MDI areas, and gets combined with overlapping widgets. At that point unexpected issues, like painting problems, artifacts and broken input, start to surface. The fact that such widgets are in practice native windows - and turn their ancestors and siblings native too - is hidden from the developer, even though this has consequences.

On Embedded Linux or Android devices that run without a windowing system, using the eglfs platform plugin, the situation is even less ideal: Combining a QQuickWindow or QGLWidget with other widgets will simply abort the application because there is no support for creating multiple, non-fullscreen native windows and surfaces. For plain QWidget windows, that are fully rendered in software, this is not an issue since they can easily be composed and blitted onto the single window surface covering the entire screen. However for OpenGL-based windows there is no workaround.

To overcome all this, a set of new widgets are being introduced. The first in the series is QQuickWidget, introduced in Qt 5.3.

As the name suggests, this, as opposed to QQuickWindow and its convenience wrapper QQuickView, is a regular QWidget-derived class. Unlike QGLWidget, it carries no surprises: this is like a normal widget, no native windows will get created behind your back. This comes at a minor cost of course: the OpenGL rendering of the Qt Quick scene is done into a framebuffer object. The compositing is handled transparently by the widget stack.

Speaking of transparency, QQuickWidget retains one limitation: Placing other widgets underneath it and making the QQuickWidget (semi-)transparent will not lead to the expected result. On the bright side, putting widgets on top will function as expected, as will everything else. To demonstrate this, consider the little example that is going to be added to Qt 5.3.2:

First, let's try using a QQuickView. The application uses regular widgets, with the QQuickView being embedded via QWidget::createWindowContainer(). This, besides not working at all on embedded, has the unfortunate consequence of not being able to show a semi-transparent overlay widget on top.

The code to create the QQuickView is the following:

    QQuickView *quickView = new QQuickView;
    quickView->setResizeMode(QQuickView::SizeRootObjectToView);
    connect(quickView, &QQuickView::statusChanged, this, &MainWindow::onStatusChangedView);
    connect(quickView, &QQuickView::sceneGraphError, this, &MainWindow::onSceneGraphError);
    quickView->setSource(source);
    m_layout->addWidget(QWidget::createWindowContainer(quickView));

 

qqw_ex_qquickview
This does not look quite correct.
Now let's switch to QQuickWidget.

The code is very similar. The QQuickWidget API mirrors QQuickView. createWindowContainer() is not needed anymore since QQuickWidget is a plain old QWidget.

    QQuickWidget *quickWidget = new QQuickWidget;
    quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
    connect(quickWidget, &QQuickWidget::statusChanged, this, &MainWindow::onStatusChangedWidget);
    connect(quickWidget, &QQuickWidget::sceneGraphError, this, &MainWindow::onSceneGraphError);
    quickWidget->setSource(source);
    m_layout->addWidget(quickWidget);

 

qqw_ex_qquickwidget
This looks much better. And works on embedded too!
To summarize:

  • Use QQuickWidget when the Qt Quick content is embedded into a widget UI or when there is a need to place widgets on top. The more complex the interface gets, the bigger the chance of encountering issues with native child windows becomes. Hence the general recommendation is to always use QQuickWidget in widget-based applications.
  • Use a standalone QQuickWindow or QQuickView when widgets are not needed and maximum performance is desired. On desktop platforms applications are of course free to open additional widget-based top-level windows when necessary.
  • Never use QWidget::createWindowContainer().
    (Well, unless there is a very good reason for using it and you know what you are doing. If the stacking and other limitations do not apply and the application is targeting desktop platforms only and the platform in question is able to use the Qt Quick Scenegraph's threaded render loop, then having a QQuickView embedded via createWindowContainer() will always lead to better performance when compared to QQuickWidget)

Future Qt versions are likely to bring similar new classes, first and foremost a modern replacement for QGLWidget, so stay tuned.

Summer time is upon us here in the northern hemisphere. The Qt Weekly blog post series will therefore take a few weeks vacation. See you back in fall!


Comments