QML学习笔记
QML语法初见
锚定
- left 左
- right 右
- top 顶部
- bottom 底部
- centerIn 中央
- fill 填充满
- verticalCenter 垂直中央
- horizontalCenter 水平中央
anchors.left: parent //放在父对象左边
rotation 旋转(瞬间旋转)
onClicked: Wheel.rotation += 90 //点击时: Wheel对象旋转90度
动画(让旋转平滑进行)
Image{
id: root
Image {
id: wheel
Behavior on rotation { //每次旋转时的行为
NumberAnimation { //动画
duration: 250 //动画时间: 250ms
}
}
}
}
Qt构建模块(Qt building Blocks)
核心基础模块
模块 | 描述 |
---|---|
Qt Core | 核心的非图形类, 供其他模块使用 |
Qt GUI | 图形用户界面(GUI)组件的基类, 包括OpenGL |
Qt Multimedia | 音频, 视频, 电台, 摄像头的功能类 |
Qt Network | 简化方便的网络编程类 |
Qt QML | QML类与JavaScript语言的支持 |
Qt Quick | 可高度动态创建的自定义应用程序用户界面框架 |
Qt SQL | 集成SQL数据库类 |
Qt Test | Qt应用程序与库的单元测试类 |
Qt WebKit | 集成WebKit2的基础实现并提供了新的QML应用程序接口 |
Qt WebKit Widgets | Widgets来自Qt4中集成WebKit1的窗口基础类 |
Qt Widgets | 扩展Qt GUI模块的C++窗口类 |
- 组织架构如下图:
graph TD;
QtNetwork-->QtCore;
QtQuick-->QtQml;
QtQml-->QtCore;
QtSql-->QtCore;
QtMultimedia-->QtGui;
QtGui-->QtCore;
linkStyle 0 stroke:#aaa,stroke-width:2px;
linkStyle 1 stroke:#aaa,stroke-width:2px;
linkStyle 2 stroke:#aaa,stroke-width:2px;
linkStyle 3 stroke:#aaa,stroke-width:2px;
linkStyle 4 stroke:#aaa,stroke-width:2px;
linkStyle 5 stroke:#aaa,stroke-width:2px;
style QtQuick fill:#f9f,stroke:#000,stroke-width:1px
style QtQml fill:#f9f,stroke:#000,stroke-width:1px
style QtNetwork fill:#f9f,stroke:#000,stroke-width:1px
style QtSql fill:#f9f,stroke:#000,stroke-width:1px
style QtGui fill:#f9f,stroke:#000,stroke-width:1px
style QtCore fill:#f9f,stroke:#000,stroke-width:1px
style QtMultimedia fill:#f9f,stroke:#000,stroke-width:1px
- Qt其他一些附加模块, 根据需要选择性了解, 列举如下:
- Qt 3D 提供3D编程接口
- Qt Bluetooth 多平台蓝牙接口
- Qt Contacts 访问联系人数据的接口
- Qt Location 提供定位, 地图, 导航, 位置搜索等接口
- Qt Organizer 提供组织事件(任务清单, 事件等)接口
- Qt Publish and SubScribe Qt发布与订阅
- Qt Service Framework 允许应用程序读取, 操纵和订阅来改变通知信息
- Qt System Info 发布系统相关的信息和功能
- Qt Versit 支持电子名片和日历数据格式
- Qt Wayland Linux Qt合成器应用程序接口(server), 和Wayland平台插件(clients)
- Qt Feedback 反馈
- Qt JSON DB 对于Qt的一个不使用SQL对象存储
创建Qt工程
新建Qt Quick项目
默认有如下几种模板
- Swipe
- 多个页面左右切换的框架, 下方标签式按钮可点击切换
- Scroll
- 下滑式item框架, 提供多个item下拉, 右侧有滚动条
- Stack
- 压栈式框架, 主页提供菜单, 可进入不同子页面, 子页面返回时, 返回到主页面.
- Empty
- 空项目, 只提供一个Helloworld窗口
第一个HelloWorld程序
- 这里我们选择上述框架中的Empty创建第一个HelloWorld界面程序, 项目名字起名为QML_helloworld吧
- 这个最简单的QML项目, 项目目录如下:
QML_helloworld └─QML_helloworld.pro //项目文件 └─Sources └─main.cpp //cpp文件 └─Resources └─qml.qrc //qrc文件 └─/ └─main.qml //qml文件
- 根据代码, 我们只看到一个cpp文件里, 加载了qml执行, 显示出了一个helloworld窗口, 怎么让qml(界面)和C++代码(数据)联动起来, 还是个未知的大问号.
- 先熟悉下QML语法, 创建一个矩形, 在里面写上文本 "Hello, World", 给他加个退出事件.
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
width: 360
height: 360
color: '#EE00EE'
Text {
id: hello
anchors.centerIn: parent
text: qsTr("Hello, World")
}
MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}
}
}
Qt Quick应用程序优势
- 现代的软件开发中有一个问题, 就是用户常常想改变界面. 或许一个项目换一个领导改一次界面, 这是很常见的, 但后端的改变速度就慢的多了. 传统技术中, 前后端保持相同的步调, 在开发中, 用户想要改变界面常常会引发冲突和矛盾. Qt Quick提供了一个类似HTML的声明式语言作为你的前端, 在后端, 你仍可以使用C++代码, 这样允许两端分离开发.
调试(Debugging)
- QML的调试和Qt程序一样, 在Qt Creator中进行, 介绍一些常用的快捷键
Ctrl+B - 构建项目
Ctrl+R - 运⾏项目
Ctrl+Tab - 切换已打开的⽂档
Ctrl+k - 打开定位器
Esc - 返回
F2 - 查找对应的符号解释。
F4 - 在头⽂件与源⽂件之间切换(只对c++代码有效)
QML入门
QML语法(QML Syntax)
import
- import声明导入了一个指定的模板版本, 如导入QtQuick 2.9来作为初始元素的引用.
import QtQuick 2.9
注释
- 与C++及JavaScript相同, 使用//或/**/注释
元素
- 每个QML文件都需要一个根元素(通常用root命名, 以方便子元素访问)
- 一个元素的内容部分, 使用{}进行包含
- 元素的属性, 按照name: value的格式来复制, name是属性名, value是值.
- 任何在QML文档中的元素都可以使用它们的id进行访问
- 元素可以嵌套, 一个父元素可以嵌套多个和多层子元素, 子元素可以使用parent关键字来访问它们的父元素
预览
- 可以用以下命令预览qml效果, $QTDIR替换为你的Qt安装路径
$ $QTDIR/bin/qmlscene exm.qml
属性的特点
- id是一个特殊的属性值, 它在一个QML文件中被用来引用元素, 一个id在一个QML中是唯一的, 并且不能被修改为其他值, 也无法被查询, 它的行为类似C++中的指针.
- 一个属性能够设置一个值, 这个值依赖于它的类型. 如果没有对一个属性赋值, 那么它将会被初始化为默认值, 具体可查阅特定元素的文档.
- 属性绑定
- 一个属性能够依赖一个或多个其它属性, 这种操作被称为属性绑定. 当它依赖的属性改变时, 它的值也对应更新.
- 添加自己定义的属性时, 需要使用property修饰符, 然后跟上类型, 名字和可选择的初始化值(property: ). 如果没有初始值, 将会给定一个系统初始值为初始值. 如果属性名与已定义的默认属性名不重复, 使用default关键字你可以将一个属性定义为默认属性.
- 另一个声明属性的方法是使用alias关键字(property alias: ). 该关键字允许我们转发一个属性或者转发一个属性对象本身到另一个作用域(即属性别名). 属性别名不需要类型, 它使用引用的属性类型或者对象类型.
- 按组分配的属性
- 如font的属性是按组分配的
font.family: "Ubuntu" font.pixelSize: 24
- 按组分配的属性, 还可以写成如下格式:
font{family: "Ubuntu"; pixelSize: 24}
- 有些属性是元素自身的附加属性, 如键盘输入, 编码方式.
信号
- 对于每个元素, 你都可以提供一个信号操作, 这个操作在属性改变时被调用
- on...Changed 属性值改变型号
onHeightChanged: console.log('height:', height) //当height改变时, 在控制台输出height的值
- Keys.onSpacePressed 按键space信号
- Keys.onEscapePressed 按键esc信号
id
- 一个元素的id应该只在当前文档中被引用.
- id的作用域
- QML提供了动态作用域的机制, 后加载的文档会覆盖之前加载文档的元素id号, 这时你可以引用已加载但还未被覆盖的元素id, 这点类似于创建全局变量, 但这样的代码阅读性较差. 建议避免使用这种机制.
- 如果你像向文档外提供元素的调用, 你可以在根元素上使用属性导出的方式来提供.
JavaScript脚本
Text {
id: label
x: 24; y: 24
width: 360
height: 360
color: '#aaaaaa'
property int spacePresses: 0
text: "Space pressed: " + spacePresses + " times" //属性绑定
onTextChanged: console.log("text chaneged to: ", text)
focus: true
Keys.onSpacePressed: {
increment()
}
Keys.onEscapePressed: {
label.text = '' //按esc时, 对text进行了赋值操作, 该操作销毁了上面的绑定了.
}
function increment() {
spacePresses = spacePresses + 1 //赋值操作
}
}
- 这里的function是一个JavaScript函数, 注意它的等号与属性的绑定不同, 这里的=只是赋值操作, 只当次调用有效. 不同于属性绑定的=是绑定于整个生命周期的.
基本元素
基本元素简介
-
分类
- 可视化元素
- 有几何形状且可以在屏幕上显示
- 非可视化元素
- 如计时器Timer, 提供了常用的功能, 通常用于操作可视化元素
- 可视化元素
-
常见的可视化元素
- Item(基础元对象)
- Rectangle(矩形框)
- Text(文本)
- Image(图像)
- MouseArea(鼠标区域)
Item
- (基础元素对象)是所有可视化元素的基础对象, 所有其它的可视化元素都继承自Item, Item本身不会有任何绘制操作, 但定义了所有可视化元素共有的属性:
Group | Properties |
---|---|
Geometry(几何属性) | x, y(坐标) 定义了元素左上角的位置, width, height(长和宽), 定义元素的显示范围, z(堆叠次序)定义元素之间的重叠顺序. |
Layouthanding | anchors(锚定), 包括左(left), 右(right), 上(top), 下(bottom), 水平与垂直居中(vertical center, horizontal center), 与margins(间距)一起定义了元素与其它元素之间的位置关系. |
Key handlikng(按键操作) | 附加属性key(按键) 和KeyNavigation(按键定位) 属性来控制按键操作, 处理输入焦点(focus)可用操作. |
Transformation | 缩放(scale)和旋转(rotate)转换, 通用的x, y, z属性列表转换(transform), 旋转基点设置(transformOrigin). |
Visual(可视化) | 不透明度(opacity), visible(是否可见), clip(裁剪)用来控制元素的边界, smooth(平滑)用来提高渲染质量. |
State definition | states(状态列表属性) 提供了元素当前所支持的状态列表, 当前属性的改变也可以使用transitions(转变) 属性列表来定义状态转变动画. |
- Item虽然不绘制, 但它常常作为其他元素的容器来使用, 类似于HTML中的div
- 后面用到时会详细介绍这些.
Rectangle Element (矩形元素)
- 对Item的一个扩展, 增加了颜色来填充它, 支持边界的定义, 如:
- border.color(边界颜色)
- border.width(边界宽度)
- radius(圆角半径)
Rectangle {
id: rect1
x: 10; y: 10
width: 75; height: 95
color: "lightsteelblue"
}
Rectangle {
id: rect2
x: 110; y: 12
width: 75; height: 95
border.color: "lightsteelblue"
border.width: 5
radius: 8
}
-
颜色的命名是来自SVGA颜色的名称(https://www.w3.org/TR/css-color-3/#svg-color), 你也可以用RGB字符串('#FF00FF'), 或者一个颜色的名字('white')来指定颜色.
-
渐变色
- 边框和填充色, 也支持渐变色设置
Rectangle { id: rect1 x: 10; y: 10 width: 175; height: 95 gradient: Gradient { GradientStop { position: 0.0; color: "lightsteelblue" } GradientStop { position: 0.5; color: "slategray" } GradientStop { position: 1.0; color: "lightsteelblue" } } border.color: "slategray" }
- 上述代码实现了一个上下偏蓝, 中间偏灰的渐变.
- position的值表示y轴上的位置, 0表示顶, 1表示底.
- GradientStop(倾斜点)的颜色标记了颜色渐变目标色
-
一个矩形框如果没有width/height将不可见, 如果有多个相互关联width/height的矩形框, 就要注意他们的组合逻辑, 防止组合逻辑的错误导致矩形框不可见.
-
不建议使用此函数创建梯形, 因为在对梯形操作时会导致一些问题. 最好使用设计好的梯形图形来完成绘制.
Text Element (文本元素)
- text属性和font属性来计算该元素的高度与宽度
- font属性组中可以设置字体和大小
- font.family 字体
- font.pixelSize 大小
- color属性改变文本颜色
Text {
text: "你好, 世界!"
font.family: "STXinwei"
color: "#333333"
font.pixelSize: 28
}
-
font.family的选择, 可以使用系统已有的字体, 例如这里选择了华文新魏("STXinwei")
-
也可以使用FontLoader来装载自己的字体
-
horizontalAlignment 设置水平对齐方式
- AlignLeft 靠左
- AlignRight 靠右
- AlignHCenter 居中
- AlignJustify 在可用空间内对齐
-
verticalAlignment 设置垂直对齐方式
- AlignTop
- AlignBottom
- AlignVCenter
- AlignBaseline 基线对齐
Text {
x: 50; y: 50
width: 150; height: 120
text: 'A very long text'
//elide: Text.ElideMiddle
wrapMode: Text.WordWrap
style: Text.Sunken
styleColor: '#FF4444'
verticalAlignment: Text.AlignTop
font.pixelSize: 48
}
-
换行与省略
- elide属性 设置对于过长的文本显示省略号
- ElideMiddle 文本超出时, 中间部分显示省略号
- ElideLeft 文本超出时, 文本开始部分显示省略号
- ElideRight 超出时, 结束部分显示省略号
- ElideNone 不显示省略号
- wrapMode属性 设置换行, 只有设置了宽度后, 该属性才生效
- elide属性 设置对于过长的文本显示省略号
-
字体绘制风格设置
- style 字体浮雕效果或者凹陷效果等
- Sunken
- Raised
- Plain
- styleColor
- style 字体浮雕效果或者凹陷效果等
-
背景问题
- text元素是无背景的, 它不会渲染任何背景修饰. 除了显示的文本, text元素背景是透明的. 为text添加背景需要你自己去处理.
-
初始宽度问题
- 文本元素的初始宽度与高度是依赖于文本字符串和设置的字体的, 一个没有设置文本和宽度的文本元素将不可见, 默认初始宽度是0
-
对齐问题
- 文本元素内部的对齐使用horizontalAlignment和verticalAlignment属性来完成, 文本元素在父对象里的对齐方式, 通常需要你操作元素的几何形状或者使用anchors(锚定)来完成
Image Element (图像元素)
Image {
x: 12; y: 12
// width: 48
// height: 118
source: "image/rocket.png"
}
Image {
x: 112; y:12
width: 48
height: 118/2
source: "image/rocket.png"
fillMode: Image.PreserveAspectCrop
clip: true
}
- Image元素能够显示不同格式的图像(png, jpg, gif, bmp等)
- source属性 提供图像文件的链接信息
- source后面的URL可以是本地路径, 也可以是网络路径的图.
- fillMode(填充模式) 属性能够控制元素对象的大小调整行为
- Stretch 图像缩放以适合
- PreserveAspectFit 图像均匀缩放以适合而不进行裁剪
- PreserveAspectCrop 图像均匀缩放以填充, 必要时进行裁剪
- Tile 图像水平和垂直复制
- TileVertical 图像水平拉伸并垂直平铺
- TileHorizontal 垂直拉伸并水平平铺
- Pad 显示图片且不做任何转换
- clip属性 裁剪
- 默认情况下裁剪是禁用的(clip: false), 需要打开裁剪(clip: true)来约束绘制行为, 该属性对任何可视化元素都是有效的.
- 建议
- 使用QQmlImageProvider你可以通过C++代码来创建自己的图像提供器, 这允许你动态创建图像, 并使用线程加载.
MouseArea Element(鼠标区域元素)
Rectangle {
id: rect1
x: 10; y: 10
width: 75; height: 95
color: "lightsteelblue"
MouseArea {
id: area
width: parent.width
height: parent.height
onClicked: rect2.visible = !rect2.visible
}
}
Rectangle {
id: rect2
x: 110; y: 10
width: 75; height: 95
visible: false
border.color: "lightsteelblue"
border.width: 4
radius: 8
}
-
这是一个矩形的非可视化元素, 你可以通过它来捕捉鼠标事件, 当用户与可视化窗口交互时, 该元素被用来与可视化元素对象一起完成命令.
-
特性: 输入处理和可视化显示分开, 这样你的交互区域可以很灵活控制.
Components (组件)
-
一个组件是一个可以复用的元素, QML提供几种不同的方法来创建组件.
-
文件组件
- 一个文件就是一个基础组件. 即: 一个以文件为基础的组件在文件中创建了一个QML元素, 并且将文件以元素类型来命名(例如Button.qml).
-
组件中只有根目录的属性, 对外是开放的, 如果要访问子元素的属性, 需要在根目录给它取一个别名
-
示例组件
//Button.xml
import QtQuick 2.0
Item {
id: root
property alias text: label.text
signal clicked
Rectangle {
id: button
x: 10; y: 10
width: 110; height: 25
color: "lightsteelblue"
border.color: "slategrey"
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
status.text = "Button clicked!"
root.clicked()
}
}
}
Text {
id: status
x: 10; y:75
width: 110; height: 25
text: "Waitting ..."
horizontalAlignment: Text.AlignHCenter
}
}
- 调用示例组件
- 调用时修改了text的值, 运行结果按钮上不是显示Start而是显示Click, 同时组件的onClicked信号会传给调用对象, 触发对应的函数, 改变了其status元素的文本为"已点击"
//mian.xml
Text {
id: status
x: 120; y:75
width: 110; height: 25
text: "Waitting ..."
horizontalAlignment: Text.AlignHCenter
}
Button {
id: button
x:12; y:12
text: "Click!"
onClicked: {
status.text = "已点击"
}
}
- 组件的root常常使用item元素, 这样组件的子元素能够更好的封装.
Simple Transformations (元素的简单转换)
- 转换操作可以改变对象的几何状态, 通常有平移, 旋转, 缩放等.
- 以下示例, 用来演示对一个小火箭的三种操作
//给小火箭做一个基础组件
//ClickableImage.qml
import QtQuick 2.0
Image {
id: root
signal clicked
MouseArea {
anchors.fill: parent
onClicked: root.clicked()
}
}
//调用小火箭组件, 并设置一些互动
Image {
id: bg
source: "image/blue.png"
}
MouseArea {
id: backgroundClicker
anchors.fill: parent
onClicked: { //点击背景时, 将三张图片参数还原
rocket1.x = 20
rocket2.rotation = 0
rocket3.rotation = 0
rocket3.scale = 1.0
}
}
ClickableImage {
id: rocket1
x: 20; y: 100
source: "image/rocket.png"
onClicked: {
x+=5 //向右平移
}
}
ClickableImage {
id: rocket2
x: 140; y: 100
source: "image/rocket.png"
smooth: true //设置抗锯齿, 提高显示质量
onClicked: {
rotation += 5 //旋转5度
}
}
ClickableImage {
id: rocket3
x: 240; y: 100
source: "image/rocket.png"
smooth: true
onClicked: {
rotation += 5 //旋转5度
scale -= 0.05 //缩小0.05
}
}
- 堆叠顺序(z-order)
- 注意堆叠顺序, 是后面的元素在前面的元素上方的. 当他们重叠时, 后面的元素会遮挡前面的元素. 如果需要调整堆叠次序时, 使用元素对象z-property来控制.
Positioning Element(定位元素)
- 有一些QML元素被用于放置元素对象, 它们被称为定位器, QtQuick模块提供了Row, Column, Grid, Flow用来作为定位器. 以下用颜色组件对象来进行示例.
- 先写几个颜色组件(Red, Blue, Green, Lighter, Darker各写一个, 这里仅以Red示例)
//RedSquare.qml
import QtQuick 2.0
Rectangle {
width: 48
height: 48
color: "#ee0000"
border.color: Qt.lighter(color)
}
- Column (行布局)
//Column
DarkerSquare {
id: root
width: 150
height: 300
anchors.centerIn: parent
Column {
id: column
anchors.centerIn: parent
spacing: 10 //行距
RedSquare {
}
GreenSquare {
width: 100
}
BlueSquare {
}
}
}
- Row (列布局)
//Row
DarkerSquare {
id: root
width: 300
height: 240
anchors.centerIn: parent
Row {
id: row
anchors.centerIn: parent
spacing: 15 //列宽
RedSquare {
}
GreenSquare {
}
BlueSquare {
}
LighterSquare {
}
}
}
- Grid (网格布局)
//Grid
DarkerSquare {
id: root
width: 300
height: 240
anchors.centerIn: parent
Grid {
id: grid
rows: 2
columns: 2
anchors.centerIn: parent
spacing: 15
RedSquare {
}
GreenSquare {
}
BlueSquare {
}
LighterSquare {
}
}
}
- Flow (流式布局)
- Flow类似Grid布局, 但更智能, 可以根据对象的长宽做智能化调整.
//Flow
DarkerSquare {
id: root
width: 300
height: 240
anchors.centerIn: parent
Flow {
id: flow
//anchors.centerIn: parent
anchors.fill: parent
anchors.margins: 20
spacing: 15
RedSquare {
width: 20
}
GreenSquare {
height: 60
}
BlueSquare {
width: 75
}
LighterSquare {
height: 90
}
}
}
- Repeater (重复元素)
- Repeater通常与定位器一起使用. 它的工作方式就像for循环和迭代器一样
知识点
- int型与string用加号连接时, 会自动转换为string
- 焦点控件变色
// focus is neeed to receive key events
focus: true
// change color based on focus value
color: focus?"red":"black"