目录
【前言】
QML是Qt的一大特色,拥有强大的UI制作能力。但是想要学好QML,还需要一些细节和技巧的掌握。
本篇文章万字长文,良心制作,提供完整的QML知识体系,让你成为Qt的UI魔法师!
【制作不易,如果觉得有用可以点赞收藏再走】
【有额外的问题,或者文章有遗漏之处也可私信我,感谢】
【本文我已做成电子版,大家可以在我主页获取下载】
1. 简介
-
什么是 QML
QML,全称为 Qt Meta-Object Language,是一种声明式语言,用于在 Qt 框架中创建用户界面(UI)。它采用了 JavaScript 的语法,并通过 Qt 的 QML 引擎来解释和执行 QML 代码。通过 QML,开发者可以快速、简单地创建现代化的用户界面,而无需太多的代码。
-
QML 的特点
QML 具有以下特点:
- 声明式语言:QML 使用声明式语言,使得开发者可以更加直观地构建 UI,无需过多关注底层实现细节。
- 基于 JavaScript:QML 语法基于 JavaScript,因此对于有一定 JavaScript 基础的开发者来说,学习 QML 会相对容易。
- 可读性高:QML 语法结构简单清晰,易于理解和维护,减少代码量和开发时间。
- 可定制性强:QML 中可以通过修改属性来快速定制 UI,无需编写额外代码。
- 与 C++ 无缝结合:QML 可以与 C++ 代码进行无缝结合,提供了更多的开发灵活性和可扩展性。
QML 的用途
- 移动应用程序的 UI 开发,如手机应用等。
- 桌面应用程序的 UI 开发,如计算器等。
- 嵌入式系统的 UI 开发,如车载导航、工业自动化等。
同时,QML 也可用于开发图形化控件、动画和过渡效果等。总之,QML 是一个功能强大的 UI 开发工具,适用于各种类型的应用程序和设备。
2. QML 基础语法
-
QML 的结构
QML 文件通常由三部分组成:
- 导入语句:用于导入 Qt 模块和自定义 QML 组件。
- 全局对象定义:用于定义全局的 QML 对象,例如常量、枚举、函数等。
- 根元素:所有其他元素都是根元素的子元素。
下面是一个简单的 QML 文件示例:
import QtQuick 2.0
Rectangle {
width: 100
height: 100
color: "red"
}
-
QML 的元素
QML 中的元素类似于 HTML 中的标签,用于构建 UI。每个元素都可以拥有自己的属性、子元素和信号等。
QML 元素的语法格式如下:
元素名 {
属性名1: 属性值1
属性名2: 属性值2
...
子元素1 {
...
}
子元素2 {
...
}
...
}
例如,下面是一个简单的 Rectangle 元素示例:
Rectangle {
width: 100
height: 100
color: "red"
}
-
QML 的属性
QML 中的元素可以拥有多个属性,用于控制元素的行为和外观。属性可以设置初始值、绑定、动画等,具有一定的动态性。属性可以使用 JavaScript 表达式进行计算,也可以绑定到其他属性或者信号上。
下面是一个 Text 元素的示例:
Text {
text: "Hello World"
font.bold: true
font.pixelSize: 24
color: "red"
}
-
QML 的信号和槽
在 QML 中,可以通过信号和槽来实现元素之间的通信。信号是元素发出的消息,槽是元素接收消息的处理函数。可以使用 onXXX 属性来定义信号,例如 onTextChanged 表示文本改变的信号。
可以使用 Connections 元素来连接信号和槽,例如:
Rectangle {
width: 100
height: 100
color: "red"
signal clicked()
MouseArea {
anchors.fill: parent
onClicked: parent.clicked()
}
}
Rectangle {
width: 100
height: 100
color: "blue"
Connections {
target: redRect
onClicked: {
console.log("Red rectangle clicked!")
}
}
}
3. QML 常用元素
-
Text 元素
Text 元素用于在 QML 中显示文本。可以使用 text 属性来设置 Text 中要显示的文本内容,也可以使用 font 属性来设置 Text 的字体、字号和字重。
Text {
text: "Hello, World!"
font.family: "Helvetica"
font.pixelSize: 20
font.bold: true
}
-
Rectangle 元素
Rectangle 元素用于在 QML 中创建矩形。可以使用 color 属性来设置 Rectangle 的颜色,也可以使用 width 和 height 属性来设置 Rectangle 的大小。
Rectangle {
color: "red"
width: 100
height: 100
}
-
Image 元素
Image 元素用于在 QML 中显示图片。可以使用 source 属性来设置要显示的图片路径,也可以使用 fillMode 属性来控制图片在 Image 区域内的填充方式。
Image {
source: "image.png"
width: 200
height: 200
}
-
ListView 元素
ListView 元素用于在 QML 中创建可滚动的列表。可以使用 model 属性来设置 ListView 的数据模型,也可以使用 delegate 属性来设置每个列表项的显示方式。
ListView {
model: ["Apple", "Banana", "Orange"]
delegate: Text {
text: modelData
font.pixelSize: 20
}
}
-
Item 元素
Item 元素是所有 QML 元素的基类,用于定位和组合其他元素。可以使用 anchors 来设置 Item 元素的位置和大小,还可以使用 transform 来设置 Item 元素的旋转、缩放等变换。
Item {
width: 200
height: 200
Rectangle {
anchors.centerIn: parent
width: 100
height: 100
color: "red"
}
}
-
Button 元素
Button {
text: "Click Me"
onClicked: console.log("Button clicked!")
}
-
TextInput 元素
TextInput 元素用于创建一个文本输入框,用户可以在其中输入文本。可以使用 text 属性来设置或获取文本框中的文本,也可以使用 onTextChanged 信号来监听文本变化。
TextInput {
text: "Enter text here"
onTextChanged: console.log("Text changed to:", text)
}
-
CheckBox 元素
CheckBox 元素用于创建一个复选框,用户可以选择或取消选择其中的选项。可以使用 checked 属性来设置或获取复选框的选中状态,也可以使用 onCheckedChanged 信号来监听选中状态变化。
CheckBox {
text: "Check me"
onCheckedChanged: console.log("Checked:", checked)
}
-
Slider 元素
Slider 元素用于创建一个滑动条,用户可以通过拖动滑块来调整数值。可以使用 value 属性来设置或获取滑动条的当前值,也可以使用 onValueChanged 信号来监听值变化。
Slider {
value: 50
onValueChanged: console.log("Value changed to:", value)
}
-
Grid元素
Grid 元素用于创建网格布局,可以使用 rows 和 columns 属性来指定网格的行数和列数。可以将其他元素添加到网格中,使用 row 和 column 属性来指定它们所在的行和列。
Grid {
rows: 2
columns: 2
Rectangle {
row: 0
column: 0
width: 100
height: 100
color: "red"
}
Rectangle {
row: 0
column: 1
width: 100
height: 100
color: "green"
}
Rectangle {
row: 1
column: 0
width: 100
height: 100
color: "blue"
}
Rectangle {
row: 1
column: 1
width: 100
height: 100
color: "yellow"
}
}
-
WebView
WebView 元素用于在 QML 中嵌入一个 Web 页面。可以使用 url 属性来指定要加载的 Web 页面的 URL。
WebView {
url: "http://www.example.com"
width: 800
height: 600
}
-
Canvas元素
Canvas 元素用于绘制 2D 图形。可以使用 CanvasRenderingContext2D API 在 Canvas 上绘制图形。
Canvas {
id: canvas
width: 400
height: 400
onPaint: {
var ctx = canvas.getContext("2d")
ctx.fillStyle = "red"
ctx.fillRect(0, 0, canvas.width, canvas.height)
}
}
(常用元素整理未完待续……)
4. QML 组件
-
QML 组件的概念
当我们在开发QML应用程序时,我们会经常使用组件,以便在程序中复用代码并提高开发效率。组件可以看作是一个独立的QML元素,它由其他QML元素和逻辑组成,可以在程序中被多次使用。
-
如何创建和使用组件
第一步:我们可以在一个单独的 QML 文件中定义一个组件的原型,(方便后续其他文件去使用这个按钮组件)例如 MyButton.qml:
import QtQuick 2.0
Rectangle {
width: 100
height: 50
color: "green"
Text {
text: "Click Me"
font.pixelSize: 20
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: console.log("Button clicked")
}
}
//代码定义了一个简单的按钮组件,包括一个绿色的矩形、一个文本标签和一个鼠标区域。当用户单击鼠标区域时,控制台将输出一条消息。
第二步:要在其他 QML 文件中使用这个组件,我们可以使用 MyButton.qml 文件的路径,然后将其作为一个普通元素添加到其他 QML 文件中
import QtQuick 2.0
Rectangle {
width: 200
height: 100
color: "lightblue"
MyButton {
anchors.centerIn: parent
}
}
//代码创建了一个蓝色的矩形,然后将 MyButton 组件添加到矩形的中心位置
5. QML 中的动画和过渡
-
动画的概念
动画是指将元素从一个状态平滑地过渡到另一个状态的过程。在QML中,动画通常是通过改变元素属性值来实现的。动画可以为用户提供更加流畅、直观的界面体验。
-
QML 中的动画和过渡
在QML中,动画可以通过属性动画和过渡动画实现。属性动画指的是改变元素的一个或多个属性值来产生动画效果,而过渡动画指的是将元素从一种状态过渡到另一种状态来产生动画效果。常用的过渡动画有添加和删除元素的过渡效果、列表项的选中效果等。
-
动画属性和动画类型
QML中,动画属性指的是可以被动画化的元素属性,例如矩形元素的宽度、高度、颜色等属性都可以被动画化。动画类型指的是属性动画的类型,例如NumberAnimation可以用于对数字类型属性进行动画,而PropertyAnimation则可以用于对任意类型属性进行动画。QML还提供了许多其他类型的动画,如RotationAnimation、ScaleAnimation、OpacityAnimation等。
-
实例分析一
ListView {
id: listView
model: myModel
delegate: Rectangle {
id: rect
width: 100
height: 50
color: "red"
Text {
text: name
anchors.centerIn: parent
}
states: State {
name: "selected"
when: listView.isCurrentItem
PropertyChanges {
target: rect
color: "blue"
}
}
transitions: Transition {
from: ""
to: "selected"
PropertyAnimation {
target: rect
property: "color"
duration: 200
}
}
}
}
//代码演示了如何使用过渡动画来实现添加和删除元素的效果
-
实例分析二
Rectangle {
id: rect
width: 100
height: 100
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
widthAnimation.running = true
}
}
NumberAnimation {
id: widthAnimation
target: rect
property: "width"
to: 200
duration: 1000
}
}
//代码演示了如何使用属性动画来改变矩形的宽度属性
6. QML 中的模型和视图
-
模型和视图的概念
在 QML 中,模型和视图是用于展示和管理数据的核心概念。模型用于存储数据,而视图则负责将数据展示给用户。
-
如何使用模型和视图
使用模型和视图的过程一般包括以下几个步骤:
- 定义模型:使用 QML 中提供的一些模型类型(如 ListModel、XmlListModel、SqlQueryModel 等)或自定义的模型来存储数据。
- 绑定模型:使用绑定语法(例如 property 或 Binding 元素)将模型绑定到视图中。
- 定义视图:使用 QML 中提供的视图组件(如 ListView、GridView、PathView 等)来展示数据。
- 设置视图属性:设置视图的各种属性,例如 layout、delegate 等。
- 配置模型:对模型进行必要的配置,例如添加、删除、修改等操作。
- 刷新视图:模型的数据发生变化后,需要使用视图中的 refresh() 方法或者通过信号和槽机制来通知视图更新数据。
-
常用的模型和视图组件
在 QML 中,有许多常用的模型和视图组件,例如:
- ListModel:用于存储列表数据。
- XmlListModel:用于从 XML 文件中读取数据并将其存储为模型。
- SqlQueryModel:用于从 SQLite 数据库中读取数据并将其存储为模型。
- TableView:用于展示表格数据。
- ListView:用于展示列表数据。
- GridView:用于展示网格数据。
- PathView:用于在路径上展示数据。
- Repeater:用于重复展示同一组件。
-
常用的模型简单案例
-
ListView 和 ListModel
import QtQuick 2.0
ListView {
width: 200
height: 400
model: ListModel {
ListElement {
name: "Alice"
}
ListElement {
name: "Bob"
}
ListElement {
name: "Charlie"
}
}
delegate: Rectangle {
height: 40
width: parent.width
color: index % 2 === 0 ? "lightgray" : "white"
Text {
text: name
font.pixelSize: 20
}
}
}
//定义了一个 ListModel,用于存储数据。然后我们将这个模型绑定到了一个 ListView 组件上,将 ListModel 中的数据展示在了 ListView 中。在 ListView 中,我们使用了 delegate 属性来定义每个元素的展示方式,这里我们使用了一个 Rectangle 组件和一个 Text 组件来展示每个元素的数据。
-
ListView 和 ListModel
XmlListModel {
id: xmlModel
source: "data.xml"
query: "/root/item"
XmlRole { name: "title"; query: "title/string()" }
XmlRole { name: "author"; query: "author/string()" }
XmlRole { name: "date"; query: "date/string()" }
}
//使用XmlListModel从名为"data.xml"的XML文件中读取数据,查询"/root/item"元素并将其存储为模型。XmlRole用于将XML数据中的不同字段映射到模型属性中。
-
SqlQueryModel
SqlQueryModel {
id: sqlModel
query: "SELECT * FROM mytable"
// 设置角色名称
roleNames: { "id": "id", "name": "name", "age": "age" }
// 连接数据库
Connections {
name: "myDb"
// 设置数据库路径
sqlite.fileName: "mydatabase.db"
}
}
//使用SqlQueryModel从名为"mytable"的SQLite数据库中读取数据,并将其存储为模型。通过roleNames可以指定模型的各个属性名称,而Connections则用于连接SQLite数据库。
-
TableView
TableView {
// 模型绑定
model: myModel
// 设置表头
headerVisible: true
// 设置每一列的宽度
columnWidthProvider: function (column) { return 100 }
// 设置表格项的样式
delegate: Rectangle {
width: 100
height: 50
color: "lightgray"
Text {
text: model.display
anchors.centerIn: parent
}
}
}
//使用TableView展示名为myModel的模型中的数据,设置表头可见,为每一列设置宽度,并且设置表格项的样式为一个灰色的矩形和居中的文本。
7. QML 中的绘图
-
绘图的概念
在 QML 中,绘图是指使用代码来创建和绘制图形。QML 中提供了许多元素和组件,可以用来绘制各种图形,例如线条、矩形、圆形等。
-
Canvas 元素
Canvas 元素是 QML 中用来进行绘图的元素之一。通过 Canvas 元素,我们可以在一个矩形区域内进行自由绘制。
Canvas {
id: canvas
width: 200
height: 200
onPaint: {
var ctx = getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(width, height);
ctx.stroke();
}
}
//通过该元素绘制一条线
-
Path 元素
Path 元素是 QML 中用来创建和绘制矢量图形的元素之一。通过 Path 元素,我们可以创建各种形状的路径,并对其进行填充、描边等操作
Path {
fillColor: "red"
strokeColor: "black"
strokeWidth: 2
startX: 0
startY: 0
PathLine {
x: 100
y: 0
}
PathLine {
x: 100
y: 100
}
PathLine {
x: 0
y: 100
}
PathLine {
x: 0
y: 0
}
}
//一个简单的 Path 元素的例子,通过该元素绘制一个带填充颜色和描边的矩形
-
Gradient 元素
Gradient 元素是 QML 中用来创建渐变色的元素之一。通过 Gradient 元素,我们可以创建各种类型的渐变色,并将其应用到绘制的图形中。
Gradient {
id: gradient
GradientStop {
position: 0.0
color: "red"
}
GradientStop {
position: 1.0
color: "blue"
}
}
Canvas {
id: canvas
width: 200
height: 200
onPaint: {
var ctx = getContext("2d");
var grd = ctx.createLinearGradient(0, 0, width, height);
grd.addColorStop(0, gradient.gradientStops[0].color);
grd.addColorStop(1, gradient.gradientStops[1].color);
ctx.strokeStyle = grd;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(width, height);
ctx.stroke();
}
}
//通过该元素创建一个从红色到蓝色的线性渐变
8. QML 中的交互
-
鼠标和键盘事件
鼠标和键盘事件是 QML 中实现交互的重要途径之一,通过这些事件可以实现用户与应用程序的交互。在 QML 中,鼠标和键盘事件主要包括以下几种:
MouseArea:
用于处理鼠标事件,例如 mousePressed、mouseReleased、mouseMoved 等。
MouseArea {
id: mouseArea
anchors.fill: parent
onReleased: {
console.log("Mouse released at", mouse.x, mouse.y)
}
}
//当用户按下鼠标时,MouseArea 组件会发出 mousePressed 信号,可以使用该信号来执行相应的操作。
Keys:
用于处理键盘事件,例如 onKeyDown、onKeyUp 等。
Rectangle {
width: 200
height: 200
Keys.onReturnPressed: {
console.log("Enter key pressed")
}
}
//当用户按下键盘时,可以使用 Keys 组件来处理键盘事件,检测用户是否按下了 Enter 键
TextInput:
用于处理文本输入事件,例如 onTextChanged 等。
TextInput {
width: 200
height: 40
onTextChanged: {
console.log("New text input: " + text)
}
}
//使用 TextInput 组件来处理文本输入事件,代码演示了如何检测用户是否输入了新的文本
Touch 事件
Touch 事件主要用于处理触摸屏幕的操作,例如 tap、doubleTap、longPress 等。在 QML 中,可以使用 MouseArea 和 TouchArea 组件来处理触摸事件。
Rectangle {
width: 200
height: 200
TouchArea {
anchors.fill: parent
onTouchReleased: {
console.log("Rectangle clicked")
}
}
}
//使用 TouchArea 或 MouseArea 组件来处理触摸事件。代码演示了检测用户是否单击了某个矩形
Gesture 事件
Gesture 事件主要用于处理多点触控的操作,例如缩放、旋转等。在 QML 中,可以使用 MultiPointTouchArea 组件来处理手势事件。
Rectangle {
width: 200
height: 200
MultiPointTouchArea {
anchors.fill: parent
onPinchStarted: {
console.log("Pinch gesture started")
}
onPinchUpdated: {
console.log("Pinch gesture updated")
}
onPinchFinished: {
console.log("Pinch gesture finished")
}
}
}
//当用户进行手势操作时,可以使用 MultiPointTouchArea 组件来处理手势事件。代码演示了如何检测用户是否进行了缩放操作
9. QML 中的网络编程
-
网络编程的概念
网络编程是指使用计算机网络进行数据传输和交换的过程,通过网络编程可以实现客户端和服务器之间的通信。在 QML 中,可以使用 XMLHttpRequest 和 WebSocket 对象实现网络编程。
-
QML 中的 XMLHttpRequest 对象
XMLHttpRequest 对象是浏览器提供的一种 API,用于在不刷新页面的情况下向服务器发送请求并获取响应数据。在 QML 中,也可以使用 XMLHttpRequest 对象来实现网络请求。
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.XmlListModel 2.0
Item {
XmlListModel {
id: xmlModel
source: "https://api.example.com/data.xml"
query: "/data/item"
XmlRole { name: "name"; query: "name/string()" }
XmlRole { name: "value"; query: "value/string()" }
}
ListView {
anchors.fill: parent
model: xmlModel
delegate: Text {
text: name + ": " + value
}
}
}
//XmlListModel 使用 XMLHttpRequest 对象从 https://api.example.com/data.xml 获取数据,并将其存储为模型。
-
QML 中的 WebSocket 对象
WebSocket 是一种基于 TCP 协议的双向通信协议,它可以在浏览器和服务器之间建立实时、双向的通信连接。在 QML 中,可以使用 WebSocket 对象来实现 WebSocket 协议的通信。
import QtQuick 2.0
import QtWebSockets 1.1
WebSocket {
id: socket
url: "wss://echo.websocket.org"
onMessageReceived: console.log("Received message:", message)
}
TextInput {
id: input
width: parent.width
onAccepted: {
socket.sendTextMessage(input.text)
input.text = ""
}
}
WebSocket 对象通过 url 属性指定要连接的服务器地址,并通过 sendTextMessage() 方法发送消息。当接收到消息时,会触发 onMessageReceived 信号,并将消息作为参数传递。在此例中,收到的消息将在控制台中输出。同时,使用 TextInput 组件接收用户输入,并通过 sendTextMessage() 方法将其发送给服务器。
10. QML 中的多媒体
-
多媒体的概念
多媒体是指音频、视频、图像等多种类型的媒体。在 QML 中,可以使用 MediaPlayer 组件和 Camera 组件来实现多媒体播放和拍摄功能。
-
QML 中的 MediaPlayer 组件
MediaPlayer 组件用于播放音频和视频,它支持多种常见格式的音视频文件,如 MP3、WAV、OGG、H.264、MPEG-4 等。MediaPlayer 组件包括以下属性和方法:
- source:指定要播放的媒体文件路径。
- autoPlay:设置是否自动播放媒体。
- volume:设置媒体的音量大小。
- play():播放媒体。
- pause():暂停播放媒体。
- stop():停止播放媒体。
import QtMultimedia 5.0
Rectangle {
width: 800
height: 600
MediaPlayer {
id: mediaPlayer
source: "myMedia.mp4"
autoPlay: true
volume: 1.0
}
VideoOutput {
id: videoOutput
anchors.fill: parent
source: mediaPlayer
}
}
首先我们导入了 QtMultimedia 模块。然后我们创建一个 MediaPlayer 组件,指定要播放的媒体文件路径为 "myMedia.mp4"。我们还设置了自动播放并将音量设置为 1.0。接下来,我们创建了一个 VideoOutput 组件,并将其 source 属性设置为 MediaPlayer 组件,以便将视频内容显示在屏幕上。
当我们运行这个示例时,将自动开始播放名为 "myMedia.mp4" 的视频文件。可以通过调整 MediaPlayer 组件的属性来实现各种不同的功能,例如暂停、停止、重新开始等。
-
QML 中的 Camera 组件
Camera 组件用于拍摄照片和录制视频,它可以连接系统中的摄像头设备,并通过该设备进行拍照和录像。Camera 组件包括以下属性和方法:
- captureMode:设置拍照还是录像模式。
- imageCapture:用于拍照。
- videoRecorder:用于录像。
- start():开始拍照或录像。
- stop():停止拍照或录像。
import QtMultimedia 5.0
Camera {
id: camera
captureMode: Camera.CaptureStillImage
imageCapture {
onImageCaptured: {
// 处理拍摄的照片
}
}
}
Camera 组件设置了拍照模式,并创建了一个 imageCapture 对象来处理拍摄的照片。在拍照时,可以调用 start() 方法开始拍摄,拍摄完成后会触发 onImageCaptured 信号,通过该信号可以获取到拍摄的照片并进行处理。