Понятие времени выполнения QML
При запуске QML выполняется внутри среды выполнения. Среда выполнения реализована на C++ в модуле QtQml
. Он состоит из движка, отвечающего за выполнение QML, контекстов, содержащих глобальные свойства, доступные для каждого компонента, и компонентов – элементов QML, которые могут быть созданы из QML.
#include <QtGui>
#include <QtQml>
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QUrl source(QStringLiteral("qrc:/main.qml"));
QQmlApplicationEngine engine;
engine.load(source);
return app.exec();
}
В примере выше QGuiApplication
инкапсулирует всё, что связано с экземпляром приложения (например, имя приложения, аргументы командной строки и управление циклом обработки событий). QQmlApplicationEngine
управляет иерархическим порядком контекстов и компонентов. Для этого требуется загрузить типовой файл QML в качестве отправной точки вашего приложения. В данном случае это main.qml, содержащий окно и текстовый тип.
Подсказка
Загрузка main.qml с простым Item
в качестве корневого типа через QmlApplicationEngine
ничего не покажет на вашем дисплее, так как для управления поверхностью для рендеринга требуется окно. Движок способен загружать код QML, который не содержит никакого пользовательского интерфейса (например, простые объекты). Поэтому по умолчанию он не создает для вас окно. Среда выполнения qml
сначала проверит, содержит ли основной файл QML окно в качестве корневого элемента, и, если нет, создаст его для вас и установит корневой элемент в качестве дочернего для вновь созданного окна.
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
width: 512
height: 300
Text {
anchors.centerIn: parent
text: "Hello World!"
}
}
В файле QML мы объявляем наши зависимости, здесь это QtQuick
и QtQuick.Window
. Эти объявления инициируют поиск этих модулей в путях импорта и в случае успеха загрузят с помощью движка необходимые плагины. Затем вновь загруженные типы будут доступны для среды QML через объявление в файле qmldir
, представляющем отчет.
Также можно сократить создание плагина, добавив наши типы непосредственно в движок в нашем файле main.cpp. Здесь мы предполагаем, что у нас есть CurrentTime
, который является классом, основанным на базовом классе QObject
.
QQmlApplicationEngine engine();
qmlRegisterType<CurrentTime>("org.example", 1, 0, "CurrentTime");
engine.load(source);
Теперь мы можем использовать тип CurrentTime
в нашем файле QML.
import org.example 1.0
CurrentTime {
// доступ к свойствам, функциям, сигналам
}
Если нам не нужно создавать экземпляр нового класса из QML, мы можем использовать свойства контекста для представления объектов C++ в QML, например:
QScopedPointer<CurrentTime> current(new CurrentTime());
QQmlApplicationEngine engine();
engine.rootContext().setContextProperty("current", current.value())
engine.load(source);
Подсказка
Не путайте setContextProperty()
и setProperty()
. Первая устанавливает свойство контекста в контексте qml, а setProperty()
устанавливает значение динамического свойства в QObject
и здесь вам не поможет.
Теперь вы можете использовать свойство current
везде в вашем приложении. Оно доступно везде в коде QML благодаря наследованию контекста. Объект current
регистрируется в самом внешнем корневом контексте, который наследуется везде.
import QtQuick
import QtQuick.Window
Window {
visible: true
width: 512
height: 300
Component.onCompleted: {
console.log('current: ' + current)
}
}
Ниже приведены различные способы расширения QML в целом:
- свойства контекста –
setContextProperty()
; - регистрация типа с помощью движка - вызов
qmlRegisterType
в вашем main.cpp; - плагины расширения QML - максимальная гибкость, которые будут обсуждаться далее.
Свойства контекста легко использовать для небольших приложений. Они не требуют никаких усилий, вы просто предоставляете свой системный API с помощью глобальных объектов. Полезно убедиться, что не будет конфликтов имен (например, используя для этого специальный символ ($
), например, $.currentTime
). $
является допустимым символом для переменных JS.
Регистрация типов QML позволяет пользователю управлять жизненным циклом объекта C++ из QML. Это невозможно со свойствами контекста. Кроме того, она не загрязняет глобальное пространство имен. Тем не менее, все типы должны быть сначала зарегистрированы, и поэтому все библиотеки должны быть слинкованы при запуске приложения, что в большинстве случаев не является проблемой.
Наиболее гибкую систему обеспечивают плагины расширения QML. Они позволяют вам регистрировать типы в плагине, который загружается, когда первый файл QML вызывает идентификатор импорта. Кроме того, при использовании синглтона QML больше нет необходимости загрязнять глобальное пространство имен. Плагины позволяют вам повторно использовать модули в разных проектах, что очень удобно, когда вы делаете с помощью Qt более одного проекта.
Вернемся к нашему простому примеру файла main.qml:
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
width: 512
height: 300
Text {
anchors.centerIn: parent
text: "Hello World!"
}
}
Когда мы импортируем QtQuick
и QtQuick.Window
, мы указываем среде выполнения QML найти соответствующие плагины расширения QML и загрузить их. Это делается движком QML путем поиска этих модулей в путях импорта QML. Вновь загруженные типы затем будут доступны для среды QML.
В оставшейся части этой главы основное внимание будет уделено плагинам расширения QML. Так как они обеспечивают наибольшую гибкость и повторное использование.