像上面示例中的,按钮、列表视图、树形视图、单行输⼊框,多行输入框,滚动条、下拉框等等都可以称为 “控件”
Qt Designer
中就可以看出来,并且 Qt 也提供了 “自定义控件” 的能力,可以让我们在现有控件不能满足需求的时候,对现有控件做出扩展,或者手搓出新的控件。🔥 所以,学习 Qt 其中一个很重要的任务就是熟悉并掌握 Qt 内置的常用控件,这些控件对于我们快速开发出符合需求的界面是至关重要的
(例如文曲星的 Lava 平台开发)
(例如 html 的原生控件)
上图是前端中的 Element-ui 中的控件概览,无论是丰富程度还是颜值,都比 Qt 自带的控件更胜一筹
QT 近几年还提供了 Qt Desiign Studio
=> 对比现代化的界面体系
这些属性既可以通过 QtDesigner 直接修改,也可以通过代码的方式修改。这些属性的具体含义在 Qt Assistant 中均有详细介绍。
在 Qt Assistant 中搜索 QWidget,即可找到对应的文档说明 (或者在 Qt Creator 代码中选中 QWidget,按 F1(+Fn) 也可)
下面是后面我罗列出的其中一些比较重要和常用的属性,等下后面会着重进行介绍
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 | 针对输入框有效,用来提示用户当前能输入的合法数据格式,如只能输入数字、只能输入日期等。 |
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
这一列的对钩去掉,则按钮的初始状态就是 “禁用” 状态。
位置和尺寸是四个属性的统称:
在实际开发中,我们通常不会直接使用这四个属性来获取或修改控件的位置和大小。
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
既可以修改位置,又可以修改尺寸① 创建界面布局:
pushButton_target(目标按钮)
、pushButton_up(向上移动按钮)
、pushButton_down(向下移动按钮)
、pushButton_left(向左移动按钮)
和 pushButton_right(向右移动按钮)
。这些按钮的初始位置和大小可以随意设置。② 编写槽函数:
widget.cpp
文件中为每个方向的按钮添加槽函数,用于改变 pushButton_target
的位置。当点击相应的方向按钮时,会调整目标按钮的 x 和 y 坐标,从而实现位置变化③ 优化移动逻辑:
QRect
对象中的 x 和 y 值。setGeometry()
方法的第二个版本来重新设定按钮的位置,保持宽度和高度不变① 设计界面:
pushButton_forever
和拒绝 pushButton_moment
)以及一个标签 label
,用来显示文本信息② 实现交互逻辑:
widget.cpp
中定义槽函数,使得当用户点击 “forever…” 拒绝按钮时,触发按钮逃跑的行为。clicked
事件(即鼠标点击后释放)实现。运行程序可以看到:当点击 “forever…” 时,按钮一下就跑了。
上述代码使用的是 clicked(一下一上是点击),如果使用 pressed(鼠标按下事件)。
如果使用 mouseMoveEvent
,会更狠一些, 只要鼠标移动到这个按钮上面,按钮就跑了。
对应的代码更麻烦⼀些,需要使用到 Qt 的事件机制(需要自定义类继承自 QPushButton
,重写 mouseMoveEvent
方法)这里就暂时不展开了。
API | 说明 |
---|---|
windowTitle() | 获取控件的窗口标题。 |
setWindowTitle(const QString& title) | 设置控件的窗口标题 |
代码示例:设置窗口标题
API | 说明 |
---|---|
windowIcon() | 获取控件的窗口图标,返回 QIcon 对象。 |
setWindowIcon(const QIcon& icon) | 设置控件的窗口图标。同 windowTitle,仅对顶层 widget 有效。 |
这两个 API 类似于 windowTitle
,上述操作仅针对顶层 widget 有效。
图标网站:Yesicon 或者 iconfont-阿里巴巴矢量图标库
(1)设置窗口图标
widget.cpp
QIcon
对象本身是否释放并不影响图标最终的显示。
QIcon
也不支持对象树,无法给它执行父对象。
注意:
Windows
下路径的分隔符可以使用 / ,也可以使用 \并且程序在任务栏中的图标也发生了变化:
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
内部也进行了判定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);
字体属性是界面设计中重要的组成部分,它们影响着文本的外观。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
,然后运行程序即可
当 widget 作为一个窗口时(例如带有标题栏等),计算尺寸和坐标有两种算法:
window frame
的方式(如 x(), y(), frameGeometry(), pos(), move()
)
window frame
的方式(如 geometry(), width(), height(), rect(), size()
)
对于非窗口的 widget,这两种计算方式的结果是一致的。
(1) 在按钮的 slot 函数中编写代码 & 在构造函数中也添加同样的代码
(2)执行程序
geometry
和 frameGeometry
是相同的。geometry
和 frameGeometry
则存在差异。💡 原因:
Widget
刚刚创建出来,还没有加入到对象树中,此时也就不具备 Window frame
。
slot
函数中,由于用户点击的时候,对象树已经构造好了,此时 Widget
已经具备了 Window frame
,因此在位置和尺寸上均出现了差异。
pushButton
的 geometry
和 frameGeometry
,结果就是完全相同的。因为 pushButton
并非是一个窗口
因此我们具体使用的时候,需要明确使用的坐标系原点究竟是谁?
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
+=
<<
上述方法的效果都是等价的,即使不翻阅文档,单纯的凭借直觉就能把代码写对。减少了记忆负担,使编程变得更加直观和友好
"./image/Q&A.jpg"
,就需要在当前工作目录中创建 image 目录,并把 Q&A.jpg
放进去。对于 Qt 程序来说,当前工作目录可能是变化的:
所谓构建目录,是和 Qt 项目并列的,专门用来放生成的临时文件和最终 exe 的目录
Qt 使用 qrc 机制 来自动管理项目依赖的静态资源,解决了以下两个关键问题:
如果我们不知道这个路径在哪,可以输入下面代码来 查看运行程序的 工作目录 与 程序所在的目录
这种资源管理机制并非 Qt 独有,很多开发框架都有类似的机制。例如 Android
的 Resources
和 AssetManager
也提供了类似的功能。
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 中资源的路径匹配,否则资源无法被访问(同时也不会有报错提示)。
运行成功后,我们可以进入到项目的构建目录中可以看到:目录中多了一个
qrc_resource.cpp
文件,直接打开这个文件可以看到:
qrc 中导入的图片资源会被转成这个 qrc_resource.cpp
(自动生成)这个 c++ 代码,代码查看如下:
上述代码其实就是通过 unsigned char
数组,把 qt_bao.jpg
中的每个字节都记录下来。
这些代码会被编译到 exe 中,后续无论 exe 被复制到哪个目录下都确保能够访问到该图片资源。
上述 qrc 这一套资源管理方案的优点和缺点都很明显:
一个 GUI 程序,界面比较复杂,按钮很多,那么就需要提供一个功能:当我们鼠标悬停到这个控件的时候,就能弹出一个提示
Tooltip
是用户 悬停在 widget 上时显示的提示信息,有助于提高用户体验。API | 说明 |
---|---|
setToolTip(const QString &tooltip) | 设置 tooltip 文本 |
setToolTipDuration(int msec) | 设置 tooltip 显示的 时间,单位为毫秒 |
设置按钮的 toolTip
(1)在界面上拖放两个按钮:objectName
设置为 pushButton_moment
和pushButton_forever
(2)编写 widget.cpp
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 中,窗口/控件的 焦点是非常主要的
比如:我们在网页做题的时候,网页时属于始终获取到焦点的状态,但是如果我们一旦切到网页/程序,则该网页立刻就能感受到失去焦点,然后从此收集我们的动作来衡量 ”作弊“
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 色深等,具体情况会更加复杂。
运行程序
【*★,°*:.☆( ̄▽ ̄)/$:*.°★* 】那么本篇到此就结束啦,如果有不懂 和 发现问题的小伙伴可以在评论区说出来哦,同时我还会继续更新关于【QT】的内容,请持续关注我 !!