- PVSM.RU - https://www.pvsm.ru -

Как подружить QML с чужим OpenGL контекстом. Часть II: Загружаем QML

В данной статье я попытаюсь рассказать о том как загружать QML в случае, если у вас, по какой-то причине, нет возможности использовать QQuickView [1], а необходимо работать непосредственно с QQuickWindow [2].
В моем случае, таковой причиной являлось то, что с QQuickRenderControl [3] умеет работать только QQuickWindow. В вашем же случае, таковой причиной может быть например то, что вам понадобилось загружать QML не из какого либо файла, а например из памяти, что открывает возможность генерации QML «на лету», или запроса содержимого QML, или его части, у пользователя — занятно, не так ли?

На случай если вы не читали начало: Часть I доступна по данной ссылке [4].

На самом деле, в поставленной задаче, нет практически ничего сложного, достаточно внимательно почитать документацию или же заглянуть в исходники QQuickView.

Итак, обо всем, по порядку

Первое что нам потребуется, это QQmlEngine [5]:

    QQmlEngine* qmlEngine = new QQmlEngine;

Далее нам нужен QQmlComponent [6] — именно с его помощью осуществляется загрузка QML. Важной его особенностью является то что в зависимости от источника QML, QQmlComponent может грузить его как синхронно, так и асинхронно.
Обработать это можно следующим образом (именно такой код используется в 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() );

но лично мне, больше импонирует такая реализация:

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

Поскольку в этом случае синхронная и асинхронная загрузки обрабатываются идентично (а меньше ветвлений в коде — меньше поводов ошибиться).

В случае необходимости загрузки QML из QString, код будет выглядеть следующим образом:

    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 );

В данном случае, несмотря на то что QML загружается из строки, можно указать URL с которым данный QML будет ассоциирован. Это необходимо в том случае, если в тексте QML строки используются какие либо внешние элементы (ссылки на другие QML компоненты или файлы), поиск которых и будет осуществляться относительно переданного URL.

Ну а нам осталось только обработать результат загрузки:

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

Важное замечание: в вышеприведенном коде, сознательно абсолютно проигнорированы как вопросы владения объектами, так и вопросы обработки ошибок.

Собственно это было все что было необходимо для решения второй части исходной задачи [4].

Класс реализующий вышеприведенную концепцию, как обычно, доступен на GitHub: FboQuickView.h [7], FboQuickView.cpp [8]
Ну и как и прежде, коментарии, вопросы, здоровая критика — приветствуются.

Продолжение следует...

Автор: RSATom

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/qt-2/79848

Ссылки в тексте:

[1] QQuickView: http://doc.qt.io/qt-5/qquickview.html

[2] QQuickWindow: http://doc.qt.io/qt-5/qquickwindow.html

[3] QQuickRenderControl: http://doc.qt.io/qt-5/qquickrendercontrol.html

[4] Часть I доступна по данной ссылке: http://habrahabr.ru/post/247477/

[5] QQmlEngine: http://doc.qt.io/qt-5/qqmlengine.html

[6] QQmlComponent: http://doc.qt.io/qt-5/qqmlcomponent.html

[7] FboQuickView.h: https://github.com/RSATom/QuickLayer/blob/master/FboQuickView.h

[8] FboQuickView.cpp: https://github.com/RSATom/QuickLayer/blob/master/FboQuickView.cpp

[9] Источник: http://habrahabr.ru/post/248103/