您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
Qt Quick 组件与对象动态创建详解(二)
 
作者 WPJY的博客,火龙果软件    发布于 2014-08-12
   次浏览      
 

利用 Loader 动态创建与销毁组件

现在我们看看如何动态创建、销毁组件。下面是 dynamic_component.qml :

import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
width: 320;
height: 240;
color: "#EEEEEE";
id: rootItem;
property var colorPickerShow : false;

Text {
id: coloredText;
anchors.horizontalCenter: parent.horizontalCenter;
anchors.top: parent.top;
anchors.topMargin: 4;
text: "Hello World!";
font.pixelSize: 32;
}

Button {
id: ctrlButton;
text: "Show";
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;

onClicked:{
if(rootItem.colorPickerShow){
redLoader.source = "";
blueLoader.source = "";
rootItem.colorPickerShow = false;
ctrlButton.text = "Show";
}else{
redLoader.source = "ColorPicker.qml";
redLoader.item.colorPicked.connect(onPickedRed);
blueLoader.source = "ColorPicker.qml";
blueLoader.item.colorPicked.connect(onPickedBlue);
redLoader.focus = true;
rootItem.colorPickerShow = true;
ctrlButton.text = "Hide";
}
}
}

Loader{
id: redLoader;
anchors.left: ctrlButton.right;
anchors.leftMargin: 4;
anchors.bottom: ctrlButton.bottom;

KeyNavigation.right: blueLoader;
KeyNavigation.tab: blueLoader;

onLoaded:{
if(item != null){
item.color = "red";
item.focus = true;
}
}

onFocusChanged:{
if(item != null){
item.focus = focus;
}
}
}

Loader{
id: blueLoader;
anchors.left: redLoader.right;
anchors.leftMargin: 4;
anchors.bottom: redLoader.bottom;
KeyNavigation.left: redLoader;
KeyNavigation.tab: redLoader;

onLoaded:{
if(item != null){
item.color = "blue";
}
}

onFocusChanged:{
if(item != null){
item.focus = focus;
}
}
}

function onPickedBlue(clr){
coloredText.color = clr;
if(!blueLoader.focus){
blueLoader.focus = true;
redLoader.focus = false;
}
}

function onPickedRed(clr){
coloredText.color = clr;
if(!redLoader.focus){
redLoader.focus = true;
blueLoader.focus = false;
}
}
}

这次我们在界面上放一个按钮,通过按钮来控制颜色选择组件的创建与销毁。启动应用时没有创建颜色选择组件,如图 4 所示:

图 4 动态创建组件初始效果

当你点击 "Show" 按键,代码通过设置 redLoader 和 blueLoader 的 source 来创建颜色选择组件,连接颜色组件的 colorPicked 信号到相应的方法,同时将改变按钮文字,也改变 rootItem 维护的颜色组件是否显示的标志位以便下次再点击按钮可以正常显示。图 5 是颜色选择组件显示后的效果图:

图 5 颜色组件创建后的效果

使用 Loader 控制组件的动态创建与销毁,只是 Qt Quick 提供的动态维护对象的两种方式中的一种。还有一种,是在 JavaScript 中动态创建 QML 对象。

在 JavaScript 中动态创建 QML 对象

ML 支持在 JavaScript 中动态创建对象。这对于延迟对象的创建、缩短应用的启动时间都是有帮助的。同时这种机制也使得我们可以根据用户的输入或者某些事件来动态的将可见元素添加到应用场景中。

在 JavaScript 中,有两种方式可以动态地创建对象:

使用 Qt.createComponent() 动态地创建一个组件对象,然后使用 Component 的 createObject() 方法创建对象

使用 Qt.createQmlObject() 从一个 QML 字符串直接创建一个对象

如果你在一个 qml 文件中定义了一个组件(比如我们的 ColorPicker ),而你想动态地创建它的实例,使用 Qt.createComponent() 是比较好的方式;而如果你的 QML 对象本身是在应用运行时产生的,那 Qt.createQmlObject() 可能是比较好的选择。

从组件文件动态创建 Component

Qt 对象的 createComponent() 方法可以根据 QML 文件动态的创建一个组件。一旦你拥有了组件对象,就可以调用它的 createObject() 方法创建一个组件的实例。下面是我们新的示例, qml 文件是 qt_create_component.qml :

import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: rootItem;
width: 360;
height: 300;
property var count: 0;
property Component component: null;

Text {
id: coloredText;
text: "Hello World!";
anchors.centerIn: parent;
font.pixelSize: 24;
}

function changeTextColor(clr){
coloredText.color = clr;
}

function createColorPicker(clr){
if(rootItem.component == null){
rootItem.component = Qt.createComponent("ColorPicker.qml");
}
var colorPicker;
if(rootItem.component.status == Component.Ready) {
colorPicker = rootItem.component.createObject(rootItem, {"color" : clr, "x" : rootItem.count *55, "y" : 10});
colorPicker.colorPicked.connect(rootItem.changeTextColor);
}

rootItem.count++;
}

Button {
id: add;
text: "add";
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
onClicked: {
createColorPicker(Qt.rgba(Math.random(), Math.random(), Math.random(), 1));
}
}
}

图 6 是示例启动后的界面:

图 6 qt create component 初始效果

图 7 是我点击了 6 次 "add" 按钮后的效果:

图 7 动态创建了颜色选择组件

好啦,现在让我们来看看代码。

我在 qt_create_component.qml 中定义了 createColorPicker() 函数,该函数的参数是颜色值,它根据颜色值来创建一个颜色选择组件实例。首先它判断 rootItem 的 component 属性如果为 null ,就调用 Qt.createComponent() 创建一个 ColorPicker 组件,然后调用 Component.createObject() 创建一个颜色选择组件实例。 createObject() 方法有两个参数,第一个参数用来指定创建出来的 item 的 parent ,第二个参数用来传递初始化参数给待创建的 item ,这些参数以 key - value 的形式保存在一个对象中。我在创建颜色组件实例时,传递颜色、 x 、 y 三个属性给待创建的 item ,于是你看到了,那些色块都在界面顶部。创建了颜色选择组件实例,我调用 colorPicked 信号的 connect() 方法,连接 rootItem 的 changeTextColor 方法,以便用户点击色块时改变 "Hello World!" 文本的颜色。

再来看 "add" 按钮,它的 onClicked 信号处理器,调用 Math 对象的随机函数 random() 和 Qt.rgba() ,随机生成一个 Color 对象,传递给 createColorPicker() 方法来创建指定颜色的颜色选择组件实例。

提一下,对于嵌入在 qml 文档内定义的 Component ,因为 Component 对象是现成的,可以略去 Qt.createComponent() 调用,直接使用 createObject() 方法创建组件实例。

代码就这么简单,解说到此为止。现在让我们看看怎么使用 Qt.createQmlObject() 来创建对象。

从 QML 字符串创建对象

如果你的软件,需要在运行过程中,根据应用的状态适时的生成用于描述对象的 QML 字符串,进而根据这个 QML 字符串创建对象,那么可以使用像下面这样:

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

createQmlObject 的第一个参数是要创建对象的 QML 字符串,就像一个 QML 文档一样,你需要导入你用到的所有类型和模块;第二个参数用于指定要创建的对象的父对象;第三个参数,用于给新创建的对象关联一个文件路径,主要用于报告错误。

对于动态创建的对象,该如何销毁呢?

销毁动态创建的对象

有些软件,在不需要一个动态创建的 QML 对象时,仅仅是把它的 visible 属性设置为 false 或者把 opactity 属性设置为 0 ,而不是删除这个对象。如果动态创建的对象很多,无用的对象都这么处理而不直接删除,那会给软件带来比较大的性能问题,比如内存占用增多,运行速度变慢等等。所以呢,动态创建的对象,不再使用时,最好把它删除掉。

我们这里说的动态创建的对象,特指使用 Qt.createComponent() 或 Qt.createQmlObject() 方法创建的对象, 使用 Loader 创建的对象,应当通过将 source 设置为空串或将 sourceComponent 设置为 undefined 触发 Loader 销毁它们。

要删除一个对象,可以调用其 destroy() 方法。 destroy() 方法有一个可选参数,指定延迟多少毫秒再删除这个对象,其默认值为 0 。 destroy() 方法有点儿像 Qt C++ 中 QObject 的 deleteLater() 方法,即便你设定延迟为 0 去调用它,对象也并不会立即删除,QML 引擎会在当前代码块执行结束后的某个合适的时刻删除它们。所以呢,即便你在一个对象内部调用 destroy() 方法也是安全的。

现在让我我们再来一个实例,看看如何销毁对象。新的 qml 文件命名为 delete_dynamic_object.qml ,从 qt_create_component.qml 拷贝而来,作了一点点修改。先看下:

import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: rootItem;
width: 360;
height: 300;
property var count: 0;
property Component component: null;

Text {
id: coloredText;
text: "Hello World!";
anchors.centerIn: parent;
font.pixelSize: 24;
}

function changeTextColor(clr){
coloredText.color = clr;
}

function createColorPicker(clr){
if(rootItem.component == null){
rootItem.component = Qt.createComponent("ColorPicker.qml");
}
var colorPicker;
if(rootItem.component.status == Component.Ready) {
colorPicker = rootItem.component.createObject(rootItem, {"color" : clr, "x" : rootItem.count *55, "y" : 10});
colorPicker.colorPicked.connect(rootItem.changeTextColor);
//[1] add 3 lines to delete some obejcts
if(rootItem.count % 2 == 1) {
colorPicker.destroy(1000);
}
}

rootItem.count++;
}

Button {
id: add;
text: "add";
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
onClicked: {
createColorPicker(Qt.rgba(Math.random(), Math.random(), Math.random(), 1));
}
}
}

修改的部分我用注释标注出来了:添加了三行代码,新创建的颜色选择组件实例,隔一个删一个, destroy(1000) 调用指示对象在 1 秒后删除。

图 8 是运行后的效果图:

图 8 删除动态创建的对象

我还制作了一个演示删除动态创建的对象的示例, qml 文件是 delete_dynamic_object2.qml ,我把点击 "add" 按钮创建的对象保存在一个数组中,当你点击 "del" 按钮时,删除最后添加的那个颜色选择组件实例。下面是代码:

import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
id: rootItem;
width: 360;
height: 300;
property var count: 0;
property Component component: null;
property var dynamicObjects: new Array();

Text {
id: coloredText;
text: "Hello World!";
anchors.centerIn: parent;
font.pixelSize: 24;
}

function changeTextColor(clr){
coloredText.color = clr;
}

function createColorPicker(clr){
if(rootItem.component == null){
rootItem.component = Qt.createComponent("ColorPicker.qml");
}
var colorPicker;
if(rootItem.component.status == Component.Ready) {
colorPicker = rootItem.component.createObject(rootItem, {"color" : clr, "x" : rootItem.dynamicObjects.length *55, "y" : 10});
colorPicker.colorPicked.connect(rootItem.changeTextColor);
rootItem.dynamicObjects[rootItem.dynamicObjects.length] = colorPicker;
console.log("add, rootItem.dynamicObject.length = ", rootItem.dynamicObjects.length);
}
}

Button {
id: add;
text: "add";
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
onClicked: {
createColorPicker(Qt.rgba(Math.random(), Math.random(), Math.random(), 1));
}
}
Button {
id: del;
text: "del";
anchors.left: add.right;
anchors.leftMargin: 4;
anchors.bottom: add.bottom;
onClicked: {
console.log("rootItem.dynamicObject.length = ", rootItem.dynamicObjects.length);
if(rootItem.dynamicObjects.length > 0){
var deleted = rootItem.dynamicObjects.splice(-1, 1);
deleted[0].destroy();
}
}
}
}

你可以自己使用 qmlscene 运行 delete_dynamic_object2.qml 看看效果。

   
次浏览       
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...