一本QML教学书, 基于QT5 : https://github.com/cwc1987/QmlBook-In-Chinese
QML介绍
QML 是一种基于 JavaScript 的声明式语言, 而且源码中为一个对象树结构.
在QT5下, 可使用Bin目录下的 qmlscene
程序进行直接运行符合QML语法的 *.qml
文件,
import QtQuick 2.1
import QtQuick.Window 2.0
Window {
visible: true
width: 360
height: 360
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
}
一个 QML 文档分为 import
和 declaration
两部分。前者用于引入文档中所需要的组件(有可能是类库,也可以是一个 JavaScript 文件或者另外的 QML 文件);后者用于声明本文档中的 QML 元素。
每一个 QML 有且只有一个根元素,类似于 XML 文档。这个根元素就是这个 QML 文档中定义的 QML 元素
QML 是一种声明语言,用于描述程序界面。
QML 将用户界面分解成一块块小的元素,每一元素都由很多组件构成。
QML 定义了用户界面元素的外观和行为;更复杂的逻辑则可以结合 JavaScript 脚本实现。这有点类似于HTML 和 JavaScript 的关系,前者用来显示界面,后者用来定义行为。
QML 最简单的元素关系是层次关系。子元素处于相对于父元素的坐标系统中。也就是说,子元素的 x 和 y 的坐标值始终相对于父元素。
定义变量(property)
一般用于导出对象和变量, 或者定义一个新的变量
自定义 QML
属性: property <type> <name> : <value>
声明属性的别名: property alias <name> : <reference>
比如:
导出内部对象的名称 | property alias text: input.text |
---|---|
导出内部对象 | property alias input: input |
定义一个变量 | property int colorIndex: Math.floor(Math.random()*3) |
定义一个变量数组 | property variant colorArray: ["#00bde3", "#67c111", "#ea7025"] |
如果你想要完整的导出TextInput对象的元素,你可以使用
property alias input: input
来导出这个元素。第一个input是属性名字,第二个input是元素id。
键值对
在使用属性键值 X,Y 或者 Width,Height 时, 需同时定义在一行, 分行时, 容易出错
x: 112 ; y: 12
width: 76; height: 96
渐变色
gradient: Gradient {
GradientStop { position: 0.0; color: "lightsteelblue" } // 渐变的开始
GradientStop { position: 1.0; color: "slategray" } // 渐变的结束
}
// 一个矩形框如果没有width/height(宽度与高度)将不可见。
// 如果你有几个相互关联width/height(宽度与高度)的矩形框,
// 在你组合逻辑中出了错后可能就会发生矩形框不可见,请注意这一点。
定位
注意:
高级的大数据模型处理和使用动态代理的动态视图会在模型与视图(model-view)章节中讲解。当有一小部分的静态数据需要显示时,使用重复元素是最好的方式
column(列, 在一列中布局行)
row(在一行中布局列)
Grid(栅格)
Flow(流)
Repeater(自动重复控件布局)
文本输入 (TextInput - TextEdit)
TextInput | 允许使用正则表达式验证器来限制输入和输入掩码模式的设置 |
---|---|
TextEdit | 支持多行输入, 不支持文本输入监测限制 |
焦点(focus - focus scope)
一个焦点区域(focus scope)定义了如果焦点区域接收到焦点,它的最后一个使用focus:true的子元素接收焦点,它将会把焦点传递给最后申请焦点的子元素。我们创建了第二个版本的TLineEdit组件,称作TLineEditV2,使用焦点区域(focus scope)作为根元素。
ListView(列表框)
// 裁剪显示, 允许出现上下临界元素显示一半的情况
clip: true
// 默认值, 在末尾可继续拖拽,自动回弹
boundsBehavior: Flickable.DragAndOvershootBounds
// 拖拽至末尾后, 无法继续拖拽
boundsBehavior: Flickable.StopAtBounds
// 每次滚动之后, 顶部会对齐到整个元素, 不会显示一半
snapMode: ListView.SnapToItem
// 每次滚动之后, 顶部会停止在第一个可见元素
snapMode: ListView.SnapOneItem
// 链表视图的方向由属性orientation控制。
// 它能够被设置为默认值ListView.Vertical或者ListView.Horizontal。
orientation: ListView.Vertical
orientation: ListView.Horizontal
// 可以通过设置layoutDirection属性来控制元素顺序方向,
// 它可以设置为Qt.LeftToRight或者Qt.RightToLeft。
layoutDirection: Qt.LeftToRight
layoutDirection: Qt.RightToLeft
高亮显示
highlight: highlightComponent
focus: true
Component {
id: highlightComponent
Rectangle {
width: ListView.view.width
// width: lstView.view.width
color: "lightGreen"
}
}
// 高亮与元素距离不相关
// highlightRangeMode: ListView.NoHighlightRange
// 高亮, 且默认显示第一个为当前选中
// highlightRangeMode: ListView.StrictlyEnforceRange
// 默认下速度被设置为每秒400像素,动作持续时间为-1
// highlightMoveSpeed // 控制每项元素之间切换速度
// highlightMoveDuration // 控制移动时, 运动持续时间
// highlightResizeSpeed //
// highlightResizeDuration
// 设置高亮的移动, 不自动控制, 需要自行实现Bahavior
//highlightFollowCurrentItem: false
使用 Behavior
自行实现高亮移动
Component {
id: highlightComponent
Item {
width: ListView.view.width
height: ListView.view.currentItem.height
y: ListView.view.currentItem.y
Behavior on y {
SequentialAnimation {
PropertyAnimation{ target: highlightRectangle; property: "opacity"; to: 0; duration: 150 }
NumberAnimation { duration: 1 }
PropertyAnimation{ target: highlightRectangle; property: "opacity"; to: 1; duration: 150 }
}
}
Rectangle {
id: highlightRectangle
anchors.fill: parent
color: "lightGreen"
}
}
}
Tips
鼠标响应无效
应该鼠标响应在前, 然后对象申明定义在后, 否则会出现鼠标点击无效的状况. 暂未知具体原因
有一个解释, 没有看懂:
在代码中先出现的元素有更低的堆叠顺序(叫做z顺序值z-order),如果你点击火箭1足够多次,你会看见火箭1移动到了火箭2下面。z轴顺序也可以使用元素对象的z-property来控制。
由于火箭2后出现在代码中,火箭2将会放在火箭1上面。这同样适用于MouseArea(鼠标区域),一个后出现在代码中的鼠标区域将会与之前的鼠标区域重叠,后出现的鼠标区域才能捕捉到鼠标事件。
既然后定义的会覆盖, 为什么需要给MouseArea 定义在前边才能生效呢? 暂未知具体原因
以下分别为可以点击生效的代码 和 不可生效的代码:
在我个人的理解中: 对象未出现, 无法直接使用, 所以应该后定义鼠标事件, 但在实际情况中 后定义的鼠标事件并未生效, 暂未知具体原因
QML 同目录下的模块使用
注意: 被使用的模块所在文件的文件名, 首字母必须大写