# 理解QML运行时
运行QML时,它是在运行时环境中执行的。 运行时在QtQml
模块中由C++语言实现。 运行时由引擎(负责执行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
,它包含一个窗口和一个文本。
提示
通过QmlApplicationEngine
加载以简单的Item
作为根类型的main.qml
文件将不会在显示器上显示任何内容,因为它需要一个窗口来管理用于渲染的外观。 该引擎能够加载不包含任何用户界面(例如,普通对象)的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);
现在还可以在QML文件中使用CurrentTime
类型。
import org.example 1.0
CurrentTime {
// access properties, functions, signals
}
如果不需要从QML中实例化新类,可以使用上下文属性将C++对象暴露给QML,例如:
QScopedPointer<CurrentTime> current(new CurrentTime());
QQmlApplicationEngine engine();
engine.rootContext().setContextProperty("current", current.value())
engine.load(source);
提示
不要混淆setContextProperty()
和setProperty()
。 setContextProperty()
是在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的不同方法:
- 上下文属性(Context properties) -
setContextProperty()
- 使用引擎注册类型(Register type with engine) - 在
main.cpp
中调用qmlRegisterType
- QML扩展插件(QML extension plugins) - 灵活性最高,将在下面讨论
上下文属性(Context properties) 容易应用到小型应用程序中。它们不需要花费太多努力,只需使用某种全局对象暴露系统API即可。确保没有命名冲突会很有用(例如,为此使用特殊字符($
),例如$.currentTime
)。 $
是在JS变量中是有效字符。
注册QML类型(Registering QML types) 允许用户在QML中控制C++对象的生命周期。这在使用上下文属性的方式中是不可能完成的。此外,它不会污染全局的命名空间。这种方法仍然需要首先注册所有类型,因此,所有库都需要在应用程序启动时链接,这在大多数情况下并不是真正的问题。
QML扩展插件(QML extension plugins) 提供了最灵活的系统。它们允许在第一个调用导入标识符的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扩展插件。 它们提供了最大的灵活性和重用性。
← 使用C++扩展QML 插件内容 →