QML 语言基础
在《Qt Quick 简单介绍》中我们提到 QML 语法和 Json 相似,请參考《Qt on Android: http下载与Json解析》查看 Json 语法。当然这里我们是期望从零開始也能学会 QML ,所以呢,你也能够直接往下看。
版权全部 foruok,转载请注明出处:http://blog.csdn.net/foruok
对象
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 QtQuick 2.0 这句。会引入 QtQuick 2.0 模块,哇,真是废话!
接着废话吧。
import 和 C++ 中的 #include 相似。与 Java 中的 import 效果一样。与 JavaScript 中的……唐僧了,打住。
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"; }我强烈建议你不要这么干!除非有代码意外的原因,比方排版须要。比方老板认为你代码行数太多……
表达式
在《Qt Quick 简单介绍》中笔者已经提到。 QML 支持 JavaScript 表达式。
比方你能够这样改写 Rectangle 对象的宽、高属性:
Rectangle { width: 23*10; height: 6*80; 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; } }
属性
事实上, QML 中的属性。就是我们非常熟悉的 C++ 中的成员变量……
属性命名
属性名的首字母一般以小写開始,如我们看烦了的 width 属性。
假设属性名以多个单词表示,那么第二个及以后的单词,首字母大写。
属性类型
能够在 QML 文档中使用的类型大概有三类:
- 由 QML 语言本身提供的类型
- 使用 QML 模块注冊 C++ 类型
- 由 QML 模块提供的类型
我们先看 QML 语言提供的基本类型。
基本类型
QML 支持的基本类型包括整型、实数型、布尔、字符串、颜色、列表等等。
这些基本类型有些是和 JavaScript 语言的基本类型相应的。
还是之前的演示样例,改动了一下,通过凝视标注了属性类型:
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 页面来查看完整的类型列表和每个类型的详情。
Qt 的 QML 模块还未 QML 引入的非常多 Qt 相关的类型,如 Qt 、 QtObject 、Component 、 Connections 、 Binding 等,请使用 Qt 助手检索 "qt qml qml types" 来了解。
id 属性
之前在介绍表达式时提到了 id 属性,这里展开描写叙述一下。
一个对象的 id 属性是唯一的,在同一个 QML 文件里不同对象的 id 属性的值不能反复。当给一个对象指定了 id ,就能够在其他对象或脚本中通过 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 :{} 。这是什么东东呢?接下来我们就来讲它。
信号处理器
信号处理器。事实上等价于 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 起始后跟信号名字(第一个字母大写)。
分组属性
在某些情况下使用一个 '.' 符号或分组符号把相关的属性形成一个逻辑组。分组属性可写以下这样:
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; } } }
版权全部 foruok。转载请注明出处:http://blog.csdn.net/foruok
好啦,关于 QML 语言的基础性介绍就到这里,相信如今你已经能够看懂简单的 QML 文档了。有的同学可能有疑问了。这节另一些东东仅仅见用不见讲啊。比方 Rectangle / Text / Image / Item / Button / Component / Qt 等等,抱歉,如今仅仅能揣着糊涂装明白了。下一篇我们会讲这些东西。