Как подружить QML с чужим OpenGL контекстом. Часть II: Загружаем QML
В данной статье я попытаюсь рассказать о том как загружать QML в случае, если у вас, по какой-то причине, нет возможности использовать QQuickView, а необходимо работать непосредственно с QQuickWindow.В моем случае, таковой причиной являлось то, что с QQuickRenderControl умеет работать только QQuickWindow. В вашем же случае, таковой причиной может быть например то, что вам понадобилось загружать QML не из какого либо файла, а например из памяти, что открывает возможность генерации QML «на лету», или запроса содержимого QML, или его части, у пользователя — занятно, не так ли? На случай если вы не читали начало: Часть I доступна по данной ссылке.На самом деле, в поставленной задаче, нет практически ничего сложного, достаточно внимательно почитать документацию или же заглянуть в исходники QQuickView.
Итак, обо всем, по порядкуПервое что нам потребуется, это QQmlEngine: QQmlEngine* qmlEngine = new QQmlEngine; Далее нам нужен QQmlComponent — именно с его помощью осуществляется загрузка 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
rootItem→setParentItem (quickWindow→contentItem ()); rootItem→setSize (QSizeF (quickWindow→width (), quickWindow→height ())); } Важное замечание: в вышеприведенном коде, сознательно абсолютно проигнорированы как вопросы владения объектами, так и вопросы обработки ошибок.Собственно это было все что было необходимо для решения второй части исходной задачи.
Класс реализующий вышеприведенную концепцию, как обычно, доступен на GitHub: FboQuickView.h, FboQuickView.cppНу и как и прежде, коментарии, вопросы, здоровая критика — приветствуются.
Продолжение следует…