1 🍑控件概述🍑
Widget
是 Qt 中的核⼼概念. 英⽂原义是 “⼩部件”, 我们此处也把它翻译为 “控件” .控件是构成⼀个图形化界⾯的基本要素。
Qt 作为⼀个成熟的 GUI 开发框架, 内置了⼤量的常⽤控件。这⼀点在 Qt Designer 中就可以看到端倪,并且 Qt 也提供了 “⾃定义控件” 的能⼒, 可以让程序猿在现有控件不能满⾜需求的时候, 对现有控件做出扩展, 或者⼿搓出新的控件。
2 🍑QWidget 核心属性🍑
在 Qt 中, 使⽤ QWidget
类表⽰ “控件”。像按钮、视图、输⼊框、滚动条等具体的控件类, 都是继承⾃QWidget
。
可以说, QWidget 中就包含了 Qt 整个控件体系中通⽤的部分,在 Qt Designer 中, 随便拖⼀个控件过来, 选中该控件, 即可在右下⽅看到 QWidget 中的属性。
这些属性既可以通过 QtDesigner 会直接修改, 也可以通过代码的⽅式修改。
2.1 🍎核心属性概览🍎
下列表格列出了 QWidget 中的属性及其作⽤:
属性 | 作⽤ |
---|---|
enabled | 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤ |
geometry | 位置和尺⼨,包含 x, y, width, height 四个部分。其中坐标是以⽗元素为参考进⾏设置的。 |
windowTitle | 设置 widget 标题 |
windowIcon | 设置 widget 图标 |
windowOpacity | 设置 widget 透明度 |
cursor | ⿏标悬停时显⽰的图标形状,是普通箭头,、还是沙漏、还是⼗字等形状,在 Qt Designer 界⾯中可以清楚看到可选项。 |
font | 字体相关属性,涉及到字体家族、字体⼤⼩、粗体、斜体、下划线等等样式。 |
toolTip | ⿏标悬停在 widget 上会在状态栏中显⽰的提⽰信息。 |
toolTipDuring | toolTip 显⽰的持续时间。 |
statusTip | Widget 状态发⽣改变时显⽰的提⽰信息(⽐如按钮被按下等)。 |
whatsThis | ⿏标悬停并按下 alt+F1 时, 显⽰的帮助信息(显⽰在⼀个弹出的窗⼝中)。 |
styleSheet | 允许使⽤ CSS 来设置 widget 中的样式,Qt 中⽀持的样式⾮常丰富, 对于前端开发⼈员上⼿是⾮常友好的。 |
focusPolicy | 该 widget 如何获取到焦点:Qt::NoFocus:控件不参与焦点管理,即⽆法通过键盘或⿏标获取焦点;Qt::TabFocus:控件可以通过Tab键获得焦点;Qt::ClickFocus:控件可以通过⿏标点击获得焦点;Qt::StrongFocus:控件可以通过键盘和⿏标获得焦点;Qt::WheelFocus:控件可以通过⿏标滚轮获得焦点(在某些平台或样式中可能不可⽤)。 |
contextMenuPolicy | 上下⽂菜单的显⽰策略:Qt::DefaultContextMenu:默认的上下⽂菜单策略,⽤⼾可以通过⿏标右键或键盘快捷键触发上下⽂菜单;Qt::NoContextMenu:禁⽤上下⽂菜单,即使⽤⼾点击⿏标右键也不会显⽰菜单;Qt::PreventContextMenu:防⽌控件显⽰上下⽂菜单,即使⽤⼾点击⿏标右键也不会显⽰菜单;Qt::ActionsContextMenu:将上下⽂菜单替换为控件的“动作”菜单,⽤⼾可以通过⿏标右键或键盘快捷键触发这个菜单,Qt::CustomContextMenu:使⽤⾃定义的上下⽂菜单,⽤⼾可以通过⿏标右键或键盘快捷键触发这个菜单。 |
locale | 设置语⾔和国家地区。 |
acceptDrops | 该部件是否接受拖放操作。如果设置为true,那么该部件就可以接收来⾃其他部件的拖放操作。当⼀个部件被拖放到该部件上时,该部件会接收到相应的拖放事件(如dropEvent)。如果设置为false,那么该部件将不会接收任何拖放操作。 |
minimumSize | 控件的最⼩尺⼨. 包含最⼩宽度和最⼩⾼度 |
maximumSize | 控件的最⼤尺⼨. 包含最⼤宽度和最⼤⾼度 |
sizePolicy | 尺⼨策略,设置控件在布局管理器中的缩放⽅式 |
windowModality | 指定窗⼝是否具有 “模态” ⾏为 |
sizeIncrement | 拖动窗⼝⼤⼩时的增量单位 |
baseSize | 窗⼝的基础⼤⼩, ⽤来搭配 sizeIncrement 调整组件尺⼨是计算组件应该调整到的合适的值。 |
palette | 调⾊板. 可以设置 widget 的颜⾊⻛格 |
mouseTracking | 是否要跟踪⿏标移动事件。如果设为 true, 表⽰需要跟踪, 则⿏标划过的时候该 widget 就能持续收到⿏标移动事件,如果设为 false, 表⽰不需要跟踪, 则⿏标划过的时候 widget 不会收到⿏标移动事件, 只能收到⿏标按下或者释放的事件。 |
tabletTracking | 是否跟踪触摸屏的移动事件,类似于 mouseTracking . Qt 5.9 中引⼊的新属性。 |
layoutDirection | 布局⽅向:Qt::LeftToRight:⽂本从左到右排列,也是默认值;Qt::RightToLeft:⽂本从右到左排列;Qt::GlobalAtomics:部件的布局⽅向由全局原⼦性决定(PS 这个翻译其实有点尴尬,其实就是根据应⽤程序中的其他 widget 布局⽅向确定的) |
autoFillBackground | 是否⾃动填充背景颜⾊ |
windowFilePath | 能够把 widget 和⼀个本地⽂件路径关联起来. PS: 其实作⽤不⼤ |
accessibleName | 设置 widget 的可访问名称. 这个名称可以被辅助技术 (像屏幕阅读器) 获取到 |
accessibleDescription | 设置 widget 的详细描述. 作⽤同 accessibleName |
inputMethodHints | 针对输⼊框有效, ⽤来提⽰⽤⼾当前能输⼊的合法数据的格式. ⽐如只能输⼊数字, 只能输⼊⽇期等。 |
接下来我们会介绍其中⼀些⽐较重要⽐较常⽤的属性。
2.2 🍎enabled🍎
API | 说明 |
---|---|
isEnabled() | 获取到控件的可⽤状态 |
setEnabled | 设置控件是否可使⽤,true 表⽰可⽤, false 表⽰禁⽤ |
🎨 所谓 “禁⽤” 指的是该控件不能接收任何⽤⼾的输⼊事件, 并且外观上往往是灰⾊的,如果⼀个 widget 被禁⽤, 则该 widget 的⼦元素也被禁⽤。
代码⽰例: 通过按钮2 切换按钮1 的禁⽤状态:
2.3 🍎geometry🍎
位置和尺⼨,其实是四个属性的统称:
x
横坐标y
纵坐标width
宽度height
⾼度
但是实际开发中, 我们并不会直接使⽤这⼏个属性, ⽽是通过⼀系列封装的⽅法来获取/修改:
API | 说明 |
---|---|
geometry() | 获取到控件的位置和尺⼨,返回结果是⼀个 QRect, 包含了 x、y、width、height,其中 x, y 是左上⻆的坐标 |
setGeometry(QRect) | 设置控件的位置和尺⼨,可以直接设置⼀个 QRect, 也可以分四个属性单独设置 |
setGeometry(int x, int y, int width, int height) | 设置控件的位置和尺⼨,可以直接设置⼀个 QRect, 也可以分四个属性单独设置 |
我们来试试:
运⾏程序可以看到, 按下下⽅的四个按钮, 就会控制 target 的左上⻆的位置. 对应的按钮整个尺⼨也会发⽣改变。
上述代码中我们是直接设置的 QRect 中的 x, y ,实际上 QRect 内部是存储了左上和右下两个点的坐标, 再通过这两个点的坐标差值计算⻓宽,单纯修改左上坐标就会引起整个矩形的⻓宽发⽣改变。
🏝 window frame 的影响
如果 widget 作为⼀个窗⼝ (带有标题栏, 最⼩化, 最⼤化, 关闭按钮), 那么在计算尺⼨和坐标的时候就有两种算法。包含 window frame 和 不包含 window frame。其中 x(), y(), frameGeometry(), pos(), move()
都是按照包含 window frame 的⽅式来计算的。其中 geometry(), width(), height(), rect(), size()
则是按照不包含 window frame 的⽅式来计算的,当然, 如果⼀个不是作为窗⼝的 widget , 上述两类⽅式得到的结果是⼀致的。
相关 API:
API | 说明 |
---|---|
x() | 获取横坐标,计算时包含 window frame |
y() | 获取纵坐标,计算时包含 window frame |
pos() | 返回 QPoint 对象, ⾥⾯包含 x(), y(), setX(), setY() 等⽅法,计算时包含 window frame |
frameSize() | 返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法,计算时包含 window frame |
frameGeometry() | 返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y,width, size,计算时包含 window frame 对象 |
width() | 获取宽度,计算时不包含 window frame |
height() | 获取⾼度,计算时不包含 window frame |
size() | 返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法,计算时不包含 window frame |
rect() | 返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取并设置 x,y, width, size,计算时不包含 window frame 对象 |
geometry() | 返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y,width, size,计算时不包含 window frame 对象 |
setGeometry() | 直接设置窗⼝的位置和尺⼨. 可以设置 x, y, width, height, 或者 QRect 对象,计算时不包含 window frame 对象 |
我们写代码来感受一下他们的区别:
当执行时:
发现第一次执行结果是相同的,而第二次的执行结果是不同的。这是为什么呢?
在构造⽅法中,Widget 刚刚创建出来, 还没有加⼊到对象树中,此时也就不具备 Window frame
,在按钮的 slot 函数中, 由于⽤⼾点击的时候, 对象树已经构造好了, 此时 Widget 已经具备了Window frame
, 因此在位置和尺⼨上均出现了差异。如果把上述代码修改成打印 pushButton
的 geometry
和 frameGeometry
, 结果就是完全相同的, 因为 pushButton
并⾮是⼀个窗⼝。
2.4 🍎windowTitle🍎
API | 说明 |
---|---|
windowTitle() | 获取到控件的窗⼝标题 |
setWindowTitle(const QString& title) | 设置控件的窗⼝标题 |
注意! 上述设置操作针对不同的 widget 可能会有不同的⾏为,如果是顶层 widget
(独⽴窗⼝), 这个操作才会有效。
2.5 🍎windowIcon🍎
API | 说明 |
---|---|
windowIcon() | 获取到控件的窗⼝图标. 返回 QIcon 对象 |
setWindowIcon(const QIcon& icon) | 设置控件的窗⼝图标 |
🎹 同 windowTitle, 上述操作仅针对顶层
widget
有效
实际开发中, 我们⼀般不会在代码中通过绝对路径引⼊图⽚. 因为我们⽆法保证程序发布后, ⽤⼾的电脑上也有同样的路径。如果使⽤相对路径, 则需要确保代码中的相对路径写法和图⽚实际所在的路径匹配 (⽐如代码中写作 “./image/rose.jpg”, 就需要在当前⼯作⽬录中创建 image ⽬录, 并把 rose.jpg 放进去)
Qt 使⽤
qrc
机制更⽅便的来管理项⽬依赖的静态资源。
qrc ⽂件是⼀种XML格式的资源配置⽂件, 它⽤XML记录硬盘上的⽂件和对应的随意指定的资源名称。应⽤程序通过资源名称来访问这些资源。在Qt开发中, 可以通过将资源⽂件添加到项⽬中来⽅便地访问和管理这些资源. 这些资源⽂件可以位于qrc⽂件所在⽬录的同级或其⼦⽬录下。
在构建程序的过程中, Qt 会把资源⽂件的⼆进制数据转成 cpp 代码, 编译到 exe 中,从⽽使依赖的资源变得 “路径⽆关”。这种资源管理机制并⾮ Qt 独有, 很多开发框架都有类似的机制。例如 Android 的 Resources和 AssetManager 也是类似的效果。
接下来我们使用QtCreator来创建一个qrc ⽂件:
-
1️⃣右键项⽬, 创建⼀个 Qt Resource File (qrc ⽂件), ⽂件名随意起(不要带中⽂)
-
2️⃣ 在 qrc 编辑器中, 添加前缀
此处我们前缀设置成/
即可,所谓的前缀, 可以理解成 “⽬录” ,这个前缀决定了后续我们如何在代码中访问资源。 -
3️⃣在 资源编辑器 中, 点击 add Files 添加资源⽂件,此处我们需要添加的是 rabbit.png
添加完毕后, 可以在 资源编辑器 中看到添加好的⽂件:
-
4️⃣在代码中使⽤ rose.jpg
注意上述路径的访问规则:
- 使⽤
:
作为开头, 表⽰从 qrc 中读取资源; /
是上⾯配置的前缀;rabbit.png
是资源的名称;
需要确保代码中编写的路径和添加到 qrc 中资源的路径匹配,否则资源⽆法被访问 (同时也不会有报错提⽰)
- 5️⃣运⾏程序, 可以看到图标已经能正确设置
接下来, 我们可以进⼊到项⽬的构建⽬录, 可以看到, ⽬录中多了⼀个 qrc_resource.cpp
⽂件,直接打开这个⽂件, 可以看到类似如下代码:
上述代码其实就是通过 unsigned char 数组, 把 rabbit.png 中的每个字节都记录下来,这些代码会被编译到 exe 中,后续⽆论 exe 被复制到哪个⽬录下, 都确保能够访问到该图⽚资源。
上述 qrc
这⼀套资源管理⽅案, 优点和缺点都很明显:
- 优点: 确保了图⽚, 字体, 声⾳等资源能够真正做到 “⽬录⽆关”, ⽆论如何都不会出现资源丢失的情况。
- 缺点: 不适合管理体积⼤的资源,如果资源⽐较⼤ (⽐如是⼏个 MB 的⽂件), 或者资源特别多,⽣成的最终的 exe 体积就会⽐较⼤, 程序运⾏消耗的内存也会增⼤,程序编译的时间也会显著增加。
2.6 🍎windowOpacity🍎
API | 说明 |
---|---|
windowOpacity() | 获取到控件的不透明数值,返回 float, 取值(0.0~1.0) 其中 0.0 表⽰全透明, 1.0 表⽰完全不透明 |
setWindowOpacity(float n) | 设置控件的不透明数值 |
这个很简单,就不再过多演示了。
2.7 🍎cursor🍎
API | 说明 |
---|---|
cursor() | 获取到当前 widget 的 cursor 属性, 返回 QCursor 对象.当⿏标悬停在该 widget 上时, 就会显⽰出对应的形状 |
setCursor(const QCursor& cursor) | 设置该 widget 光标的形状. 仅在⿏标停留在该 widget 上时⽣效 |
QGuiApplication::setOverrideCursor(const QCursor& cursor) | 设置全局光标的形状. 对整个程序中的所有 widget 都会⽣效,覆盖上⾯的 setCursor 设置的内容 |
我们先创建一个按钮,然后在右侧的编辑框里面找到cursor这个选项:
当我们将鼠标移动到按钮那里的时候就会显示我们设置的是哪一种形状。
出了系统默认带的形状外,我们还可以自定义的设置,方式还是使用的是qrc机制:
2.8 🍎font🍎
API | 说明 |
---|---|
font() | 获取当前 widget 的字体信息,返回 QFont 对象 |
setFont(const QFont& font) | 设置当前 widget 的字体信息 |
关于 QFont
:
属性 | 说明 |
---|---|
family | 字体家族 ⽐如 “楷体”, “宋体”, “微软雅⿊” 等 |
pointSize | 字体⼤⼩ |
weight | 字体粗细. 以数值⽅式表⽰粗细程度取值范围为 [0, 99], 数值越⼤, 越粗 |
bold | 是否加粗. 设置为 true, 相当于 weight 为 75. 设置为 false 相当于weight 为 50 |
italic | 是否倾斜 |
underline | 是否带有下划线 |
strikeOut | 是否带有删除线 |
这个设置我们可以使用代码的方式也可以使用可视化的方式进行。
2.9 🍎toolTip🍎
API | 说明 |
---|---|
setToolTip | 设置 toolTip,⿏标悬停在该 widget 上时会有提⽰说明 |
setToolTipDuring | 设置 toolTip 提⽰的时间(单位 ms),时间到后 toolTip ⾃动消失 |
toolTip 只是给⽤⼾看的,在代码中⼀般不需要获取到 toolTip
示例:
2.10 🍎focusPolicy🍎
设置控件获取到焦点的策略,⽐如某个控件能否⽤⿏标选中或者能否通过 tab
键选中。
所谓 “焦点” , 指的就是能选中这个元素,接下来的操作 (⽐如键盘操作), 就都是针对该焦点元素进⾏的了,这个对于 输⼊框, 单选框,复选框等控件⾮常有⽤的。
API | 说明 |
---|---|
focusPolicy() | 获取该 widget 的 focusPolicy, 返回 Qt::FocusPolicy |
setFocusPolicy(Qt::FocusPolicy policy) | 设置 widget 的 focusPolicy |
Qt::FocusPolicy 是⼀个枚举类型,取值如下:
Qt::NoFocus
:控件不会接收键盘焦点Qt::TabFocus
:控件可以通过Tab键接收焦点Qt::ClickFocus
:控件在⿏标点击时接收焦点Qt::StrongFocus
:控件可以通过Tab键和⿏标点击接收焦点 (默认值)Qt::WheelFocus
: 类似于 Qt::StrongFocus , 同时控件也通过⿏标滚轮获取到焦点 (新增的选项, ⼀般很少使⽤)
2.11 🍎styleSheet🍎
通过 CSS 设置 widget 的样式。
CSS (Cascading Style Sheets 层叠样式表) 本⾝属于⽹⻚前端技术,主要就是⽤来描述界⾯的样式,所谓 “样式”, 包括不限于 ⼤⼩, 位置, 颜⾊, 间距, 字体, 背景, 边框等。我们平时看到的丰富多彩的⽹⻚, 就都会⽤到⼤量的 CSS,Qt 虽然是做 GUI 开发, 但实际上和 ⽹⻚前端 有很多异曲同⼯之处. 因此 Qt 也引⼊了对于 CSS的⽀持。
CSS 中可以设置的样式属性⾮常多,基于这些属性 Qt 只能⽀持其中⼀部分, 称为 QSS (Qt Style Sheet)具体的⽀持情况可以参考 Qt ⽂档中 “Qt Style Sheets Reference” 章节。