【译】QQmlContext 类介绍 (Qt 5.11)

972 阅读3分钟

原文:doc.qt.io/archives/qt…

本译文仅仅是该类相关知识的介绍,不包含详细用法等

详细介绍

QQmlContext 类定义了 QML 引擎中的一个上下文。

“上下文”允许我们将数据暴露给由 QML 引擎实例化的 QML 组件。

每个 QQmlContext 都包含一组属性(这里的属性指的不是其自身的 QObject 属性),这些属性允许数据以我们指定的名称绑定到 QML 的上下文中。这些被绑定的上下文属性要通过调用 QQmlContext::setContextProperty() 进行定义和修改。下面的例子中演示了如何将一个 Qt 数据模型 QStringListModel 绑定到上下文中,然后在 QML 文件中取值:

QQmlEngine engine;
QStringListModel modelData;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextProperty("myModel", &modelData);

QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
QObject *window = component.create(context);

注意:QQmlContext 实例需要由创建者来删除。context 对象在 window 实例被销毁时就不再有用了,这时必须要显式地手动销毁 context 实例。确保 context 能够被及时销毁的最简单方式是指定 windowcontextparent

我们还可以在 QQmlContext 上设置自定义的上下文对象。上下文对象内的所有成员属性都可以在上下文中用它们的名称来使用,就像是其中的每个成员都是分别用 QQmlContext::setContextProperty() 设置的一样。对属性值的修改可以通过属性的 notify 信号检测到。设置上下文对象要比手动添加和管理上下文属性值更快,操作起来也更简单。

下面例子中的代码和上一个例子是等效的,只不过是把上面的方式换为了使用上下文对象:

class MyDataSet: ... {
	...
    // 使用 Q_PROPERTY 宏来定义一个属性,这个属性会在下面被绑定到 QML 上下文中
	Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
	...
};

MyDataSet myDataSet;
QQmlEngine engine;
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextObject(&myDataSet);	// 从 xxxProperty 变为了 xxxObject

QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
component.create(context);

注意:所有使用 QQmlContext::setContextProperty() 显式添加的属性都将优先于上下文对象属性。

上下文层次结构

多个上下文能够组成一个层次结构。这个层次结构的根是 QML 引擎的"根上下文"。子上下文会继承他们父级上下文的属性,这意味着如果一个子上下文设置了其父上下文中已存在的属性,这个新的属性就会覆盖从父级上下文继承来的那个属性。

“根上下文”由 QQmlEngine 自动创建。需要能够被所有 QML 组件获取到的数据都应该放在根上下文中。与之相对的,只需要被一部分组件获取到的数据可以放在根上下文下面的子上下文中。

下面的例子定义了两个上下文——context1context2 ,第二个上下文将继承来的属性 b 覆盖为了一个新值:

QQmlEngine engine;
QQmlContext *context1 = new QQmlContext(engine.rootContext());
QQmlContext *context2 = new QQmlContext(context1);		// 设置 2 为 1 的子上下文

context1->setContextProperty("a", 12);
context1->setContextProperty("b", 12);

context2->setContextProperty("b", 15);	// 覆盖掉继承来的 12

需要注意,虽然在上下文中实例化的 QML 对象并不严格属于上下文,但它们的绑定却是严格属于上下文的——这意味着如果一个上下文被销毁,那么还在求值中的 QML 对象的属性绑定也不会再继续求值了。

警告:当已经在上下文中创建过上下文对象后,再在该上下文中设置上下文对象或添加新的上下文属性的操作都会产生很大的开销——因为这会强制对所有的绑定重新求值。因此最好在使用上下文之前完成所有的初始化步骤,避免在使用过程中再加上下文属性。