【QT】: 初识 QWidget 控件 | QWidget 核心属性(API) | qrc 文件
🔥 目录
1. 控件概述
像上面示例中的,按钮、列表视图、树形视图、单行输⼊框,多行输入框,滚动条、下拉框等等都可以称为 “控件”
Qt Designer
中就可以看出来,并且 Qt 也提供了 “自定义控件” 的能力,可以让我们在现有控件不能满足需求的时候,对现有控件做出扩展,或者手搓出新的控件。🔥 所以,学习 Qt 其中一个很重要的任务就是熟悉并掌握 Qt 内置的常用控件,这些控件对于我们快速开发出符合需求的界面是至关重要的
控件体系的发展阶段
(例如文曲星的 Lava 平台开发)
(例如 html 的原生控件)
上图是前端中的 Element-ui 中的控件概览,无论是丰富程度还是颜值,都比 Qt 自带的控件更胜一筹
QT 近几年还提供了 Qt Desiign Studio
=> 对比现代化的界面体系
2. QWidget 核心属性
在 Qt 中,使用 QWidget 类表示 “控件”,像按钮、视图、输入框、滚动条等具体的控件类,都是继承自 QWidget。QWidget 中包含了 Qt 整个控件体系中通用的部分。
在 Qt Designer 中,随便拖一个控件过来,选中该控件,即可在右下方可以看到 QWidget 中的属性。
这些属性既可以通过 QtDesigner 直接修改,也可以通过代码的方式修改。这些属性的具体含义在 Qt Assistant 中均有详细介绍。
在 Qt Assistant 中搜索 QWidget,即可找到对应的文档说明 (或者在 Qt Creator 代码中选中 QWidget,按 F1(+Fn) 也可)
2.1 核心属性概览
下面是后面我罗列出的其中一些比较重要和常用的属性,等下后面会着重进行介绍
QWidget
属性及其作用:
属性 | 作用 |
---|---|
enabled | 设置控件是否可使用。true 表示可用,false 表示禁用。 |
geometry | 控制控件的位置和尺寸,包含 x , y , width , height 四个部分。坐标是以父元素为参考进行设置的。 |
windowTitle | 设置 widget 的标题。 |
windowIcon | 设置 widget 的图标。 |
windowOpacity | 设置 widget 的透明度。 |
cursor | 设置鼠标悬停时显示的图标形状,如普通箭头、沙漏或十字等。可通过 Qt Designer 查看选项。 |
font | 控制字体相关属性,包括字体家族、大小、粗体、斜体、下划线等样式。 |
toolTip | 当鼠标悬停在 widget 上时,在状态栏中显示的提示信息。 |
toolTipDuration | toolTip 显示的持续时间。 |
statusTip | 当 widget 状态发生改变时(如按钮被按下)显示的提示信息。 |
whatsThis | 当鼠标悬停并按下 Alt+F1 时,显示的帮助信息(显示在一个弹出窗口中)。 |
styleSheet | 允许使用 CSS 来设置 widget 中的样式,支持丰富的样式,便于前端开发者上手。 |
focusPolicy | 定义 widget 如何获取焦点:NoFocus , TabFocus , ClickFocus , StrongFocus , WheelFocus 。 |
contextMenuPolicy | 设置上下文菜单的显示策略:DefaultContextMenu , NoContextMenu , PreventContextMenu , ActionsContextMenu , CustomContextMenu 。 |
ocale | 设置语言和国家地区。 |
acceptDrops | 设置该部件是否接受拖放操作。true 表示可以接收来自其他部件的拖放操作;false 则表示不接收任何拖放操作。 |
minimumSize | 控件的最小尺寸,包含最小宽度和最小高度。 |
maximumSize | 控件的最大尺寸,包含最大宽度和最大高度。 |
sizePolicy | 设置控件在布局管理器中的缩放方式。 |
windowModality | 指定窗口是否具有 “模态” 行为。 |
sizeIncrement | 拖动窗口大小时的增量单位。 |
baseSize | 窗口的基础大小,用于配合 sizeIncrement 调整组件尺寸。 |
palette | 设置 widget 的颜色风格。 |
mouseTracking | 是否跟踪鼠标移动事件。true 表示需要跟踪;false 表示不需要跟踪。 |
tabletTracking | 是否跟踪触摸屏的移动事件,类似于 mouseTracking 。Qt 5.9 引入的新属性 |
layoutDirection | 设置布局方向:LeftToRight , RightToLeft , LayoutDirectionAuto 。 |
autoFillBackground | 是否自动填充背景颜色。 |
windowFilePath | 将 widget 和一个本地文件路径关联起来。 |
accessibleName | 设置 widget 的可访问名称,辅助技术(如屏幕阅读器)可以获取到这个名称。 |
accessibleDescription | 设置 widget 的详细描述,作用同 accessibleName 。 |
inputMethodHints | 针对输入框有效,用来提示用户当前能输入的合法数据格式,如只能输入数字、只能输入日期等。 |
2.2 用件可用(Enabled)
API | 说明 |
---|---|
isEnabled() | 获取到控件的可用状态 |
setEnabled() | 设置控件是否可使用,code 表示可用,false 表示禁用 |
widget
被禁用,则该 widget
的子元素也被禁用。🧀 案例1:创建一个禁用状态的按钮:
运行程序,可以看到按钮处于灰色状态,无法被点击:
🧀 通过按钮 2 切换按钮 1 的禁用状态
(1)使用 Qt Designer 拖两个按钮到 Widget 中
objectName
分别为 pushButton
和 pushButton_2
QObject 的 objectName 属性介绍:
QObject
是 QWidget
的父类,里面最主要的属性就是 objectName
。在一个 Qt 程序中,objectName
相当于对象的身份标识,彼此之间不能重复。Qt Designer
时,尤其是界面上存在多个 widget
的时候,可以通过 objectName
获取到指定的 widget 对象。Qt Designer
生成的 ui 文件,本身是 xml 格式的,qmake
会把这个 xml 文件转换成 C++ 的 .h 文件(这个文件生成在 build 目录中),构成一个 ui_widget 类。widget
的 objectName
最终就会成为 ui_widget
类的属性名字。最终这个类的实例就是:Ui::Widget *ui
,因此就可以通过形如 ui->pushButton
或者 ui->pushButton_2
这样的代码获取到界面上的 widget 对象了。objectName
是有规律的:控件的类型 + 下划线 + 数字。很明显,以数字的方式命名并不是一个好的编程习惯,这里我将它修改为如下所示:(2)生成两个按钮的 slot 函数
运行程序可以看到:初始情况下,上面的按钮是可用状态。接着点击下方按钮,即可使上方按钮被禁用
Qt Designer
中创建按钮的时候可以设置按钮的初始状态是 “可用” 还是 “禁用”。如果把 enabled
这一列的对钩去掉,则按钮的初始状态就是 “禁用” 状态。
2.3 坐标系(Geometry)
位置和尺寸是四个属性的统称:
在实际开发中,我们通常不会直接使用这四个属性来获取或修改控件的位置和大小。
Qt
提供了一系列封装的方法,这些方法更方便操作,并且考虑到了 Qt
的左手坐标系——其中原点位于父元素的左上角。
API | 说明 |
---|---|
geometry() | 获取到控件的位置和尺寸,返回结果是一个QRect,包含 x, y, width, height,其中 x, y 是左上角坐标 |
setGeometry(QRect) seGeometry(int x, int y, int width, int height) | 设置控件的位置和尺寸,可以直接设置一个 QRect,也可以分四个属性单独设置 |
💡 move VS setGeometry
move
只是修改位置setGeometry
既可以修改位置,又可以修改尺寸实例 1: 控制按钮的位置
① 创建界面布局:
pushButton_target(目标按钮)
、pushButton_up(向上移动按钮)
、pushButton_down(向下移动按钮)
、pushButton_left(向左移动按钮)
和 pushButton_right(向右移动按钮)
。这些按钮的初始位置和大小可以随意设置。② 编写槽函数:
widget.cpp
文件中为每个方向的按钮添加槽函数,用于改变 pushButton_target
的位置。当点击相应的方向按钮时,会调整目标按钮的 x 和 y 坐标,从而实现位置变化
③ 优化移动逻辑:
QRect
对象中的 x 和 y 值。setGeometry()
方法的第二个版本来重新设定按钮的位置,保持宽度和高度不变实例 2: 表白 程序
① 设计界面:
pushButton_forever
和拒绝 pushButton_moment
)以及一个标签 label
,用来显示文本信息② 实现交互逻辑:
widget.cpp
中定义槽函数,使得当用户点击 “forever…” 拒绝按钮时,触发按钮逃跑的行为。clicked
事件(即鼠标点击后释放)实现。运行程序可以看到:当点击 “forever…” 时,按钮一下就跑了。
上述代码使用的是 clicked(一下一上是点击),如果使用 pressed(鼠标按下事件)。
如果使用 mouseMoveEvent
,会更狠一些, 只要鼠标移动到这个按钮上面,按钮就跑了。
对应的代码更麻烦⼀些,需要使用到 Qt 的事件机制(需要自定义类继承自 QPushButton
,重写 mouseMoveEvent
方法)这里就暂时不展开了。
2.4 窗口标题(windowTiltle)
API | 说明 |
---|---|
windowTitle() |
获取控件的窗口标题。 |
setWindowTitle(const QString& title) |
设置控件的窗口标题 |
代码示例:设置窗口标题
2.5 窗口图标(windowlcon)
API | 说明 |
---|---|
windowIcon() |
获取控件的窗口图标,返回 QIcon 对象。 |
setWindowIcon(const QIcon& icon) |
设置控件的窗口图标。同 windowTitle ,仅对顶层 widget 有效。 |
这两个 API 类似于 windowTitle
,上述操作仅针对顶层 widget 有效。
图标网站:Yesicon 或者 iconfont-阿里巴巴矢量图标库
(1)设置窗口图标
- 先在 D 盘中保存一张图片,我这里命名为 qt_bao.jpg
- 修改
widget.cpp
前面推荐使用堆来创建对象 ,主要是因为要确保当前控件的生命周期是足够的,要通过 Qt 对象树来释放对象。
但是对于 QIcon来说,QIcon 自身是一个比较小的对象。创建出来之后,就是要设置到某个 QWidget 里面, QIcon
对象本身是否释放并不影响图标最终的显示。
QIcon
也不支持对象树,无法给它执行父对象。
注意:
Windows
下路径的分隔符可以使用 / ,也可以使用 \并且程序在任务栏中的图标也发生了变化:
2.6 窗口透明度(windowOpacity)
API | 说明 |
---|---|
windowOpacity() |
获取控件的不透明数值,取值范围为 0.0(全透明)到 1.0(完全不透明)。 |
setWindowOpacity(float n) |
设置控件的不透明数值。 |
调整窗口透明度
(1)在界面上拖放两个按钮,分别用来增加不透明度和减少不透明度
objectName
分别为 pushButton_add 和 pushButton_sub:
(2)编写 wdiget.cpp
, 编写两个按钮的 slot 函数
pushButton_sub
会减少不透明度,也就是窗口越来越透明pushButton_add
会增加不透明度,窗口会逐渐恢复(3)执行程序
点击了几下 ‘-’ 之后,就可以透过窗⼝看到后面的内容了,点击 ‘+’ 又会逐渐恢复:
同时控制台中也可以看到 opacity 数值的变化,发现其窗口得到不透明度变化并非是精确的
注意 :
还有个小细节,我们上面加了判定条件
setWindowOpacity
内部也进行了判定2.7 光标属性(cursor)
API | 说明 |
---|---|
cursor() |
获取当前 widget 的光标属性,返回 QCursor 对象。 |
setCursor(const QCursor& cursor) |
设置该 widget 的光标形状,仅在鼠标停留在该 widget 上时生效。 |
QGuiApplication::setOverrideCursor(const QCursor& cursor) |
设置全局光标的形状,覆盖 setCursor 设置的内容。 |
1. 在 Qt Designer 中设置按钮的光标
(1)在界面中创建一个按钮,然后直接在右侧属性编辑区修改 cursor
属性为 “打开手势”
(2)运行程序
鼠标悬停到按钮上之后,就可以看到光标的变化。
2. 通过代码设置按钮的光标
(1) 编写 widget.cpp
其中 Qt::WaitCursor
就是自带的沙漏 / 转圈形状的光标。
系统内置的光标形状如下:
Ctrl + 左键点击 Qt::WaitCursor
跳转到源码即可看到:
3. 自定义鼠标光标
Qt 自带的光标形状有限,我们也可以自己找个图片,做成鼠标的光标,比如我们这里用我们上面图标那用到的宝可梦当鼠标光标
(1)用下面说到的,创建 qrc 的方法,来创建 qrc 资源文件,添加前缀 /,并加入图片
注意: 这里 pixmap = pixmap.scaled(10, 10);
2.8 字体属性(QFont)
字体属性是界面设计中重要的组成部分,它们影响着文本的外观。Qt 提供了多种方式来设置和获取字体属性。
API 说明
属性列表
属性 | 说明 |
---|---|
family | 字体家族,例如 “楷体”, “宋体”, “微软雅黑” 等 |
pointSize | 字体大小 |
weight | 字体粗细,以数值表示粗细程度,取值范围为 [0, 99],数值越大,越粗 |
bold | 是否加粗,设置为 true 相当于 weight 为 75;false 则为 50 |
italic | 是否倾斜 |
underline | 是否带有下划线 |
strikeOut | 是否带有删除线 |
1. 在 Qt Designer 中设置字体属性
1)在界面上创建一个 label
2)在右侧的属性编辑区,设置该 label 的 font 相关属性在这里调整上述属性,Qt Designer 能够对界面的属性设置支持 “实时预览”,因此我们可以实时的看到文字的变化。
3)执行程序,就可以看到上面的效果了
2. 在代码中设置字体属性
编写 widget.cpp
,然后运行程序即可
3. Window Frame 的影响
当 widget 作为一个窗口时(例如带有标题栏等),计算尺寸和坐标有两种算法:
包含 window frame
的方式(如 x(), y(), frameGeometry(), pos(), move()
)
不包含 window frame
的方式(如 geometry(), width(), height(), rect(), size()
)
对于非窗口的 widget,这两种计算方式的结果是一致的。
Geometry 和 FrameGeometry 的区别
(1) 在按钮的 slot 函数中编写代码 & 在构造函数中也添加同样的代码
(2)执行程序
geometry
和 frameGeometry
是相同的。geometry
和 frameGeometry
则存在差异。💡 原因:
在构造方法中,Widget
刚刚创建出来,还没有加入到对象树中,此时也就不具备 Window frame
。
在按钮的 slot
函数中,由于用户点击的时候,对象树已经构造好了,此时 Widget
已经具备了 Window frame
,因此在位置和尺寸上均出现了差异。
如果把上述代码修改成打印 pushButton
的 geometry
和 frameGeometry
,结果就是完全相同的。因为 pushButton
并非是一个窗口
因此我们具体使用的时候,需要明确使用的坐标系原点究竟是谁?
4. API 设计理念
API | 说明 |
---|---|
x() | 获取横坐标。计算时包含 window frame。 |
y() | 获取纵坐标。计算时包含 window frame。 |
pos() | 返回 QPoint 对象,包含 x() 和 y() 的值及设置方法。计算时包含 window frame。 |
frameSize() | 返回 QSize 对象,包含 width() 和 height() 及其设置方法。计算时包含 window frame。 |
frameGeometry() | 返回 QRect 对象,相当于 QPoint 和 QSize 的结合体,可以获取 x, y, width, size。计算时包含 window frame 对象。 |
width() | 获取宽度。计算时不包含 window frame。 |
height() | 获取高度。计算时不包含 window frame。 |
size() | 返回 QSize 对象,包含 width() 和 height() 及其设置方法。计算时不包含 window frame。 |
rect() | 返回 QRect 对象,可以获取并设置 x, y, width, size。计算时不包含 window frame 对象。 |
geometry() | 返回 QRect 对象,可以获取 x, y, width, size。计算时不包含 window frame 对象。 |
setGeometry() | 设置窗口的位置和尺寸,可以设置 x, y, width, height 或 QRect 对象。计算时不包含 window frame 对象。 |
认真观察上面的表格,可以看到,其实这里的 API 有 frameGeometry
和 geometry
两个就足够完成所有的需求了。
为什么要提供这么多功能重复的 API 呢?
这涉及到 Qt API 的设计理念:尽量符合人的直觉。例如,Qt 的
QVector
提供了多种尾插元素的方法:push_back
append
+=
<<
上述方法的效果都是等价的,即使不翻阅文档,单纯的凭借直觉就能把代码写对。减少了记忆负担,使编程变得更加直观和友好
5. 资源管理与路径使用
1、图片路径的选择
"./image/Q&A.jpg"
,就需要在当前工作目录中创建 image 目录,并把 Q&A.jpg
放进去。2、路径类型说明
对于 Qt 程序来说,当前工作目录可能是变化的:
通过 Qt Creator 运行的程序,当前工作目录是项目的构建目录 直接双击 exe 运行时,工作目录则是 exe 所在目录
3、构建目录的作用
所谓构建目录,是和 Qt 项目并列的,专门用来放生成的临时文件和最终 exe 的目录
Qt 使用 qrc 机制 来自动管理项目依赖的静态资源,解决了以下两个关键问题:
- 确保我们的 图片所在路径在目标用户机器上存在
- 确保我们的 图片不会被用户误删或修改
如果我们不知道这个路径在哪,可以输入下面代码来 查看运行程序的 工作目录 与 程序所在的目录
6. qrc 文件
6.1 qrc 文件的特点
qrc 文件是一种 XML 格式的资源配置文件
它用 XML 记录硬盘上的文件和对应的随意指定的资源名称,应用程序通过资源名称来访问这些资源
在 Qt 开发中,可以通过将资源文件添加到项目中来方便地访问和管理这些资源,这些资源文件可以位于 qrc 文件所在目录的同级或其子目录下
在构建程序的过程中,Qt 会把资源文件的二进制数据转成 cpp 代码,编译到 exe 中,从而使依赖的资源变得 “路径无关”。
这种资源管理机制并非 Qt 独有,很多开发框架都有类似的机制。例如 Android
的 Resources
和 AssetManager
也提供了类似的功能。
qrc 的局限性
6.2 通过 qrc 管理图片作为图标
(1)右键项目,创建一个 Qt Resource File(qrc 文件), 文件名随意起(不要带中文),此处叫做 resource.qrc
如下:
(2)在 qrc 编辑器中 添加 前缀
png&pos_id=img-Sq50mLtn-1737007918100)
此处我们前缀设置成 / 即可。
所谓的前缀,可以理解成 “虚拟的目录”,这个目录在我们的电脑中并不是真实存在的,是 Qt 自己抽象出来的,它决定了后续我们如何在代码中访问资源。
(3)在资源编辑器中,点击 add Files 添加资源文件
此处我们需要添加的是:qt_bao.jpg:
注意 :
(4)在代码中使用 qt_bao.jpg
代码中需要访问 qrc 中管理的文件时,就需要在路径上带有 : 前缀。创建的前缀叫什么名字,代码中就写什么名字:前缀 + 文件名。
注意上述路径的访问规则:
-
使用 : 作为开头,表示从 qrc 中读取资源
-
/ 是上面配置的前缀
-
qt_bao.jpg 是资源的名称
🔥 需要确保代码中编写的路径 和添加到 qrc 中资源的路径匹配,否则资源无法被访问(同时也不会有报错提示)。
运行成功后,我们可以进入到项目的构建目录中可以看到:目录中多了一个
qrc_resource.cpp
文件,直接打开这个文件可以看到:
qrc 中导入的图片资源会被转成这个 qrc_resource.cpp
(自动生成)这个 c++ 代码,代码查看如下:
上述代码其实就是通过 unsigned char
数组,把 qt_bao.jpg
中的每个字节都记录下来。
这些代码会被编译到 exe 中,后续无论 exe 被复制到哪个目录下都确保能够访问到该图片资源。
上述 qrc 这一套资源管理方案的优点和缺点都很明显:
优点:确保了图片、字体、剩余等资源能够真正做到 “目录无关”,无论如何都不会出现资源丢失的情况。 缺点:不适合管理体积大的资源。如果资源比较大(比如是几个 MB 的文件),或者资源特别多,生成的最终的 exe 体积就会比较大,程序运行消耗的内存也会增大,程序编译的时间也会显著增加。
7. 其他
7.1 ToolTip 设置
一个 GUI 程序,界面比较复杂,按钮很多,那么就需要提供一个功能:当我们鼠标悬停到这个控件的时候,就能弹出一个提示
Tooltip
是用户 悬停在 widget 上时显示的提示信息,有助于提高用户体验。API | 说明 |
---|---|
setToolTip(const QString &tooltip) | 设置 tooltip 文本 |
setToolTipDuration(int msec) | 设置 tooltip 显示的 时间,单位为毫秒 |
设置按钮的 toolTip
(1)在界面上拖放两个按钮:objectName
设置为 pushButton_moment
和pushButton_forever
(2)编写 widget.cpp
7.2 Focus Policy 设置
Focus policy 决定了控件是否及如何接收 键盘焦点
设置控件获取到焦点的策略,比如某个控件 能否用鼠标选中 或者 能否通过 tab 键选中
API | 说明 |
---|---|
focusPolicy() | 获取当前 widget 的 focus policy |
setFocusPolicy(Qt::FocusPolicy policy) | 设置 widget 的 focus policy |
Qt::FocusPolicy 是一个枚举类型,如下:
Qt::NoFocus
:控件不会接收键盘焦点。Qt::TabFocus
:控件可以通过 Tab 键接收焦点。Qt::ClickFocus
:控件在鼠标点击时接收焦点。Qt::StrongFocus
:默认值,控件可以通过 Tab 键和鼠标点击接收焦点。Qt::WheelFocus
:类似于 Qt::StrongFocus
,同时控件也通过鼠标滚轮获取到焦点。💡 代码示例:理解不同的 focusPolicy
(1)在界面上创建四个单行输入框(Line Edit)
(2)修改四个输入框的 focusPolicy 属性分别为 Qt::StrongFocus (默认取值,一般不用额外修改)、Qt::NoFucus、Qt::TabFucus、Qt::ClickFucus
结果如下:
GUI 中,窗口/控件的 焦点是非常主要的
比如:我们在网页做题的时候,网页时属于始终获取到焦点的状态,但是如果我们一旦切到网页/程序,则该网页立刻就能感受到失去焦点,然后从此收集我们的动作来衡量 ”作弊“
7.3 Style Sheet(QSS)
CSS(Cascading Style Sheets 层叠样式表)本身属于网页前端技术,主要用于 描述界面的样式。
然而,Qt 只能支持部分 CSS 样式属性,这些被支持的属性称为 QSS(Qt Style Sheet)。具体的支持情况可以参考 Qt 文档中的 "Qt Style Sheets Reference"
章节。
设置文本样式
(1)在界面上创建 label,然后编辑右侧的 styleSheet 属性,设置样式
或者右击,选择下面这种方式打开
然后对样式表,编写如下:
font-family: '微软雅黑';
font-size: 30px;
font-style: bond;
color: red;
text-align: center
这样的文本居中操作,在某些情况下可能无法支持。编辑完成样式之后,可以看到在 Qt Designer 中能够实时预览出效果:
实现切换夜间模式
(1)在界面上创建一个多行输入框(Text Edit)和两个按钮objectName
分别为 pushButton_light
和 pushButton_dark
(2)编写按钮的 slot 函数
#333
是深色,但不是完全黑色。#fff
是纯白色。#000
是纯黑色。关于颜色,我们可以使用在线调色板或画图板工具可以查看颜色对应的数值。
关于计算机中的颜色表示
混合三种不同颜色的数值比例可以搭配出千千万万的颜色出来。
rgb(255, 0, 0) 或者 #FF0000 或者 #F00 表示纯红色。
rgb(0, 255, 0) 或者 #00FF00 或者 #0F0 表示纯绿色。
rgb(0, 0, 255) 或者 #0000FF 或者 #00F 表示纯蓝色。
rgb(255, 255, 255) 或者 #FFFFFF 或者 #FFF 表示纯白色。
rgb(0, 0, 0) 或者 #000000 或者 #000 表示纯黑色。
上述规则适用于一般程序的颜色设定。
实际显示器可能会有8bit 色深或者 10bit 色深等,具体情况会更加复杂。
运行程序
8. 共勉
【*★,°*:.☆( ̄▽ ̄)/$:*.°★* 】那么本篇到此就结束啦,如果有不懂 和 发现问题的小伙伴可以在评论区说出来哦,同时我还会继续更新关于【QT】的内容,请持续关注我 !!
作者:IsLand1314~