处理动态对象时,通常需要跟踪已创建的对象。另一个常见的功能是能够存储和恢复动态对象的状态。在我们动态填充时,使用链表模型(ListModel)可以非常方便的处理这些问题。
在下面的例子中包含了两种元素,火箭和飞机,能够被用户创建和移动。为了控制整个场景动态创建元素,我们使用一个模型来跟踪项。
待完成
插图
模型是一个链表模型(ListModel),用已创建的项进行填充。实例化时跟踪对象引用的资源URL。后者不是需要严格跟踪的对象,但是以后会派上用场。
import QtQuick 2.0
import "create-object.js" as CreateObject
Item {
id: root
ListModel {
id: objectsModel
}
function addPlanet() {
CreateObject.create("planet.qml", root, itemAdded);
}
function addRocket() {
CreateObject.create("rocket.qml", root, itemAdded);
}
function itemAdded(obj, source) {
objectsModel.append({"obj": obj, "source": source})
}
你可以从上面的例子中看到,create-object.js是一种使得JavaScript引进更加简单的、普遍的方法。创建方法使用了三个参数:一个资源URL,一个根元素和一个完成的回调函数。回调需要两个参数:一个新创建的对象引用和一个资源URL。
这意味着每一次调用addPlanet或者addRocket时,当新建对象被创建完成后悔调用itemAdded函数。后者会将对象的引用和资源URL添加到objectsModel模型中。
可以在很多方面使用objectsModel。在示例中,clearItems函数依赖它。这个函数证明了两个事情。首先,如何遍历模型和执行一个任务,即调用析构函数来移除每一个项。其次,它强调了模型不会更新已经销毁的对象。此外移除模型项已连接的对象问题,模型项的对象属性设置为null,为了补救这个问题,代码显式的清除了已移除对象的模型项。
function clearItems() {
while(objectsModel.count > 0) {
objectsModel.get(0).obj.destroy();
objectsModel.remove(0);
}
}
通过设置XmlListModel模型的xml属性可以处理XML文档字符串。代码如下,模型展示了反序列化函数。反序列化函数通过设置dsIndex引用模型的第一个项来启动反序列化,然后调用项的创建。然后回调dsItemAdded设置新创建对象的x,y属性,然后更新索引创建下一个对象。
XmlListModel {
id: xmlModel
query: "/scene/item"
XmlRole { name: "source"; query: "source/string()" }
XmlRole { name: "x"; query: "x/string()" }
XmlRole { name: "y"; query: "y/string()" }
}
function deserialize() {
dsIndex = 0;
CreateObject.create(xmlModel.get(dsIndex).source, root, dsItemAdded);
}
function dsItemAdded(obj, source) {
itemAdded(obj, source);
obj.x = xmlModel.get(dsIndex).x;
obj.y = xmlModel.get(dsIndex).y;
dsIndex ++;
if (dsIndex < xmlModel.count)
CreateObject.create(xmlModel.get(dsIndex).source, root, dsItemAdded);
}
property int dsIndex
这个例子演示了如何使用模型跟踪已创建的模型项,和基于信息对模型项序列化和反序列化。这可以用于存储一个动态填充场景,例如窗口部件。在这个例子中,模型被用于跟踪每一个模型项。
另一种解决方案是用于一个场景根项下的子项属性来跟踪子项。然后,这要求项自己知道资源URL用于创建它们自己。这也要求场景只能动态创建子项,以避免序列化或者反序列化静态分配的对象。