Qt6 QML Book/动态QML/创建和销毁对象

Creating and Destroying Objects

创建和销毁对象

The Loader element makes it possible to populate part of a user interface dynamically. However, the overall structure of the interface is still static. Through JavaScript, it is possible to take one more step and to instantiate QML elements completely dynamically.

Loader元素类型可以动态填充用户界面的一部分。然而,界面的整体结构仍然是静态的。通过JavaScript,可以采取更多步骤,完全动态地实例化QML元素。

Before we dive into the details of creating elements dynamically, we need to understand the workflow. When loading a piece of QML from a file or even over the Internet, a component is created. The component encapsulates the interpreted QML code and can be used to create items. This means that loading a piece of QML code and instantiating items from it is a two-stage process. First, the QML code is parsed into a component. Then the component is used to instantiate actual item objects.

在深入研究动态创建元素的细节之前,我们需要了解工作流。当从文件甚至通过Internet加载QML时,会创建一个组件。该组件封装了解释的QML代码,可用于创建项。这意味着加载一段QML代码并从中实例化项是一个两阶段的过程。首先,QML代码被解析为一个组件。然后,该组件用于实例化实际的项对象。

In addition to creating elements from QML code stored in files or on servers, it is also possible to create QML objects directly from text strings containing QML code. The dynamically created items are then treated in a similar fashion once instantiated.

除了从存储在文件或服务器上的QML代码创建元素外,还可以直接从包含QML代码的文本字符串创建QML对象。动态创建的项目一旦实例化,就会以类似的方式进行处理。

Dynamically Loading and Instantiating Items

动态加载和实例化项

When loading a piece of QML, it is first interpreted as a component. This includes loading dependencies and validating the code. The location of the QML being loaded can be either a local file, a Qt resource, or even a distance network location specified by a URL. This means that the loading time can be everything from instant, for instance, a Qt resource located in RAM without any non-loaded dependencies, to very long, meaning a piece of code located on a slow server with multiple dependencies that need to be loaded.

加载QML时,它首先被解释为一个组件。这包括加载依赖项和验证代码。正在加载的QML的位置可以是本地文件、Qt资源,甚至可以是URL指定的远程网络位置。这意味着加载时间可以是任何东西,即时的,例如,位于RAM中的Qt资源没有任何未加载的依赖项,到非常长的,这意味着一段代码位于需要加载多个依赖项的慢速服务器上。

The status of a component being created can be tracked by it is status property. The available values are Component.NullComponent.LoadingComponent.Ready and Component.Error. The Null to Loading to Ready is the usual flow. At any stage, the status can change to Error. In that case, the component cannot be used to create new object instances. The Component.errorString() function can be used to retrieve a user-readable error description.

正在创建的组件的状态可以通过其status属性进行跟踪。可用的值是Component.NullComponent.LoadingComponent.Ready和Component.Error。通常的流是Null-Loading-Ready 。在任何阶段,状态status都可能变为错误Error。在这种情况下,该组件不能用于创建新的对象实例。Component.errorString()函数可用于检索用户可读的错误描述。

When loading components over slow connections, the progress property can be of use. It ranges from 0.0, meaning nothing has been loaded, to 1.0 indicating that all have been loaded. When the component’s status changes to Ready, the component can be used to instantiate objects. The code below demonstrates how that can be achieved, taking into account the event of the component becoming ready or failing to be created directly, as well as the case where a component is ready slightly later.

通过慢速连接加载组件时,可以使用progress属性。它的范围从0.0(表示未加载任何内容)到1.0(表示已加载所有内容)。当组件的状态status更改为Ready时,该组件可用于实例化对象。下面的代码演示了如何实现这一点,考虑到组件准备就绪或无法直接创建的事件,以及组件稍晚准备就绪的情况。

var component;

function createImageObject() {
    component = Qt.createComponent("dynamic-image.qml");
    if (component.status === Component.Ready || component.status === Component.Error) {
        finishCreation();
    } else {
        component.statusChanged.connect(finishCreation);
    }
}

function finishCreation() {
    if (component.status === Component.Ready) {
        var image = component.createObject(root, {"x": 100, "y": 100});
        if (image === null) {
            console.log("Error creating image");
        }
    } else if (component.status === Component.Error) {
        console.log("Error loading component:", component.errorString());
    }
}

The code above is kept in a separate JavaScript source file, referenced from the main QML file.

上面的代码保存在一个单独的JavaScript源文件中,从主QML文件中引用。

import QtQuick
import "create-component.js" as ImageCreator

Item {
    id: root

    width: 1024
    height: 600

    Component.onCompleted: ImageCreator.createImageObject();
}

The createObject function of a component is used to create object instances, as shown above. This not only applies to dynamically loaded components but also Component elements inlined in the QML code. The resulting object can be used in the QML scene like any other object. The only difference is that it does not have an id.

组件的createObject函数用于创建对象实例,如上所示。这不仅适用于动态加载的组件,还适用于QML代码中内联的组件元素类型。生成的对象可以像任何其他对象一样在QML场景中使用。唯一的区别是它没有id。

The createObject function takes two arguments. The first is a parent object of the type Item. The second is a list of properties and values on the format {"name": value, "name": value}. This is demonstrated in the example below. Notice that the properties argument is optional.

createObject函数有两个参数。第一个是类型项Item的父对象。第二个是{“name”:value,“name”:value}格式的属性和值列表。下面的例子说明了这一点。请注意,properties参数是可选的。

var image = component.createObject(root, {"x": 100, "y": 100});

TIP

A dynamically created component instance is not different to an in-line Component element. The in-line Component element also provides functions to instantiate objects dynamically.

动态创建的组件实例与内嵌组件元素没有区别。内嵌组件元素还提供了动态实例化对象的功能。

Incubating Components

孵化组件

When components are created using createObject the creation of the object component is blocking. This means that the instantiation of a complex element may block the main thread, causing a visible glitch. Alternatively, complex components may have to be broken down and loaded in stages using Loader elements.

使用createObject创建组件时,对象组件的创建将是阻塞的。这意味着复杂元素的实例化可能会阻塞主线程,从而导致可见的故障。或者,复杂的部件可能必须使用Loader元素类型分阶段进行分解和装载。

To resolve this problem, a component can be instantiated using the incubateObject method. This might work just as createObject and return an instance immediately, or it may call back when the component is ready. Depending on your exact setup, this may or may not be a good way to solve instantiation related animation glitches.

为了解决这个问题,可以使用incubateObject方法实例化组件。这可能与createObject一样工作,并立即返回一个实例,或者在组件准备就绪时回调。根据具体设置,这可能是解决实例化相关动画问题的好方法,也可能不是。

To use an incubator, simply use it as createComponent. However, the returned object is an incubator and not the object instance itself. When the incubator’s status is Component.Ready, the object is available through the object property of the incubator. All this is shown in the example below:

要使用孵化器,只需将其用作createComponent即可。但是,返回的对象是孵化器,而不是对象实例本身。当孵化器的状态为Component.Ready时。可通过孵化器的object属性获取该对象。所有这些都显示在下面的示例中:

function finishCreate() {
    if (component.status === Component.Ready) {
        var incubator = component.incubateObject(root, {"x": 100, "y": 100});
        if (incubator.status === Component.Ready) {
            var image = incubator.object; // Created at once
        } else {
            incubator.onStatusChanged = function(status) {
                if (status === Component.Ready) {
                    var image = incubator.object; // Created async
                }
            };
        }
    }
}

Dynamically Instantiating Items from Text

从文本动态实例化项

Sometimes, it is convenient to be able to instantiate an object from a text string of QML. If nothing else, it is quicker than putting the code in a separate source file. For this, the Qt.createQmlObject function is used.

有时,可以方便地从QML的文本字符串实例化对象。如果没有其他方法,那么它比将代码放入单独的源文件更快。对于这一点,使用Qt.createQmlObject函数。

The function takes three arguments: qmlparent and filepath. The qml argument contains the string of QML code to instantiate. The parent argument provides a parent object to the newly created object. The filepath argument is used when reporting any errors from the creation of the object. The result returned from the function is either a new object or null.

该函数有三个参数:qml、parent和filepath。qml参数包含要实例化的qml代码字符串。parent参数为新创建的对象提供父对象。filepath参数用于报告对象创建过程中的任何错误。函数返回的结果是新对象或null。

WARNING

警告

The createQmlObject function always returns immediately. For the function to succeed, all the dependencies of the call must be loaded. This means that if the code passed to the function refers to a non-loaded component, the call will fail and return null. To better handle this, the createComponent / createObject approach must be used.

createQmlObject函数总是立即返回。为了使函数成功,必须加载调用的所有依赖项。这意味着,如果传递给函数的代码引用了未加载的组件,则调用将失败并返回null。为了更好地处理这个问题,必须使用createComponent/createObject方法。

The objects created using the Qt.createQmlObject function resembles any other dynamically created object. That means that it is identical to every other QML object, apart from not having an id. In the example below, a new Rectangle element is instantiated from in-line QML code when the root element has been created.

使用Qt.createQmlObject函数创建的对象。类似于任何其他动态创建的对象。这意味着它与其他所有QML对象相同,只是没有id。在下面的示例中,当创建根元素时,将从内嵌的QML代码实例化一个新的矩形元素。

import QtQuick 2.5

Item {
    id: root

    width: 1024
    height: 600

    function createItem() {
        Qt.createQmlObject("import QtQuick 2.5; Rectangle { x: 100; y: 100; width: 100; height: 100; color: \"blue\" }", root, "dynamicItem");
    }

    Component.onCompleted: root.createItem();
}

Managing Dynamically Created Elements

管理动态创建的元素

Dynamically created objects can be treated as any other object in a QML scene. However, there are some pitfalls that we need to be aware of. The most important is the concept of the creation contexts.

可以将动态创建的对象视为QML场景中的任何其他对象。然而,我们需要注意一些陷阱。最重要的是创造语境的概念。

The creation context of a dynamically created object is the context within it is being created. This is not necessarily the same context as the parent exists in. When the creation context is destroyed, so are the bindings concerning the object. This means that it is important to implement the creation of dynamic objects in a place in the code which will be instantiated during the entire lifetime of the objects.

动态创建的对象的创建上下文就是正在创建的对象中的上下文。这不一定与父对象所在的上下文相同。当创建上下文被析构时,与对象相关的绑定也会被析构。这意味着在代码中的某个位置实现动态对象的创建非常重要,该位置将在对象的整个生命周期中实例化。

Dynamically created objects can also be dynamically destroyed. When doing this, there is a rule of thumb: never attempt to destroy an object that you have not created. This also includes elements that you have created, but not using a dynamic mechanism such as Component.createObject or createQmlObject.

动态创建的对象也可以动态销毁。做这件事时,有一条经验法则:永远不要试图破坏你没有创建的对象。这还包括您创建的元素,但不使用动态机制(如Component.createObjectcreateQmlObject)。

An object is destroyed by calling its destroy function. The function takes an optional argument which is an integer specifying how many milliseconds the objects shall exist before being destroyed. This is useful too, for instance, let the object complete a final transition.

通过调用其destroy函数来销毁对象。该函数接受一个可选参数,该参数是一个整数,指定对象在被销毁之前应存在的毫秒数。这也很有用,例如,让对象完成最终转换。

item = Qt.createQmlObject(...);
...
item.destroy();

TIP

It is possible to destroy an object from within, making it possible to create self-destroying popup windows for instance.

可以从内部销毁对象,例如,可以创建自毁弹出窗口。

示例源码下载​​​​​​​ 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值