Qt Weekly #16: QQuickWidget

Published Wednesday July 2nd, 2014 | by

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!

Did you like this? Share it:

Posted in Uncategorized

9 comments to Qt Weekly #16: QQuickWidget

Joni says:

My only question is that does this stuff will work on OpenGL 2.1 and OpenGL ES 2 hardware ?
If not, we still regret this limitation

Laszlo Agocs says:

Yes, of course. The baseline for all OpenGL support remains OpenGL ES 2.0.

Tannin says:

>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.

So we can not have a transparent QQuickWidget overlay on top of “regular” widgets. Is there some way to achieve this behaviour? I used such a widget in qt 4.8 (quick 1.1) and this may be the biggest problem stopping me from switching to qt 5…

Laszlo Agocs says:

No, not at the moment. It could be supported through an opt-in mechanism on a per-widget basis. Such QQuickWidgets would then always stack on top, making it impossible to have other widgets on top of them, but at least making them semi-transparent would lead to the desired overlay effect. See QTBUG-40086.

In the meantime, assuming you are on one of the desktop platforms, you could still use createWindowContainer() with an alpha-enabled QQuickView.

Tannin says:

Thank you for the quick reply. Yes, I’m on windows, but I still can’t get this to work.
This is what I have:


m_TutorialView = new QQuickView();
m_TutorialView->setFlags(Qt::FramelessWindowHint);
m_TutorialView->setResizeMode(QQuickView::SizeRootObjectToView);

m_TutorialView->setOpacity(0.999);
m_TutorialView->setColor(Qt::transparent);

m_TutorialWidget = QWidget::createWindowContainer(m_TutorialView, m_TargetControl);
m_TutorialWidget->setStyleSheet(QString("background: transparent"));
m_TutorialWidget->setAttribute(Qt::WA_TranslucentBackground);

The view itself is transparent if I leave it as a separate window, but contained in the widget it still has a black background.
What am I doing wrong?

Laszlo Agocs says:

The setFlags, setStyleSheet, setAttribute, setOpacity calls are not necessary. What you need is setColor and a context/surface format with alpha enabled.

So either call QQuickView::setDefaultAlphaBuffer(true) before creating the QQuickView, or alternatively do something like

QSurfaceFormat format;
format.setAlphaBufferSize(8);
m_TutorialView->setFormat(format);

to have alpha enabled for that particular window only.

Tannin says:

Still doesn’t work. :(


m_TutorialView = new QQuickView();
m_TutorialView->setResizeMode(QQuickView::SizeRootObjectToView);
QSurfaceFormat format;
format.setAlphaBufferSize(8);
m_TutorialView->setFormat(format);
m_TutorialView->setColor(Qt::transparent);
m_TutorialWidget = QWidget::createWindowContainer(m_TutorialView, m_TargetControl);

Background is still all black.

Laszlo Agocs says:

Then we are hitting some limitation with child windows. Is this Windows 7? Just wondering since WS_EX_LAYERED is only supported for top-level windows before Windows 8.

Sebastian says:

Yes, Windows 7. Sorry if this is a stupid question, but what is a child window in this context?
The m_TargetControl is a top-level QDialog lives directly inside the top-level dialog, alongside the other widgets. It’s not an MDI application.

What confuses me is that this worked with qt 4 using a qdeclarativeview, so it’s not a windows problem but something that changed between qt4 and qt5, probably the fact that qml is now rendered with opengl instead of a software rasterizer.

The QuickView is also transparent if I don’t turn it into a widget (i.e. i create the quickview with the m_TargetControl->windowHandle() as the parent window)

Commenting closed.