# 跟踪动态对象
使用动态对象时,通常需要跟踪创建的对象。 另一个常见的特点是能够存储和恢复动态对象的状态。 使用动态填充的XmlListModel
可以轻松地处理这两个任务。
在下面显示的示例中,用户可以创建和移动两种类型的元素:火箭和UFO。 为了能够操纵动态创建元素的整个场景,使用模型来跟踪这些项目。
在创建项目时填充模型,即XmlListModel
。 对象引用与实例化时使用的源URL一起被跟踪。 源URL对于跟踪对象并不是严格需要的,但稍后会派上用场。
import QtQuick
import "create-object.js" as CreateObject
Item {
id: root
ListModel {
id: objectsModel
}
function addUfo() {
CreateObject.create("ufo.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的更通用形式。 create
方法有三个参数:源URL、根元素和完成时调用的回调函数。使用两个参数调用回调函数:对新创建对象的引用和使用的源URL。
这意味着每次调用addUfo
或addRocket
函数时,都会在创建新对象时调用itemAdded
函数。itemAdded
函数会将对象的引用和源URL附加到objectsModel
模型上。
objectsModel
可以以多种方式使用。在提及的示例中,clearItems
函数依赖于它。这个函数演示了两件事:首先,如何迭代模型并执行任务,即为每个项目调用destroy
函数以将其删除;其次,它强调了模型没有随着对象被销毁而更新的事实。该模型项的obj
属性设置为null
,而不是删除连接到相关对象的模型项。为了解决这个问题,代码必须在删除对象时明确清除模型项。
function clearItems() {
while(objectsModel.count > 0) {
objectsModel.get(0).obj.destroy()
objectsModel.remove(0)
}
}
拥有一个代表所有动态创建的项目的模型,很容易创建一个序列化项目的函数。 在示例代码中,序列化信息由每个对象的源URL及其x
和y
属性组成,这些都是是用户可以更改的属性,这些信息用于构建XML文档字符串。
function serialize() {
var res = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<scene>\n"
for(var ii=0; ii < objectsModel.count; ++ii) {
var i = objectsModel.get(ii)
res += " <item>\n <source>" + i.source + "</source>\n <x>" + i.obj.x + "</x>\n <y>" + i.obj.y + "</y>\n </item>\n"
}
res += "</scene>"
return res
}
提示
目前,Qt 6的XmlListModel
缺少序列化和反序列化工作所需的xml
属性和get()
函数。
通过设置XmlListModel
模型的xml
属性,可以将XML文档字符串与模型一起使用。 在下面的代码中,模型随着deserialize
函数而显示。 deserialize
函数通过将dsIndex
设置为引用模型的第一个项目,然后调用该项目的创建来启动反序列化。 回调 dsItemAdded
然后设置新创建对象的x
和y
属性,然后它更新索引并创建下一个对象(如果有)。
XmlListModel {
id: xmlModel
query: "/scene/item"
XmlListModelRole { name: "source"; elementName: "source" }
XmlListModelRole { name: "x"; elementName: "x" }
XmlListModelRole { name: "y"; elementName: "y" }
}
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
该示例演示了如何使用模型来跟踪创建的项目,以及序列化和反序列化此类信息是多么容易。 这可用于存储动态填充的场景,例如一组小部件。 在示例中,使用模型来跟踪每个项目。
另一种解决方案是使用场景根的children
属性来跟踪项目。 但是,这需要项目本身知道用于重新创建它们的源URL。 它还要求实现一种方法,能够将动态创建的项目与属于原始场景的项目区分开来,这样就可以避免尝试序列化和稍后反序列化任何原始项目。