QML- 在JavaScript动态创建QML对象
创始人
2024-06-03 07:14:54
0

在JavaScript动态创建QML对象

  • 一、概述
  • 二、动态创建对象
  • 三、动态创建组件
  • 四、从QML字符串创建对象
  • 五、维护动态创建的对象
  • 六、动态删除对象

一、概述

QML支持在JavaScript中动态创建对象。这有助于将对象的实例化推迟到必要的时候,从而提高应用程序的启动时间。它还允许动态创建可视对象,并根据用户输入或其他事件将其添加到场景中。动态创建用的场景是非常的多。有些组件在时间线上不是同时创建的,同时就像弹窗一样,有些组件其实是在运行的时候创建一会儿,就销毁掉了。

二、动态创建对象

在JavaScript中动态创建对象有两种方法。

  • 1.你可以调用Qt.createComponent()动态创建一个组件对象,
  • 2.也可以使用Qt.createQmlObject()从QML字符串创建一个对象。

这两种方法有不同的适用范围,如果有在QML文档中定义的现有组件,并且希望动态创建该组件的实例,则创建组件是更好的选择。否则,当对象QML本身在运行时生成时,从QML字符串创建对象是有用的。

三、动态创建组件

要动态加载QML文件中定义的组件,在Qt对象中调用Qt. createcomponent()函数。这个函数将QML文件的URL作为唯一的参数,并从这个URL创建一个组件对象。

一旦有了一个组件,就可以调用它的 createObject() 方法来创建该组件的实例。这个函数可以接受一个或两个参数:

  • 第一个是新对象的父对象。父对象可以是图形对象(即Item类型)或非图形对象(即QtObject或c++ QObject类型)。只有具有图形父对象的图形对象才会被渲染到Qt Quick visual canvas中。如果你希望稍后设置父元素,你可以安全地将null传递给这个函数。
  • 第二个是可选的,是属性-值对的映射,定义了对象属性的初始值。此参数指定的属性值在最终创建对象之前应用于对象,从而避免在必须初始化特定属性以启用其他属性绑定时可能发生的绑定错误。此外,与在创建对象之后定义属性值和绑定相比,在性能上有小的优势。

这里有一个例子。首先是 Sprite.qml 定义了一个简单的qml组件:

import QtQuick 2.0Rectangle { width: 80; height: 50; color: "red" }

我们的主应用程序文件 main.qml 导入一个 componentcreate .js JavaScript文件,用来创建子画面 Sprite 对象:

import QtQuick 2.0
import "componentCreation.js" as MyScriptRectangle {id: appWindowwidth: 300; height: 300Component.onCompleted: MyScript.createSpriteObjects();
}

下面是componentcreate .js。注意它检查组件状态是否为component。在调用createObject()之前准备好,以防QML文件通过网络加载,因此不能立即准备好。

  var component;var sprite;function createSpriteObjects() {component = Qt.createComponent("Sprite.qml");if (component.status == Component.Ready)finishCreation();elsecomponent.statusChanged.connect(finishCreation);}function finishCreation() {if (component.status == Component.Ready) {sprite = component.createObject(appWindow, {x: 100, y: 100});if (sprite == null) {// Error Handlingconsole.log("Error creating object");}} else if (component.status == Component.Error) {// Error Handlingconsole.log("Error loading component:", component.errorString());}}

如果你确定要加载的QML文件是本地文件,可以省略finishCreation()函数并立即调用createObject():

  function createSpriteObjects() {component = Qt.createComponent("Sprite.qml");sprite = component.createObject(appWindow, {x: 100, y: 100});if (sprite == null) {// Error Handlingconsole.log("Error creating object");}}

注意,在这两个例子中,调用 createObject() 时都将 appWindow 作为父参数,因为动态创建的对象是一个可视化(Qt Quick)对象。创建的对象将成为 main.qml 中的 appWindow对象的一个子对象,并出现在场景中。

当使用具有相对路径的文件时,路径应该相对于Qt.createComponent()执行的文件。 路径都是相对于 有这个 Qt.createComponent() 函数的文件位置

要将信号连接到(或从)动态创建的对象中接收信号,可以使用signal connect()方法。通过incubateObject()函数也可以实例化组件而不会阻塞。为该组件创建实例。这个函数的创建过程允许异步实例化新的组件实例,并且不会导致UI冻结。

  var component = Qt.createComponent("Button.qml");var incubator = component.incubateObject(parent, { x: 10, y: 10 });if (incubator.status != Component.Ready) {incubator.onStatusChanged = function(status) {if (status == Component.Ready) {print ("Object", incubator.object, "is now ready!");}}} else {print ("Object", incubator.object, "is ready immediately!");}

四、从QML字符串创建对象

如果QML在运行时才定义,可以使用Qt.createQmlObject()函数从QML字符串创建QML对象,如下面的例子所示:

var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',parentItem,"dynamicSnippet1");
  • 第一个参数是要创建的QML字符串。就像在新文件中一样,你需要导入想要使用的任何类型。
  • 第二个参数是新对象的父对象,适用于组件的父参数语义同样适用于createQmlObject()。
  • 第三个参数是要关联到新对象的文件路径。这用于错误报告。

如果QML字符串使用相对路径导入文件,则该路径应该相对于定义父对象(方法的第二个参数)的文件。

重要提示:在构建静态QML应用程序时,将扫描QML文件以检测导入依赖关系。这样,所有必要的插件和资源都在编译时解决。但是,只考虑显式的import语句(在QML文件顶部的那些语句),而不考虑包含在字符串字面量中的import语句。为了支持静态构建,因此需要确保QML文件使用Qt.createQmlObject(),在文件的顶部显式地包含所有必要的导入,除了在字符串字面量内部。也就是说 要明确的 写好 'import QtQuick 2.0;’ 这个部分的东西。

五、维护动态创建的对象

在管理动态创建的对象时,必须确保创建上下文的寿命比创建的对象长。否则,如果创建上下文首先被销毁,动态对象中的绑定和信号处理程序将不再工作。也就是说这个 创建这个动态对象的所在对象必须寿命要比这个创建对象的长,这个才符号逻辑。

实际的创建上下文取决于对象是如何创建的:

  • 如果使用Qt.createComponent(),则创建上下文是调用此方法的QQmlContext
  • 如果调用Qt.createQmlObject(),则创建上下文是传递给该方法的父对象的上下文
  • 如果定义了一个Component{}对象,并且在该对象上调用了createObject()或incubateObject(),那么创建上下文就是定义该组件的上下文

另外,请注意,虽然动态创建的对象可以与其他对象一样使用,但它们在QML中没有id

六、动态删除对象

在许多用户界面中,只要将可视对象的不透明度设置为0,或者将其移出屏幕而不是删除就足够了。但是,如果你有很多动态创建的对象,如果删除未使用的对象,你可能会获得值得的性能提升。

请注意,永远不要手动删除由便利的QML对象工厂动态创建的对象(如Loader和Repeater)。此外,应该避免删除不是自己动态创建的对象。

可以使用destroy()方法删除元素。这个方法有一个可选参数(默认值为0),指定对象被销毁前的近似延迟时间(以毫秒为单位)。
这里有一个例子。application.qml 创建了 SelfDestroyingRect.qml 的五个实例。每个实例都会运行一个NumberAnimation,动画结束后,调用根对象的 destroy() 方法销毁自己:

在这里插入图片描述

application.qml

import QtQuick 2.0Item {id: containerwidth: 500; height: 100Component.onCompleted: {var component = Qt.createComponent("SelfDestroyingRect.qml");for (var i=0; i<5; i++) {var object = component.createObject(container);object.x = (object.width + 10) * i;}}}

SelfDestroyingRect.qml

import QtQuick 2.0Rectangle {id: rectwidth: 80; height: 80color: "red"NumberAnimation on opacity {to: 0duration: 4000onRunningChanged: {if (!running) {console.log("Destroying...")rect.destroy();}}}}

或者,application.qml 可以通过调用 object.destroy() 来销毁创建的对象。

注意,在该对象内的对象上调用destroy()是安全的。对象不会在destroy()被调用的瞬间被销毁,而是会在脚本块结束和下一帧之间的某个时间被清理(除非你指定了一个非零的延迟)。

还要注意,如果像下面这样静态地创建一个SelfDestroyingRect实例:

  Item {SelfDestroyingRect {// ...}}

这将导致错误,因为只有动态创建的对象才能被动态销毁。

用Qt.createQmlObject()创建的对象同样可以使用destroy()来销毁:

var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',parentItem,"dynamicSnippet1");
newObject.destroy(1000);

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...