Qt界面优化
背景介绍
在⽹⻚前端开发领域中, CSS 是⼀个⾄关重要的部分. 描述了⼀个⽹⻚的 “样式”. 从⽽起到对⽹⻚美化的作⽤.
所谓样式, 包括不限于⼤⼩, 位置, 颜⾊, 背景, 间距, 字体等等.
现在的⽹⻚很难找到没有 CSS 的. 可以说让 “界⾯好看” 是⼀个刚需.
⽹⻚开发作为 GUI 的典型代表, 也对于其他客⼾端 GUI 开发产⽣了影响. Qt 也是其中之⼀.
Qt 仿照 CSS 的模式, 引⼊了 QSS, 来对 Qt 中的控件做出样式上的设定, 从⽽允许程序猿写出界⾯更好看的代码.
当然, 由于 Qt 本⾝的设计理念和⽹⻚前端还是存在⼀定差异的, 因此 QSS 中只能⽀持部分 CSS 属性.整体来说 QSS 要⽐ CSS 更简单⼀些.
基本语法
对于CSS来说,基本的语法结构非常简单:
选择器{
属性名:属性值;
}
QSS沿用了这样的特性:
选择器{
属性名:属性值;
}
- 选择器: 描述了那个控件要应用样式规则(在于确定谁?);
- 属性: 是一个键值对,属性名表示要设置那种样式,属性值表示设置的样式的值(在于怎么做?);
eg:
QPushButton {
color: red;
}
上面这个例子表示:
将所有的QPushButton的文本样式设置为红色;
eg:当用户点击按钮的时候就会将按钮上的文本颜色进行替换:
-
设计大概UI界面:
-
给按钮控件的clicked信号绑定对应的槽函数:
-
运行结果:
上述通过控件的setStyleSheet成员函数设置的QSS样式,只会针对当前控件生效,不会对界面上的其它按钮控件生效;
QSS设置方式
指定控件样式设置
就是通过控件的成员函数setStyleSheet来来设置QSS,这样设置出来的样式只针对当前控件本身生效,在界面上其它控件不受影响;
但是,这样设置会对其挂载在本控件上的子控件们产生影响;
eg: 给一控件设置样式,其挂载在当前控件上面的子控件也会收到影响:
-
设置界面
-
通过Widget设置样式
-
运行结果
当然:
- 如果父控件通过QSS设置样式过后,其挂载的子控件也使用了QSS来设置自己的样式,那么这时候子控件的样式设置以自己的为准;
- 对于一个控件来说,通过QSS设置的样式优先级高于通过代码设置的;
eg:
全局样式设置
向上面那样一个一个的指定每个控件的样式,得累死,并且一旦控件多起来,那么我们就可能在代码的任意地方都设置QSS,不方便统一管理,秉持着“高内聚,低耦合”的观念,我们建议将QSS放在一处设置,这样方便管理;
全局样式设置:
通过QApplication的setStyleSheet成员函数来设置整个程序的全局样式;
全局样式优点:
- 是同一个样式针对多个控件生效,代码更加简洁;
- 所有控件样式内聚在一起,便于维护和排查问题;
样式的层叠特性:
就比如说我们通过全局样式给按钮控件们设置了颜色为绿色,随后我们希望单独在调整一下按钮2的字体大小,于是我们又单独通过按钮2的setStyleSheet函数来设置QSS样式改变按钮2的字体大小为50像素,最终按钮2呈现出来的样式就是,字体为绿色,字体大小为50像素的情况,像这样,对于按钮2来说,它即继承了全局样式的文本颜色属性,也复用了自己样式的字体大小属性,这样两个样式属性叠加起来现象就叫样式的层叠属性;
eg:
运行结果:
当然,如果控件本地样式和全局样式冲突了,那么本地样式优先;
从文件加载样式表
上面两种样式设置方式,都是将样式表和代码融合在一起了,在后期代码量打起来过后就会变得越来越不好维护,因此更好的做法是将样式单独放在一个文件中,然后从文件中读取样式表;
eg:
- 设计ui界面
- 创建.qss文件,并续写QSS样式
- 为了避免路径问题,我们将style.qss文件采用qrc机制,导入到程序中
- 采用全局样式
- 最终运行结果
使用Qt Designer来编辑QSS
QSS 也可以通过 Qt Designer 直接编辑, 从⽽起到实时预览的效果. 同时也能避免 C++ 和 QSS 代码的耦合.
- 选中要设计的控件,然后鼠标右键,选中“改变样式表”
- 开始编辑QSS样式
- 效果实时展示
选择器
选择器 | 实例 | 说明 |
---|---|---|
全局选择器 | * | 选择所有的控件 |
类型选择器 | QPushButton 、QLabel等 | 选择QPushButton、QLabel及其子类实例(这里的子类是继承关系上的) |
类选择器 | .QPushButton | 选择所有的QPushButton控件,不考虑其子类的实例 |
ID选择器 | #objectName | 指定单独一个控件进行设置 |
后代选择器 | QDialog QPushButton | 选择 QDialog 的所有后代(⼦类控件, 孙⼦类控件等等)中的 QPushButton. |
⼦选择器 | QDialog > QPushButton | 选择 QDialog 的所有⼦类控件中的 QPushButton. |
并集选择器 | QPushButton, QLineEdit,QComboBox | 选择 QPushButton, QLineEdit, QComboBox 这三种控件.(即接下来的样式会针对这三种控件都⽣效). |
属性选择器 | QPushButton[flat=“false”] | 选择所有 QPushButton 中, flat 属性为 false 的控件. |
我们只需要记住几个常用的即可,不会的到时候查文档即可;
注意:
当某个控件⾝上, 通过类型选择器和 ID 选择器设置了冲突的样式时, ID 选择器样式优先级更
⾼.同理, 如果是其他的多种选择器作⽤同⼀个控件时出现冲突的样式, 也会涉及到优先级问题.
Qt ⽂档上有具体的优先级规则介绍 (参⻅ The Style Sheet Syntax 的 Conflict Resolution 章
节).这⾥的规则计算起来⾮常复杂(CSS 中也存在类似的设定), 咱们此处对于优先级不做进⼀步讨
论.实践中我们可以简单的认为, 选择器描述的范围越精准, 则优先级越⾼. ⼀般来说, ID 选择器优
先级是最⾼的.
子控件选择器
有些控件内部包含了多个“子控件”.比如QComboBox的下拉后的面板,还有QSpinBox的上下按钮等;
我们可以通过子控件选择器" :: " 针对上述子控件进行样式设置;
哪些控件拥有哪些⼦控件, 参考⽂档 Qt Style Sheets Reference 中 List of Sub-Controls 章
节.
eg1: 设置下拉框的下拉箭头样式
- 通过Qt Designer设计一个下拉框,并放入几条数据
- 将下列图标元素,通过qrc当如程序
- 编写核心代码
- 运行结果
伪类选择器
伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输⼊框获取到焦点, ⿏标移动到某个控件上等.
- 当状态具备时, 控件被选中, 样式⽣效.
- 当状态不具备时, 控件不被选中, 样式失效.
使用":" 的方式来定义伪类选择器;
以下是一些伪类选择器:
这些状态可以使⽤ ! 来取反. ⽐如 :!hover 就是⿏标离开控件时, :!pressed 就是⿏标松开时,
等等.
需要的时候,去查Qt文档即可
参考 Qt Style Sheets Reference 的 Pseudo-States 章节.
eg: 当鼠标悬停在按钮上面时,就改变按钮上文本的颜色;
核心代码:
通过Qt Designer来设计QSS
运行结果:
样式属性
QSS 中的样式属性⾮常多, 不需要都记住. 核⼼原则还是⽤到了就去查.
⼤部分的属性和 CSS 是⾮常相似的.
参考Qt Style Sheets Reference::List of Properties章节
BoxModel(盒模型)
一个遵循盒模型的控件,由上述几个部分构成:
- Content矩形区域: 存放控件内容;eg: 文本、图标;
- Padding矩形区域: 内边距;内容和边框的距离;
- Border矩形区域: 控件的边框区域
- Margin矩形区域: 外边距;边框到控件 geometry 返回的矩形边界的距离
可以通过一些QSS属性来设置上述的边距和边距样式;
QSS属性 | 说明 |
---|---|
margin | 设置四个⽅向的外边距. 复合属性. |
padding | 设置四个⽅向的内边距. 复合属性. |
border-style | 设置边框样式 |
border-width | 边框的粗细 |
border-color | 边框的颜⾊ |
border | 复合属性, 相当于 border-width+border-style + border-color |
eg1: 设置边框和内边距
- 在界面上创建一个Label
- 通过全局样式来设计
- 运行结果
控件样式示例
按钮
经过QSS样式调整:
QPushButton{
font-size:20px;
border: 2px solid green;
border-radius: 15px;
background-color: rgb(133, 229, 255);
}
属性解释:
- font-size: 字体大小
- border-radius: 圆角矩形,数值越大,角就越圆;
- backgroung-color: 背景色;
复选框
eg:
- 默认情况下(未选中)使用:
- 默认情况下(选中):
- 鼠标放上去(未选中):
- 鼠标放上去(选中):
- 鼠标点击(未选中):
- 鼠标点击选中:
QSS代码:
QCheckBox::indicator {
width:40px;
height:40px;
}
QCheckBox::indicator:unchecked{
image: url(:/hu.png);
}
QCheckBox::indicator::checked{
image: url(:/hz.png);
}
QCheckBox::indicator:unchecked:hover{
image: url(:/lu.png);
}
QCheckBox::indicator:checked:hover{
image: url(:/lz.png);
}
QCheckBox::indicator:unchecked:pressed{
image: url(:/gu.png);
}
QCheckBox::indicator:checked:pressed{
image: url(:/gz.png);
}
运行结果: