📜 ⬆️ ⬇️

How to make QML friends with someone else's OpenGL context. Part II: Loading QML

In this article I will try to talk about how to load QML in case you, for some reason, do not have the ability to use QQuickView , but need to work directly with QQuickWindow .
In my case, the reason was that only QQuickWindow can work with QQuickRenderControl. In your case, such a reason could be for example the fact that you needed to download QML not from any file, but for example from memory, which opens up the possibility of generating QML on the fly, or querying the contents of QML, or part of it, from the user interesting, right?

In case you did not read the beginning: Part I is available at this link .

In fact, in the task, there is practically nothing complicated, it is enough to carefully read the documentation or look at the source QQuickView.

So, everything in order


The first thing we need is QQmlEngine :
')
QQmlEngine* qmlEngine = new QQmlEngine; 

Next, we need QQmlComponent - it is with its help that QML is loaded. Its important feature is that, depending on the source of QML, the QQmlComponent can load it both synchronously and asynchronously.

You can handle this as follows (this is the code used in QQuickView):

  const QUrl source = QStringLiteral( "http://example.com/main.qml" ); qmlComponent = new QQmlComponent( &qmlEngine, source ); if( qmlComponent->isLoading() ) connect( qmlComponent, &QQmlComponent::statusChanged, componentStatusChanged ); else componentStatusChanged( qmlComponent->status() ); 

but personally, I am more impressed with this implementation:

  const QUrl source = QStringLiteral( "http://example.com/main.qml" ); qmlComponent = new QQmlComponent( qmlEngine ); connect( qmlComponent, &QQmlComponent::statusChanged, componentStatusChanged ); qmlComponent->loadUrl( source ); 

Since in this case, synchronous and asynchronous downloads are processed identically (and fewer branches in the code, fewer reasons for error).

If you need to load QML from QString, the code will look like this:

  const QUrl qmlUrl = QStringLiteral( "http://example.com/main.qml" ); const QString qml = QStringLiteral( "import QtQuick 2.0; Rectangle { color: 'green'; }" ); qmlComponent = new QQmlComponent( qmlEngine ); connect( qmlComponent, &QQmlComponent::statusChanged, componentStatusChanged ); qmlComponent->setData( qml.toUtf8(), qmlUrl ); 

In this case, although QML is loaded from a string, you can specify the URL with which this QML will be associated. This is necessary if any external elements are used in the QML text (links to other QML components or files), which will be searched for relative to the transferred URL.

Well, we just need to process the download result:

 void componentStatusChanged( QQmlComponent::Status status ) { Q_ASSERT( !m_rootItem ); if( QQmlComponent::Ready != status ) { return; } QObject* rootObject = qmlComponent->create(); QQuickItem* rootItem = qobject_cast<QQuickItem*>( rootObject ); if( !rootItem ) { return; } rootItem->setParentItem( quickWindow->contentItem() ); rootItem->setSize( QSizeF( quickWindow->width(), quickWindow->height() ) ); } 

Important note: in the above code, both object ownership and error handling are deliberately completely ignored.

Actually it was all that was necessary to solve the second part of the original problem .

The class that implements the above concept, as usual, is available on GitHub: FboQuickView.h , FboQuickView.cpp
Well, as before, comments, questions, healthy criticism are welcome.

Continued: Part III: Processing User Input

Source: https://habr.com/ru/post/248103/


All Articles