Qt6 QML Book/动态QML/跟踪动态对象

Tracking Dynamic Objects

跟踪动态对象

Working with dynamic objects, it is often necessary to track the created objects. Another common feature is to be able to store and restore the state of the dynamic objects. Both these tasks are easily handled using an XmlListModel that is dynamically populated.

使用动态对象时,通常需要跟踪创建的对象。另一个常见功能是能够存储和恢复动态对象的状态。这两项任务都可以使用动态填充的XmlListModel轻松处理。

In the example shown below two types of elements, rockets and ufos can be created and moved around by the user. In order to be able to manipulate the entire scene of dynamically created elements, we use a model to track the items.

在下面的例子中,有两种元素类型,火箭和UFO可以由用户创建和移动。为了能够操纵动态创建元素的整个场景,我们使用模型来跟踪项目。

The model, a XmlListModel, is populated as the items are created. The object reference is tracked alongside the source URL used when instantiating it. The latter is not strictly needed for tracking the objects but will come in handy later.

该模型为XmlListModel,在创建项时填充。对象引用与实例化时使用的源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})
    }

As you can tell from the example above, the create-object.js is a more generalized form of the JavaScript introduced earlier. The create method uses three arguments: a source URL, a root element, and a callback to invoke when finished. The callback gets called with two arguments: a reference to the newly created object and the source URL used.

从上面的例子可以看出,create-object.js是前面介绍的JavaScript的一种更通用的形式。create方法使用三个参数:一个源URL、一个根元素,以及一个在完成时调用的回调。调用回调时有两个参数:对新创建的对象的引用和使用的源URL。

This means that each time addUfo or addRocket functions are called, the itemAdded function will be called when the new object has been created. The latter will append the object reference and source URL to the objectsModel model.

这意味着每次调用addUfo或addRocket函数时,在创建新对象时都会调用itemAdded函数。后者将对象引用和源URL附加到objectsModel模型。

The objectsModel can be used in many ways. In the example in question, the clearItems function relies on it. This function demonstrates two things. First, how to iterate over the model and perform a task, i.e. calling the destroy function for each item to remove it. Secondly, it highlights the fact that the model is not updated as objects are destroyed. Instead of removing the model item connected to the object in question, the obj property of that model item is set to null. To remedy this, the code explicitly has to clear the model item as the objects are removed.

objectsModel可以以多种方式使用。在所讨论的示例中,clearItems函数依赖于它。这个函数演示了两件事。首先,如何迭代模型并执行任务,即为每个项调用destroy函数以删除它。其次,它强调了一个事实,即当对象被破坏时,模型不会更新。该模型项的obj属性设置为null,而不是删除连接到相关对象的模型项。为了解决这个问题,代码必须在删除对象时明确清除模型项。

function clearItems() {
    while(objectsModel.count > 0) {
        objectsModel.get(0).obj.destroy();
        objectsModel.remove(0);
    }
}

Having a model representing all dynamically created items, it is easy to create a function that serializes the items. In the example code, the serialized information consists of the source URL of each object along its x and y properties. These are the properties that can be altered by the user. The information is used to build an XML document string.

有了一个表示所有动态创建项的模型,就很容易创建一个序列化这些项的函数。在示例代码中,序列化信息由每个对象的源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;
}

TIP

Currently, the XmlListModel of Qt 6 lacks the xml property and get() function needed to make serialization and deserialization work.

目前,Qt 6的XmlListModel缺少使序列化和反序列化工作所需的xml属性和get()函数。

The XML document string can be used with an XmlListModel by setting the xml property of the model. In the code below, the model is shown along the deserialize function. The deserialize function kickstarts the deserialization by setting the dsIndex to refer to the first item of the model and then invoking the creation of that item. The callback, dsItemAdded then sets that x and y properties of the newly created object. It then updates the index and creates the next object, if any.

XML文档字符串可以通过设置模型的xml属性与XmlListModel一起使用。在下面的代码中,模型显示在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

The example demonstrates how a model can be used to track created items, and how easy it is to serialize and deserialize such information. This can be used to store a dynamically populated scene such as a set of widgets. In the example, a model was used to track each item.

该示例演示了如何使用模型跟踪创建的项,以及序列化和反序列化此类信息是多么容易。这可以用来存储动态填充的场景,比如一组窗体。在本例中,使用了一个模型来跟踪每个项目。

An alternate solution would be to use the children property of the root of a scene to track items. This, however, requires the items themselves to know the source URL to use to re-create them. It also requires us to implement a way to be able to tell dynamically created items apart from the items that are a part of the original scene, so that we can avoid attempting to serialize and later deserialize any of the original items.

另一种解决方案是使用场景根的children属性来跟踪项目。然而,这需要项目本身知道用于重新创建它们的源URL。它还要求我们实现一种方法,能够将动态创建的项目与作为原始场景一部分的项目区分开来,这样我们就可以避免尝试序列化和以后反序列化任何原始项目。

源码示例下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值