QML 语法和 Json 相似,
QML 文件的后缀是 qml ,事实上就是个文本文件。以下是 一个简单的 QML 文件:
import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import an.qt.ImageProcessor 1.0
import QtQuick.Controls.Styles 1.1
Rectangle {
width: 320;
height: 480;
color: "#121212";
Image {
source: "images/IMG_001.jpg";
anchors.centerIn: parent;
}
}
这个简单的 QML 文件的開始是 import 语句。import 和 C++ 中的 #include 相似。
对象:
Rectangle{ } 语句。定义了一个类型为 Rectangle 的对象。
假设你看了《Qt on Android: http下载与Json解析》一文中有关 Json 的语法描写叙述。应该已经知道对象要用一对花括号来描写叙述。没错。 QML 里也是这样,只是呢,花括号前要写上对象的类型。就这么简单!
演示样例 QML 文档中有两个对象。一个是 Rectangle 。一个是 Image 。
在花括号之间,是对象的属性描写叙述。属性是以 "property: value" 形式指定的,这点和 Json 一样。
如你所见, Rectangle 对象有 width 、 color 等属性。
属性能够分行书写。此时语句后能够不要 “;” 号,只是笔者建议 C++ 程序员都加上 “;” ,这会避免你患上精神分裂症。
当然,也能够把多个属性写在一行内,多个属性之间必须以 “;” 切割。例如以下所看到的:
Rectangle {
width: 320; height: 480; color: “#121212”;
}
…
表达式 <==> 三目运算符
Button {
text: "Quit";
style: ButtonStyle {
background: Rectangle {
implicitWidth: 70;
implicitHeight: 25;
border.width: control.activeFocus ? 2 : 1;
}
}
}
在这个演示样例中我指定了button风格中的背景矩形。在button有焦点时边框宽度为 2 没有焦点时宽度为 1 。语句 “border.width: control.activeFocus ? 2 : 1” 使用了 JavaScript 的 “?:” 三元云算法( C++ 中貌似也有……)。三目运算符
另外,慧眼如你,可能已经注意到。上面的表达式中我使用了 “control.activeFocus” ,没错,在表达式中能够引用其他对象及其属性。当你这么做的时候。待赋值的属性就和你所引用的对象的那个属性建立了关联,当被引用属性发生变化时。表达式的值会又一次计算。而待赋值的属性也会变化。
引用对象
通过对象的 id 值来引用一个对象。
Rectangle {
width: 320;
height: 480;
Button {
id: openFile;
text: "打开";
anchors.left: parent.left;
anchors.leftMargin: 6;
anchors.top: parent.top;
anchors.topMargin: 6;
}
Button {
id: quit;
text: "退出";
anchors.left: openFile.right;
anchors.leftMargin: 4;
anchors.bottom: openFile.bottom;
}
}
上面的演示样例中,退出button使用 id( openFile )引用了打开button。
我的乖呀,anchors 是什么东东……先别管它,下一篇会讲到。
凝视 <==> 注释
在 QML 中。凝视与 C++ 中一样,单行以 "//" 開始。多行以 "/*" 開始以 "*/" 结束。
使用凝视的演示样例 QML :
/*
* the root element of QML
*/
Rectangle {
width: 320;
height: 480;
Button {
id: quit;
text: "退出";
//use anchors to layout
anchors.left: openFile.right;
anchors.leftMargin: 4;
anchors.bottom: openFile.bottom;
//set z-order
z: 1;
}
}
anchors :是QML的一种布局方法,参看QML布局
属性
属性命名
属性名的首字母一般以小写開始,如我们看烦了的 width 属性。
假设属性名以多个单词表示,那么第二个及以后的单词,首字母大写。
属性类型
能够在 QML 文档中使用的类型大概有三类:
由 QML 语言本身提供的类型
使用 QML 模块注冊 C++ 类型
由 QML 模块提供的类型
我们先看 QML 语言提供的基本类型。
1. 基本类型:整型、实数型、布尔、字符串、颜色、列表等等。
Rectangle {
width: 320; //int
height: 480;
Button {
id: quit;
text: "退出"; //string
anchors.left: openFile.right;
anchors.leftMargin: 4;
anchors.bottom: openFile.bottom;
z: 1.5; // real
visible: false; //bool
}
}
注意。 QML 中属性是有类型安全检測的,也就是说你仅仅能指定与属性类型匹配的值。否则会报错。
请使用 Qt 助手的索引模式。以"qml basic types " 为keyword检索。找到 QML Basic Types 页面来查看完整的类型列表和每个类型的详情。
2. Qt 的 QML 模块
还为 QML 引入的非常多 Qt 相关的类型,如 Qt 、 QtObject 、Component 、 Connections 、 Binding 等,请使用 Qt 助手检索 “qt qml qml types” 来了解。
-
id 属性
之前在介绍表达式时提到了 id 属性,这里展开描写叙述一下。
请注意, id 属性的值,首字符必须是小写字母或下划线而且不能包括字母、数字、下划线以外的字符。 -
列表属性
列表属性相似于以下这样:
Item {
children:[
Image{},
Text{}
]
}
列表是包括在方括号内,以逗号分隔的列表元素。看起来是不是挺熟悉?在《Qt on Android: http下载与Json解析》中。我们举过 Json 数组的样例。再看看:
[
"name":"zhangsan",
{
"age":30,
"phone":"13588888888",
"other": ["xian", null, 1.0, 28]
}
]
事实上列表和 JavaScript 的数组是相似的,其訪问方式也一样:
length 属性提供了列表内元素的个数
列表内的元素通过数组下标来訪问([index])
值得注意的是,列表内仅仅能包括 QML 对象,不能包括不论什么基本类型(如整型、布尔型)。这点与 Json 是不一样的。以下是訪问列表的演示样例:
Item {
children:[
Text{
text: "textOne";
},
Text{
text: "textTwo";
}
]
Component.onCompleted:{
for (var i = 0; i < children.length; i++)
console.log("text of label ", i, " : ", children[i].text)
}
}
假设你一个列表内仅仅有一个元素,也能够省略方括号。例如以下所看到的:
Item {
children:Image{}
}
只是笔者还是建议你始终使用方括号。哪怕当中仅仅有一个元素。
Component.onCompleted :{} 。参看本文“信号处理器”。
-
分组属性
在某些情况下使用一个 ‘.’ 符号或分组符号把相关的属性形成一个逻辑组。分组属性可写以下这样:
Text {
font.pixelSize: 18;
font.bold: true;
}
也能够这样写:
Text {
font { pixelSize: 12; bold: true; }
}
事实上呢,能够这么理解。font 属性的类型本身是一个对象,这个对象又有 pixelSize / bold / italic / underline 等等属性。
对于类型为对象的属性值,能够使用 “.” 操作符展开对象的每个成员对其赋值。也能够通过分组符号(一对花括号)把要赋值的成员放在一起给它们赋值。对于后者,其形式就和对象的定义一样了,起码看起来木有差别。所以呢。又能够这么理解上面的演示样例: Text 对象内聚合了 font 对象。 OK ,就是聚合。
- 附加属性
到如今还没讲完,不但你烦了,我也快坐不住了。我保证。这是最后一个要点了,只是也是最复杂最难以理解的属性了。对于这样的玩意儿,我一向的做法时。不能理解的话就接受。你就当它生来如此,存在即合理,仅仅要学会怎么用它就 OK 了。
在 QML 语言的语法中,有一个附加属性(attached properties)和附加信号处理器(attached signal handlers)的概念,这是附加到一个对象上的额外的属性。从本质上讲,这些属性是由附加类型(attaching type)来实现和提供的,它们可能被附加到另一种类型的对象上。
附加属性与普通属性的差别在于。对象的普通属性是由对象本身或其基类(或沿继承层级向上追溯的祖先们)提供的。
举个样例。以下的 Item 对象使用了附加属性和附加信号处理器:
import QtQuick 2.0
Item {
width: 100;
height: 100;
focus: true;
Keys.enabled: false;
Keys.onReturnPressed: console.log("Return key was pressed");
}
你看, Item 对象能够訪问和设置 Keys.enabled 和 Keys.onReturnPressed 的值。 enabled 是 Keys 对象的一个属性。
onReturnPressed 事实上是 Keys 对象的一个信号。对于附加信号处理器,和前面讲到的普通信号处理器又有所不同。
普通信号处理器,你先要知道信号名字。然后依照 on{Signal} 的语法来定义信号处理器的名字;而附加信号处理器。你仅仅要通过附加类型名字引用它。把代码块赋值给它就可以。
最后说下 Keys 对象。它是 Qt Quick 提供的,专门供 Item 处理按键事件的对象。它定义了非常多针对特定按键的信号。比方上面的 onReturnPressed ,还定义了更为普通的 onPressed 和 onReleased 信号,一般地,你能够使用这两个信号来处理按键(请对比 Qt C++ 中的 keyPressEvent 和 keyReleaseEvent 来理解)。
它们有一个名字是 event 的 KeyEvent 參数,包括了按键的具体信息。
假设一个按键被处理。 event.accepted 应该被设置为 true 以免它被继续传递。
以下是使用 onPressed 信号的一个演示样例,它检測了左方向键:
Item {
anchors.fill: parent;
focus: true;
Keys.onPressed: {
if (event.key == Qt.Key_Left) {
console.log("move left");
event.accepted = true;
}
}
}
信号处理器
信号处理器。事实上等价于 Qt 中的槽。可是我们没有看到相似 C++ 中的明白定义的函数……没错,就是这样。你的的确确仅仅看到了一对花括号!对啦,这是 JavaScript 中的代码块。事实上呢,你能够理解为它是一个匿名函数。
而 JavaScript 中的函数,事实上具名的代码块。
函数的优点是你能够在其他地方依据名字调用它。而代码块的优点是。除了定义它的地方,没人能调用它,一句话,它是私有的。代码块就是一系列语句的组合。它的作用就是使语句序列一起运行。
让我们回头再看信号处理器,它的名字还有点儿特别,通常是 on{Signal} 这样的形式。比方 Qt Quick 中的 Button 元素有一个信号 clicked() ,那么你要可能会写出这样的代码:
Rectangle {
width: 320;
height: 480;
Button {
id: quit;
text: "退出";
anchors.left: parent.left;
anchors.leftMargin: 4;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 4;
onClicked: {
Qt.quit();
}
}
}
上面的 QML 代码事实上已经是一个简单 QML 应用了,这个应用在窗体的左下角放了个退出button。当用户点击它时会触发button的 clicked() 信号,而我们定义了信号处理器来响应 clicked() 信号——调用 Qt.quit() 退出应用。
你看到了,当信号是 clicked() 时,信号处理器就命名为 onClicked 。就这么简单,以 on 起始后跟信号名字(第一个字母大写)。
参考博文