最近更新日期:2024/12/18
目录
一、Qt Quick简介
1.3 新建Qt Quick Application工程
1.3.1 导入Qt资源文件
1.3.2 设置应用图标(Windows系统)
二、QML
2.2 import
2.2.1 import模块
2.2.2 import代码文件
2.3 属性:property
2.4 方法
2.5 自定义信号
2.6 枚举
2.7 基本类型
2.8 其它类型
2.8.1 对象类型
2.8.2 JavaScript类型
2.9 JavaScript
2.10 自定义QML组件
2.11 作用域
2.12 代码风格
三、Qt Quick基础
3.1.1 项目Item
3.1.2 矩形Rectangle
3.1.3 文本text
3.1.4 标签Label
3.1.5 文本输入框 TextInput
3.1.6 文本编辑框TextEdit
3.2.1 行列布局 Row Column
3.2.2 栅格布局 Grid
3.2.3 流布局 Flow
3.2.4 布局过渡 Transition
3.2.5 重复器 Repeater
3.2.6 锚布局 Anchors
3.2.7 布局管理器 Layouts
3.3.1 触摸区域 MouseArea
3.3.2 鼠标事件 MouseEvent
3.3.3 拖拽事件 DragEvent
3.3.4 键盘事件 KeyEvent
3.3.5 定时器 Timer
3.4 自定义滑动区域 SwipeArea
3.5 自定义按钮 QuickButton
3.6 Loader
3.7 综合示例 HarmonyUI
四、Qt Quick控件
五、Qt Quick对话框
六、图片
七、动画
八、图形效果
九、粒子效果
十、Qt Quick 3D
十一、模型与视图
十二、图表
十三、数据可视化
十四、多媒体
十五、QML与C++交互
十六、新能源汽车中控屏
写在前面:
本篇文章虽然只是作为我的学习笔记,但也作为我日后复习之用,所以会认真并详细记录,但会分重点。
这节主要讲2个知识点,1个是【导入Qt资源文件】,1个是【设置应用图标】。
1.3.1 导入Qt资源文件
首先在工程目录中新建一个名为 images 的文件夹,把程序需要用到的图片放进去,png、ico格式的都一起。(ico格式的是用来作为应用图标的)
这里不用分格式、用途,全部一股脑放这个文件夹里就行。
图片放好之后,我们回到Qt Creator中,在工程目录中新建一个资源文件(Qt Resource File),文件名随意,我的就叫做images和图片文件夹名称一致。
添加好之后,你的工程目录中会多出一个后缀名为 .qrc 的文件,右键添加现有文件,把文件夹里的图片全部选中点击确定即可。然后你逐一点开这个qrc文件,就可以在这个文件里看到你上传的所有图片了。
到这里还没完,最后一步是点开工程目录中的 CMakeLists.txt 文件,然后在里面加一句代码(否则我们无法使用资源文件 ):
这样就导入完成了,虽然有一丢丢麻烦,但是你总不会一直导的,对吧!?
1.3.2 设置应用图标(Windows系统)
应用图标的格式要求是 .ico 格式,png、jpg其他的可不行哦!上面我们已经导入了1张 ico 格式的图片,接下来我们看一下怎么设置成应用图标吧!
(这里推荐一个图片转ico格式的网站,免费且广告很少:锤子在线工具。)
首先我们在工程目录中新建一个文本文档,把文件名改为 ico.rc,然后双击打开这个文件,还是记事本打开哈,在里面写入下面这句代码:
注意,双引号里面的是你自己的路径,写好之后保存该文件。
最后一步, 点开工程目录中的 CMakeLists.txt 文件,在 qt_add_executable 里面加上:
我们运行一下看看,果然,报错了!
原来我们导入的资源文件是带中文的,真的是太太粗心了!但是为什么直接在 Image 模块中用带中文的路径能正常显示,而应用图标带中文就不行了呢?
这个我也不太清楚,建议大家还是都用英文和下划线吧!
把文件名改成英文,然后重新弄了一遍之后,运行成功了!包括任务栏图标也是这个可可爱爱的青蛙了~
2.2.1 import模块
import是QML中的一个导入关键字,一般用于导入下面代码需要用到的模块。
这里讲一个特殊情况,比如在同一个代码文件中,我们需要导入多个名称相同或者非常相似的模块,容易搞混弄错,那么我们可以使用 as 关键字来给其中一些模块单独命名。
那相应的,我们使用这个模块的方式就要改变了,否则会报错。
2.2.2 import代码文件
代码文件比如说我们在其他qml文件中写了一些代码,想要在另外一个代码文件中使用,那么也需要import关键字去导入。
这种一般都是借用别人的代码,如果是我们自己写的话,大概率会直接在Qt Creator中新建相应的文件。
假设我们现在工程目录中粘贴了一个 MyButton的文件,现在想要在 Main.qml 中使用,那么就在顶部写上:
如果是文件中的代码文件该怎么导入呢?也很简单!直接把这个文件夹导入就行了,这样里面的所有文件都能使用了。
格式就是 https://blog.csdn.net/weixin_53989417/article/details/ + 文件夹名称 。另外,这个也可以用 as关键字来简写,像下面这样:
import用好了,做大一点的项目也会方便、清晰很多哦!
只读:修饰符 readonly
只读属性必须给初始值,之后不允许修改。
附加属性
附加属性和附加信号处理器是一种允许对象使用额外的属性或信号处理器的机制,允许对象访问一些与个别对象相关的属性或者信号。
有点抽象对吧?没关系,看下面例子就行。
这里的 onCompleted 就是 Component 的附加属性。我们不需要了解过深,只需要会用,知道哪些属性有附加属性可供使用就行了。
方法就是函数,可以执行某些处理或者触发其他事件。可以将方法关联到信号上,这样在发射该信号时就会自动调用该方法。
在qml中的函数其实不用写的太复杂,如果你真的有很复杂的函数需要实现,可以在C++中。
信号和信号接收器是一对,我们不仅可以在同一文件中去实现他们,甚至可以把信号写在另一个文件,在当前文件中用信号接收器去接收。
属性值改变信号
QML类型提供内建属性值改变信号,属性值改变就会自动发出信号。
Connections
用于连接外部对象的信号。可以接收指定目标的任意信号。
connect() 函数
将信号与动态创建的对象关联(也可以和函数关联)。
枚举(Enumeration)提供了一组固定的命名选项。
自定义的qml文件必须首字母大写。
枚举名字必须首字母大写。
QML支持常见的数据类型,包括:整型、浮点型、字符串和布尔类型。在QML中,将这种仅指向简单数据的类型称为基本类型。
随便举几个例子:
2.8.1 对象类型
QML对象类型用于对象实例化,与基本类型的区别是它可以声明一个对象。例如:Rectangle、Button等对象类型。
2.8.2 JavaScript类型
Qt Quick 支持JavaScript对象和数组。可以创建任何标准的JavaScript类型,例如:Date、Array等。
1. JavaScript在QML中的定位
1)辅助实现复杂的界面逻辑,扩展QML功能
2)主流是QML搭配C++实现完整的程序
3)执行效率远低于C++
4)过度使用JavaScript代码会导致复杂度增加、可维护性降低
2. 属性绑定
1)属性绑定可以是表达式、对象属性、JavaScript函数
2)语法 “属性 :值”
3)属性绑定一旦被重新赋值,就会解除绑定关系
4)如果需要重新绑定,使用 Qt.binding() 函数
3. 调用外部JavaScript文件
1. 定义对象类型
1)必须以大写字母开头,不能包含除字母、数字、下划线以外的字符。这个后缀名为 .qml 的文件会被引擎识别为1个QML类型的定义
2)同一目录的其它QML文件会被自动设置为可用
2. 自定义类型的可访问特性
property propertyType propertyName : value
将自定义类型的属性暴露出去,在其他文件就可以修改。
1. 作用
1)表达式可以访问哪些变量
2)重名时的优先级
2. 绑定的作用域对象
3. 组件作用域
1)QML文件每个组件都定义了一个逻辑作用域
2)每个文件都至少有一个根组件
4. 作用域使用技巧
id.property(通过另一个作用域的id来调用)
Qt帮助文档查找:QML Coding Conventions
1. QML对象声明
2. 属性组
3. 列表
4. 信号处理器
5. JavaScript代码
6. 复杂条件判断
涉及到较为复杂的条件判断,可以把属性绑定到函数,在函数中去具体实现,提高代码的可读性。
如果只有1、2层,可以用三目运算符,更多的话还是用函数吧!
Item 是所有可视化元素的基类,所有其它的可视化元素都继承自 Item。它自身不会有任何绘制操作,但是定义了所有可视化元素共有的属性。
Qt帮助文档搜索 Item 获取更多详细信息。
说明
1)通常被用来作为其它元素的容器使用
2)属性 opacity 指定透明度,取值范围:0.0 ~ 1.0
3)堆叠次序 z
4)可见性 visible,虽然 Item 本身不可见,但可以用来分组其它可视对象
Text 可以显示纯文本和富文本。实际开发中常用 Label 替代 Text。
Qt帮助文档搜索 Text 获取更多详细信息。
Text 常用属性
1)颜色 color
2)字体 font
3)裁剪 clip
4)省略 elide
5)对齐 alignment
描述
Label 继承自 Text。如果没有明确指定背景大小,它会遵循控件的大小。在大多数情况下不需要为背景指定宽度或高度。
Qt帮助文档搜索 Label 获取详细信息。
文本样式
style:文本样式(如:Text.Normal、Text.Outline、Text.Raised、Text.Sunken)
高级属性
1)font.underline、font.strikeout:下划线和删除线样式
2)elide:省略模式(如:Text.ElideLeft、Text.ElideRight、Text.ElideMiddle)
3)lineHeight 和 lineHeightMode:行高和行高模式
4)renderType:渲染类型(如:Text.QtRendering、Text.NativeRendering)
字体 font
family、pointSize、weight
对齐和布局
1)horizontalAlignment:水平对齐方式(如:Qt.AlignLeft、Qt.AlignRight、Qt.AlignHCenter)
2)verticalAlignment:垂直对齐方式(如:Qt.AlignTop、Qt.AlignBottom、Qt.AlignVCenter)
3)wrapMode:文本换行模式(如:Text.NoWrap、Text.WordWrap、Text.WrapAnywhere、Text.Wrap)
交互
1)selectable:是否可以选择文本(用于复制等操作)
2)truncated:文本是否被截断
Label 的功能非常强大,我们甚至可以用它显示图片。
填充个 MouseArea,它还可以设计成一个自定义按钮:
描述
TextInput 显示单行可编辑的纯文本。
我们可以通过使用验证器 validator 或输入掩码 inputMask 来实现输入限制。
实际开发中常用 TextField 或 TextEdit 来替代 TextInput。
验证器和掩码
限制输入范围、类型、格式
回显
TextInput.Normal(默认)
TextInput.Password
TextInput.NoEcho
TextInput.PasswordEchoOnEdit
信号处理器
onAccepted()
onEditingFinished()
onTextEdited()
自定义外观
TextInput的缺点就是需要额外定义一下外观,初始的TextInput在窗口上根本看不见在哪。
描述
TextEdit 显示多行可编辑的纯文本或富文本。
Positioners 定位器具有 add、move 和 populate 属性,添加或删除控件时,可以使用 Transition 使这些操作具有动画效果。
1)add:定位器创建完毕后,向定位器中添加控件时
2)move:定位器中删除控件时
3)populate:定位器第一次创建时,只会运行一次
描述
用来创建大量相似的控件,包含一个模型 model 属性和一个委托 delegate 属性。委托用来将模型中的每个控件进行可视化显示。
描述
MouseArea 提供一系列触摸事件,它是一个不可见的项目,通常与可见项目组合实现界面交互。
属性
1)mouseX:real
2)mouseY:real
3)enabled:bool
4)pressed:bool
5)propagateComposedEvents:bool
信号
1)clicked(MouseEvent mouse):单击
2)pressed(MouseEvent mouse):按下
3)released(MouseEvent mouse):松开
4)positionChanged(MouseEvent mouse):鼠标移动(x、y)
5)doubleClicked(MouseEvent mouse):双击
6)pressAndHold(MouseEvent mouse):长按,按下达到一定时间才会激发
7)wheel(WheelEvent wheel):滚轮
再做一个小示例:在鼠标按下后,五角星图片跟着光标实时移动,并且图片中心和光标顶点重叠,鼠标松开后五角星图片停留在此处。
1 - 描述
MouseEvent 可以结合 MouseArea 类型获取鼠标事件,通过信号处理器与鼠标交互。通过 modifiers 获取按下键盘修饰符,包括:左键、右键、中键以及滚轮。
2 - 常用按键
在使用 MouseEvent 时,需要将 modifiers 与以下特殊按键进行按位与来判断按键。
- Qt.NoModifier - 没有修饰键被按下
- Qt.ShiftModifier - Shift键被按下
- Qt.ControlModifier - Ctrl键被按下
- Qt.AltModifier - Alt键被按下
- Qt.MetaModifier - Meta键被按下
- Qt.KeypadModifier - 小键盘按钮被按下
3 - WheelEvent 滚轮事件
WheelEvent 最重要的属性是 angleDelta,用来获取滚动距离,它的x、y坐标分别保存了水平和垂直方向的增量。向上或向右滚动返回正值,向下或向左滚动返回负值。
对于大多数鼠标,每当滚轮旋转一下默认是15°,此时 angleDelta 的值就是 15x8,即整数120。
下面做个小示例,窗口中心有个红色矩形,当鼠标放在矩形上并且点击鼠标左键后,矩形变为粉色,若点击右键则变为番茄红。
再做一个示例,当我们按下 Ctrl键,并且鼠标左键双击矩形,让矩形变为橘色。
鼠标滚轮示例:我们按住Ctrl键,然后光标放在文本上,接着用滚轮来控制文字的大小。
1 - 描述
实现项目拖拽
2 - 属性
1)drag.target:拖动的项目id
2)drag.active:是否可以被拖动
3)drag.axis:拖动方向
4)drag.minimumX:水平方向最小拖动距离
5)drag.maximumX:水平方向最大拖动距离
6)drag.minimumY:垂直方向最小拖动距离
7)drag.maximumY:垂直方向最大拖动距离
8)drag.threshold:拖动的阈值
3 - DropArea
它是一个不可见的项目。当其他项目拖动到其上时它可以接收相关事件。通过drag.x 和 drag.y 获取最后一个拖放事件坐标,使用drag.source 获取拖放的源对象,通过keys 获取拖放的键列表。
1)onEntered:拖放进入时
2)onDropped:drop 事件发生时
3)onExited:拖放离开时
4)onPositionChanged:拖放位置改变时
做一个拖拽五角星图片例子:
代码示例:添加一些不同颜色的小球,当我们拖动小球进入浅灰色正方体时,正方体变成和当前拖动的小球相同的颜色,当小球从正方体中出去时,正方体又恢复成原来的浅灰色。
小球是我们在另外一个qml文件中定义的:
描述
Loader 用于动态加载QML组件,可以加载QML文件或组件对象。一般将其放在主QML文件中,用于切换界面。
属性
source
从加载的项目中接收信号
任何从被加载的项目中发射的信号都可以使用 Connections 类型进行接收。
代码示例
用 Loader 和 Connections 实现多界面切换。如下图所示,当我们点击对应的动物头像,就可以去拜访它们的家啦!(跳转页面)然后点击中间“这是XX的家”就可以再跳转回主界面。
这个用Loader + Connections 实现起来很简单,但是我个人认为只适合少量的界面切换,如果你的界面很多,这个还是不太适合的,因为这里切换页面的核心是 Connections 下的一个函数,我们通过多条if语句去判断接收的信号,然后将对应的 source 设置到 Loader中。
在子界面中,我们需要自定义一个信号:
并且要发出信号,让主界面去接收,主界面接收了就可以做对应的事。
不全部做了,就记个日期功能吧!
autoRepeat、autoRepeatInterval 可以用来实现长按持续调节音量大小。下面是一个简单示例(看注释):
这里有个小技巧,当我们需要百分比显示数据,但是又不想要小数,可以直接用整数,后面的百分比符号用字符串来拼接上去,因为我们直接用小数或者百分比去计算,没准哪个区间会冒出老长一段小数。
如果需要用到比较复杂的逻辑判断,最好是封装到一个函数里,然后将值和函数进行绑定。
1 - 描述
QML语言与C++语言可以直接进行交互。这种机制允许将QML和C++进行混合开发。
QML与C++的交互具有以下优势:
1)UI界面与业务逻辑分离
2)扩展了QML语言的功能
注意:
一般情况下,不推荐C++中操作QML对象,重构QML要比重构C++容易的多。为了减少后期维护成本,建议尽量减少在C++端处理QML内容。
2 - QObject子类暴露给QML的方式
只有QObject派生的类才能将数据或函数提供给QML使用。由QObject派生的所有子类的属性、方法和信号等都可以在QML中访问。
暴露给QML的2种方式:
1)C++类注册为实例化QML类型
2)C++类型注册为一个单例类型
3 - QQmlContext
QQmlContext 提供对象实例化和表示式执行所需的运行时上下文。所有对象要在特定的上下文中实例化,所有表达式要在特定上下文中执行。
QQmlContext 允许数据暴露给QML引擎实例化的QML组件,它包括一系列属性,通过名字将数据显示绑定到上下文。
使用 setContextProperty() 函数来定义、更新上下文中的属性。
使用 QQmlContext 需要在C++文件中包含:
4 - 示例
添加新文件
第3步的时候,点击 instance,然后右键菜单中选择 重构(R)。
然后再点击 getText 右键去 cpp文件中重构:
这样,我们就可以在qml文件中调用了:
1 - 描述
Q_INVOKABLE 是一个宏,它可以让 QML 能直接访问 C++ 类中的成员函数。
通过这个宏,使复杂的业务逻辑可以在 C++中实现,而QML则专注于用户界面。这种分工使代码更加清晰,提高了整个应用的性能和可维护性。
在C++中成员函数默认无法被QML直接访问,为了实现这种跨语言的调用,当在类的成员函数前加上这个宏,Qt的元对象编译器(meta-Object Compiler,moc)会处理这个标记并在编译时生产额外的元数据,这些元数据使得函数能够在运行时被QML引擎识别和调用。
注意!在QML中绑定被 Q_INVOKABLE 修饰的函数它不会自动更新数据!
2 - 代码示例
下面我们做一个如下图所示的小程序,每点击一次左边加号按钮,中间的数字就会加上1,右侧的减号按钮则相反,即每点击一次中间的数字就会减掉1。
写完后我们发现,加减的2个按钮好像没生效,因为中间的数字没有变化。但实际上,按钮是生效了的,只是数据没有实时更新到 QML端,这个就是前面描述中提到的,被 Q_INVOKABLE 修饰的函数它不会自动更新数据。
那怎么才能实现实时更新呢?答案是加个定时器(Timer)…… 通过定时器来不断刷新。
1 - 描述
Q_PROPERTY 宏用于声明类的属性,这些属性可以在Qt的元对象系统中使用,从而实现属性的自动化处理,如绑定、序列化、动态属性设置等。
Q_PROPERTY 的作用:
1)属性声明:用于声明一个类的属性,并将其与类中的成员变量或成员函数关联起来。这使得属性可以通过Qt元对象系统进行访问和操作。
2)与Qt元对象系统集成:通过QObject的 setProperty 和 property 方法进行设置和获取,并且这些属性可以在Qt的设计器、Qt脚本、QML等中使用。
3)信号和槽的集成:可以与信号和槽机制结合使用,从而在属性值改变时自动发出信号,通知相关部分进行相应的处理。
2 - 语法
Q_PROPERTY (
)
注意!加粗并标红是必选参数,仅加粗是常用参数,其它为非常用参数。
3 - 自动生成
建议使用工具自动生成 Q_PROPERTY 相关代码!
别看 Q_PROPERTY 有这么多参数,其实一个也不用我们亲自去写,只需要用重构中的快捷功能就能快速创建出变量需要的所有信号、函数等等,这种自动生成的代码大大减少了人工编写的失误。
使用方法也非常简单哦~比如我们在 public 下声明一个变量 level。
然后我们点到 变量level 这个单词的中间,接着我们右键重构,点击 Generate Q_PROPERTY and Missing Members。
2步,仅此2步,你就可以去QML直接调用啦!
之前我们使用 Q_INVOKABLE,但是它不能实时更新,我们自己还要在 QML端专门写一个定时器去刷新。现在就不需要定时器了,因为它可以实时更新哦!
看看修改后的代码:
现在看起来是不是简洁多了?唯一不足可能就是一开始定义类那一块有点小麻烦,后面使用起来就很简单方便了。
1 - 描述
QML 代码可以使用 QObject 子类的任意 public信号。QML引擎会为每一个来自QObject派生类的信号自动创建一个信号处理器。
这些信号处理器具有相对统一的名字:on<Signal>,其中Signal 即信号的名字,首字母大写。信号传递的参数通过其名字在信号处理器中使用。
注意!
信号的参数必须能够被QML引擎支持。如果使用了QML引擎不支持的参数类型,程序不会报错,只是参数值不能在信号处理函数中被访问到。
C++类可能具有参数列表不同的多个同名信号,但是只有最后一个信号才能被QML访问到。使用相同名称不同参数的信号无法被区分。