该系列教程主要讲授有关QML的实用经验,不建议完全没有Qt经验的童鞋阅读(不包括熟悉Qt C++不懂QML的)
初学QML的童鞋,也许刚刚懂得怎么用一些基本element的用法和一些动画效果,或许童鞋们会发现,QML除了显示源码上的那些控件外,能不能按照逻辑动态增加/减少一些东西呢?比如鼠标点一下多一个气球,再点一下气球就消失,总不可能先在代码里面写上几百上千个气球的代码再一个个去显示吧 (;´༎ຶД༎ຶ`)
1.官方文档
在QT帮助文档里面,搜索“Dynamic QML Object Creation from JavaScript”即可找到我下文要写的大部分内容,英文好的童鞋可以直接忽略我的教程看这个。
2.几种常用动态qml方法
2.1 MVC
相信大部分童鞋都知道什么是MVC,概念我不说了,在qml这里其实就是listview,gridview这类东东。我把这类摆第一位主要因为这种最常用到也是最容易学的。
来一段示例代码,无关的属性什么的我就不详细写了,多看看官方文档:
-
-
Rectangle {
-
color: "blue"
-
MouseArea { onClicked: { modelMVC.add( { /*随便加点东东*/ } ) } } // 每点一次这个就可以动态加东西
-
}
-
-
Listview { // 这个就是V
-
id: listviewMVC
-
model: modelMVC // 这个就是M
-
delegate: delegateMVC // 这个就是C
-
-
Component {
-
id: delegateMVC
-
Rectangle {
-
color: "red"
-
MouseArea { anchors.fill: parent; onClicked: { modelMVC.remove(index) } } // 每点一次这个就可以去掉自己
-
}
-
}
-
-
Listmodel {
-
id: modelMVC
-
}
-
}
-
复制代码
实际运行效果,listview初始化后就是一个列表,列表的多少完全由model控制,这样动态的添加和删除就只需要操作这个model就行了,上面例子就是add和remove两个函数而已。
2.2 Loader
确切来说Loader和MVC一样不能算完全动态的qml,因为都需要一个静态的外壳,MVC的外壳就好理解了,那Loader又是什么东东?
如果等效成C++来看,Loader就类似一个指针,如果只写了一个Loader在qml里面,其实就相当于一个空指针,没意义。如果想要它有意义,只需要指定内容就行了,类似C++的new。
下面是一个空Loader例子:
-
-
Loader {
-
id: loader
-
source: ""
-
sourceComponent: undefined
-
}
-
复制代码
这个空Loader除了占地方外,没有任何意义,因为就相当于一个空指针。
这里稍微解释一下Loader的用法,具体请查看文档:
source里面加入qml文件的地址就能加载这个qml文件的内容;
sourceComponent指定某个qml代码片段,一般指Component类型;
以上两者不能同时使用
当加入内容后,代码如下:
-
-
Loader {
-
id: loader
-
// 这里最好先设定好大小,不然可能会因为大小没定而不显示东西
-
source: "TestComponent.qml"
-
}
-
复制代码
Loader就会把TestComponent.qml的内容都加载进内存中并显示出来,这里要注意的是,Loader里面的东西和外面是半隔离状态的,就是外面只能看到Loader外壳,反之透明。如果需要访问Loader里面的内容需要使用Loader.item来访问。
来一小段代码示范
-
-
function testLoader () {
-
//先访问loader内容,然后清空loader
-
print(loader.item.text) //我乱编的属性
-
loader.source = "" //清空的方法很多,文档有写
-
}
-
复制代码
2.3 Dynamic QML Object Creation from JavaScript (来自JS的动态qml对象加载)
详情可以直接在文档中搜这段英文,英文好的童鞋可以跳过我这段。
这种方法相对于前两种,是真正的完全动态生成qml对象,用法也很灵活,当然代价也是不太容易学会。
先介绍如何创建动态的qml对象:
准备好一个组件:
-
-
import QtQuick 2.0
-
Rectangle { width: 80; height: 50; color: "red" }
-
复制代码
然后是一段js代码,用来创建qml对象
-
-
var component;
-
var sprite;
-
-
function createSpriteObjects() {
-
component = Qt.createComponent("Sprite.qml"); // 这个可以理解为预加载qml文件
-
if (component.status == Component.Ready)
-
finishCreation();
-
else
-
component.statusChanged.connect(finishCreation); // c++里面的connect在qml里面的用法之一
-
}
-
-
function finishCreation() {
-
if (component.status == Component.Ready) {
-
sprite = component.createObject(appWindow, {"x": 100, "y": 100}); // 这个才是关键地方, 在内存中生成qml对象
-
if (sprite == null) {
-
// Error Handling
-
console.log("Error creating object");
-
}
-
} else if (component.status == Component.Error) {
-
// Error Handling
-
console.log("Error loading component:", component.errorString());
-
}
-
}
-
复制代码
只要调用上面的js代码就能随时随地创建qml对象了
-
-
import QtQuick 2.0
-
import "componentCreation.js" as MyScript
-
-
Rectangle {
-
id: appWindow
-
width: 300; height: 300
-
-
Component.onCompleted: MyScript.createSpriteObjects(); // 这里调用上面的js代码段
-
}
-
复制代码
同样的稍微再改一下就能用鼠标来控制创建
-
-
import QtQuick 2.0
-
import "componentCreation.js" as MyScript
-
-
Rectangle {
-
id: appWindow
-
width: 300; height: 300
-
-
MouseArea {
-
anchors.fill: parent
-
onClicked: MyScript.createSpriteObjects(); // 这里调用上面的js代码段
-
}
-
}
-
复制代码
那么如果我想让创建的qml对象消失呢?很简单,调用destroy函数即可。这里回到上面的qml文件,改成下面
-
-
import QtQuick 2.0
-
Rectangle {
-
width: 80; height: 50; color: "red"
-
MouseArea {
-
anchors.fill: parent
-
onClicked: parent.destroy() // 必须给根对象用这个destroy函数,不然会出错
-
}
-
}
-
复制代码
到这里,qml动态创建和销毁基本就这样了,其实这个方法也是官方极力推荐的,建议大家多用。
有童鞋看到这里可能有疑问,这些动态的对象没有id我怎么去操作啊?——没错,qml里面非静态的对象基本上没有id可言,操作这些对象就要用到qt特有的功能——signal & slot
继续用上面的代码:
-
-
import QtQuick 2.0
-
Rectangle {
-
width: 80; height: 50; color: "red"
-
-
signal test() // 声明一个信号
-
-
Component.onCompleted: test.connect(/* 随便指定一个外部函数即可,如appWindow.slot,注意这里不需要加括号 */)
-
// 用法是 <对象名(省略的话就是自己)>. <信号名>.connect(<普通函数名>)
-
-
MouseArea {
-
anchors.fill: parent
-
onClicked: parent.destroy() // 必须给根对象用这个destroy函数,不然会出错
-
}
-
}
-
复制代码
同样道理,外面的信号也能这样连到动态对象的函数
注:方法2.3还有另一种我个人觉得不怎么好用的创建qml方式,如下:
-
-
var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
-
parentItem, "dynamicSnippet1");
-
复制代码
本次教程暂告一段落,欢迎高手们拍砖。 ლ(╹◡╹ლ) (┙>∧<)┙へ┻┻