【QT】使用QSS进行界面美化
文章目录
- 1. QSS
- 1.1 基本语法
- 1.2 设置方式
- 1.2.1 指定控件样式设置
- 1.2.2 全局样式设置
- 1.2.3 从文件加载样式表
- 1.2.4 使用 Qt Designer 编辑样式
- 2. 选择器
- 2.1 类型与类选择器
- 2.2 id选择器
- 2.3 并集选择器
- 2.4 子控件选择器
- 2.5 伪类选择器
- 3. 样式属性
- 3.1 盒模型
- 3.2 控件常用样式
- 4. 绘图
- 4.1 绘制形状
- 4.2 绘制文本
- 4.3 绘制图片

1. QSS
在网页前端开发领域中,CSS 是⼀个⾄关重要的部分. 描述了⼀个网页的 “样式”,从而起到对网页美化的作用.
所谓样式, 包括不限于大小、位置、颜⾊、背景、间距、字体等等.
网页开发作为 GUI 的典型代表,也对于其他客⼾端 GUI 开发产⽣了影响,Qt 也是其中之⼀.
1.1 基本语法
Qt 仿照 CSS 的模式,引⼊了 QSS,来对 Qt 中的控件做出样式上的设定,从而允许程序猿写出界⾯更好看的代码
由于 Qt 本身的设计理念和网页前端还是存在⼀定差异的,因此 QSS 中只能⽀持部分 CSS 属性;整体来说 QSS 要比 CSS 更简单⼀些
注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突,则 QSS 优先级更⾼
对于 CSS 来说, 基本的语法结构⾮常简单.
选择器 {属性名: 属性值;
}
QSS 沿⽤了这样的设定.
选择器 {属性名: 属性值;
}
- 选择器 描述了 “哪个 widget 要应用样式规则”
- 属性 则是⼀个键值对,属性名表⽰要设置哪种样式,属性值表⽰了设置的样式的值.
QPushButton {color: red;
}
上述代码的含义表示,针对界⾯上所有的 QPushButton,都把文本颜色设置为红色
1.2 设置方式
1.2.1 指定控件样式设置
QWidget 中包含了 setStyleSheet 方法,可以直接设置样式.
给指定控件设置样式之后,该控件的子元素也会受到影响.
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 给 Widget 本⾝设置样式.//样式对于子控件同样生效this->setStyleSheet("QPushButton { color: red;} ");//ui->pushButton->setStyleSheet("QPushButton { color: red; }");
}
1.2.2 全局样式设置
还可以通过 QApplication
的 setStyleSheet
⽅法设置整个程序的全局样式.
全局样式优点:
- 使同⼀个样式针对多个控件⽣效,代码更简洁.
- 所有控件样式内聚在⼀起,便于维护和问题排查.
在 CSS 中也存在类似的优先级规则,通常来说都是 “局部” 优先级⾼于 “全局” 优先级; 相当于全局样式先 “奠定基调” ,再通过指定控件样式来 “特事特办”
对于第⼀个按钮来说,由于局部样式的存在,它的颜色为绿色;对于第二个按钮,两种设置方式设置的样式,叠加起来了,形如上述这种属性叠加的效果,我们称为 “层叠性”.
1.2.3 从文件加载样式表
上述代码都是把样式通过硬编码的方式设置的,这样使 QSS 代码和 C++ 代码耦合在⼀起了,并不方便代码的维护,因此更好的做法是把样式放到单独的文件中,然后通过读取文件的方式来加载样式。
创建 style.qss 文件,并添加到 resource.qrc 中.
- style.qss 是需要程序运⾏时加载的,为了规避绝对路径的问题,仍然使用 qrc 的⽅式来组织 (即把资源⽂件内容打包到 cpp 代码中).
- Qt Creator 没有提供创建 qss 文件的选项,咱们直接 右键 -> 新建⽂件 -> ⼿动设置⽂件扩展名为 qss 即可.
1.2.4 使用 Qt Designer 编辑样式
QSS 也可以通过 Qt Designer 直接编辑,从而起到实时预览的效果. 同时也能避免 C++ 和 QSS 代码的耦合.
此时 Qt Designer 的预览界⾯就会实时显示出样式的变化
当我们发现⼀个控件的样式不符合预期的时候, 要记得排查这四个地⽅:
- 全局样式
- 指定控件样式
- qss ⽂件中的样式
- ui ⽂件中的样式
2. 选择器
QSS 的选择器支持以下几种:
选择器 | 示例 | 说明 |
---|---|---|
全局选择器 | * | 选择所有的 widget. |
类型选择器 | QPushButton | 选择所有的 QPushButton 和 其⼦类 的控件 |
类选择器 | .QPushButton | 选择所有的 QPushButton 的控件,不会选择⼦类. |
ID 选择器 | #pushButton_2 | 选择 objectName 为 pushButton_2 的控件 |
后代选择器 | QDialog QPushButton | 选择 QDialog 的所有后代(⼦控件, 孙⼦控件等等) 中的 QPushButton |
⼦选择器 | QDialog > QPushButton | 选择 QDialog 的所有⼦控件中的 QPushButton. |
并集选择器 | QPushButton, QLineEdit, QComboBox | QPushButton, QLineEdit, QComboBox |
属性选择器 | QPushButton[flat=“false”] | 选择所有 QPushButton 中,flat 属性为 false 的控件. |
2.1 类型与类选择器
int main(int argc, char *argv[])
{QApplication a(argc, argv);//类型选择器,设置全局样式a.setStyleSheet("QWidget { color: red; }");//类选择器//只是选择 QWidget类, ⽽不会选择QWidget 的⼦类 QPushButton了a.setStyleSheet(".QWidget { color: green; }");Widget w;w.show();return a.exec();
}
2.2 id选择器
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 设置全局样式QString style = "";//类型选择器style += "QPushButton { color: yellow; }";//ID选择器style += "#pushButton { color: red; }";style += "#pushButton_2 { color: green; }";a.setStyleSheet(style);Widget w;w.show();return a.exec();
}
当某个控件身上,通过类型选择器和 ID 选择器设置了冲突的样式时,ID 选择器样式优先级更⾼.
同理,如果是其他的多种选择器作⽤同⼀个控件时出现冲突的样式,也会涉及到优先级问题.
实践中我们可以简单的认为,选择器描述的范围越精准,则优先级越⾼,⼀般来说,ID 选择器优先级是最⾼的.
2.3 并集选择器
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 设置全局样式a.setStyleSheet("QPushButton, QLabel, QLineEdit { color: red; } ");Widget w;w.show();return a.exec();
}
运行程序,可以看到这三种控件的文字颜⾊都设置为了红色
并集选择器是⼀种很好的代码复用的⽅式,很多时候我们希望界⾯上的多个元素⻛格是统⼀的,就可以使⽤并集选择器,把样式属性同时指定给多种控件
2.4 子控件选择器
有些控件内部包含了多个 “子控件” ,比如 QComboBox 的下拉后的⾯板,⽐如 QSpinBox 的上下按钮等
可以通过子控件选择器 ::
,针对上述⼦控件进⾏样式设置.
也可直接在Qt Designer中右侧的属性编辑器设置
2.5 伪类选择器
伪类选择器,是根据控件所处的某个状态被选择的,例如按钮被按下,输⼊框获取到焦点,⿏标移动到某个控件上等.
- 当状态具备时,控件被选中,样式⽣效.
- 当状态不具备时,控件不被选中,样式失效.
使⽤ :
的方式定义伪类选择器
常用的伪类选择器
伪类选择器 | 说明 |
---|---|
:hover | ⿏标放到控件上 |
:pressed | ⿏标左键按下时 |
:focus | 获取输⼊焦点时 |
:enabled | 元素处于可⽤状态时 |
:checked | 被勾选时 |
:read-only | 元素为只读状态时 |
这些状态可以使⽤ ! 来取反. ⽐如 :!hover
就是⿏标离开控件时, :!pressed
就是鼠标松开时, 等等.
int main(int argc, char *argv[])
{QApplication a(argc, argv);QString style = "";style += "QPushButton { color: red; }";style += "QPushButton:hover { color: green; }";style += "QPushButton:pressed { color: blue; }";a.setStyleSheet(style);Widget w;w.show();return a.exec();
}
可以看到,默认情况下按钮⽂字是红⾊,⿏标移动上去是绿⾊,⿏标按下按钮是蓝⾊.
3. 样式属性
3.1 盒模型
⼀个遵守盒模型的控件,由上述几个部分构成
- Content 矩形区域:存放控件内容,比如包含的文本/图标等.
- Border 矩形区域: 控件的边框.
- Padding 矩形区域: 内边距,边框和内容之间的距离.
- Margin 矩形区域: 外边距,边框到控件 geometry 返回的矩形边界的距离
默认情况下,外边距、内边距、边框宽度都是 0
可以通过⼀些 QSS 属性来设置上述的边距和边框的样式
QSS 属性 | 说明 |
---|---|
margin | 设置四个⽅向的外边距,复合属性. |
padding | 设置四个⽅向的内边距. 复合属性. |
border-style | 设置边框样式 |
border-width | 边框的粗细 |
border-color | 边框的颜⾊ |
border | 复合属性,相当于 border-style + border-width + border-color |
下面,我们来设置一下边框样式与内边距
其中,border:5px solid red
,相当于 border-width: 5px; border-style: solid; border-color: red;
(一般按照 宽度 → 样式 → 颜色的顺序书写,其它方式可能会解析失败)
再来设置一下外边距
其中,margin的可以写多个,顺序是:
上-> 右 -> 下-> 左
3.2 控件常用样式
下⾯,我们给出⼀些常用控件的样式示例
- 按钮
- 复选框
使用蓝色作为默认形态.
使用绿色作为 hover 形态.
使用红色作为 pressed 形态.
单选框也是如此,这里就不演示了
要点 | 说明 |
---|---|
::indicator | ⼦控件选择器. 选中 checkbox 中的对钩部分 |
width | 设置⼦控件宽度,对于普通控件⽆效 (普通控件使⽤ geometry ⽅式设定尺⼨). |
height | 设置⼦控件⾼度. 对于普通控件⽆效 |
image | 设置⼦控件的图⽚. |
- 输入框
属性 | 说明 |
---|---|
border-width | 设置边框宽度. |
border-radius | 设置边框圆⻆ |
border-color | 设置边框颜⾊ |
border-style | 设置边框⻛格. |
color | 设置⽂字颜⾊. |
background | 设置背景颜⾊. |
selection-background-color | 设置选中⽂字的背景颜⾊ |
selection-color | 设置选中⽂字的⽂本颜⾊… |
关于颜色,其中有一个属性
qlineargradient
qlineargradient 有 6 个参数:
- x1, y1: 标注了⼀个起点,
- x2, y2: 标注了⼀个终点,这两个点描述了⼀个 “方向”,例如:
- x1: 0, y1: 0, x2: 0, y2: 1 就是垂直⽅向从上向下 进⾏颜⾊渐变.
- x1: 0, y1: 0, x2: 1, y2: 0 就是⽔平⽅向从左向右 进⾏颜⾊渐变.
- x1: 0, y1: 0, x2: 1, y2: 1 就是从左上往右下⽅向 进⾏颜⾊渐变.
- stop0 和 stop1 描述了两个颜⾊. 渐变过程就是从 stop0 往 stop1 进⾏渐变的.
- 菜单栏
对于菜单栏而言,它可以分为菜单栏与菜单项,它们各自有不同的样式:
属性 | 说明 |
---|---|
QMenuBar::item | 选中菜单栏中的元素 |
QMenuBar::item:selected | 选中菜单来中的被选中的元素. |
QMenuBar::item:pressed | 选中菜单栏中的⿏标点击的元素. |
QMenu::item | 选中菜单中的元素 |
QMenu::item:selected | 选中菜单中的被选中的元素. |
QMenu::separator | 选中菜单中的分割线. |
下面,我们就做一个样式稍微综合一点的案例:登录界面
首先,我们先使用Qt Designer拖拽出来几个控件,然后使用布局布局管理器来设置一下
由于顶层窗⼝的 QWidget ⽆法设置背景图⽚, 因此我们需要再套上⼀层 QFrame,背景图⽚就可以设置到 QFrame 上即可
设置背景图片,出来使用background-image之外,还有一个border-image,其中,border-image
设置的背景,会随着控件的大小而改变
QSS 本⾝给 Qt 提供了更丰富的样式设置的能力,但是整体来说 QSS 的功能是不如 CSS 的,在 CSS 中,整个网页的样式,都是 CSS ⼀手负责,CSS 功能更强大,并且也更可控。
相比之下,Qt 中是以原⽣ api 为主,来控制控件之间的尺⼨、位置等,QSS 只是起到辅助的作⽤;⽽且 Qt 中提供的⼀些 “组合控件” (像 QComboBox, QSpinBox 等) 内部的结构是不透明的,此时进⾏⼀些样式设置也会存在⼀定的局限性
4. 绘图
虽然 Qt 已经内置了很多的控件,但是不能保证现有控件就可以应对所有场景,很多时候我们需要更强的 “⾃定制” 能力。
Qt 提供了画图相关的 API,可以允许我们在窗⼝上绘制任意的图形形状,来完成更复杂的界⾯设计.
所谓的 “控件” ,本质上也是通过画图的⽅式画上去的,画图 API 和控件之间的关系,可以类⽐成机器指令和⾼级语⾔之间的关系。
控件是对画图 API 的进⼀步封装,画图 API 是控件的底层实现.
绘图 API 核⼼类
类 | 说明 |
---|---|
QPainter | ⽤来绘图的对象,提供了⼀系列 drawXXX ⽅法,可以允许我们绘制各种图形. |
QPaintDevice | 描述了 QPainter 把图形画到哪个对象上。像咱们之前⽤过的 QWidget 也是⼀种 QPaintDevice (QWidget 是 QPaintDevice 的⼦类) . |
QPen | 描述了 QPainter 画出来的线是什么样的 |
QBrush | 描述了 QPainter 填充⼀个区域是什么样的. |
绘图 API 的使用,⼀般不会在 QWidget 的构造函数中使用,而是要放到 paintEvent 事件中.
paintEvent 会在以下情况下被触发:
- 控件⾸次创建.
- 控件被遮挡,再解除遮挡.
- 窗口最小化,再恢复.
- 窗口最小化,再恢复.
- 控件大小发⽣变化时.
- 主动调⽤ repaint() 或者 update() ⽅法(这两个⽅法都是 QWidget 的⽅法).
4.1 绘制形状
- 线段
//参数:
//p1:绘制起点坐标
//p2:绘制终点坐标
void drawLine(const QPoint &p1, const QPoint &p2);
- 矩形
//参数:
//x:窗⼝横坐标;
//y:窗⼝纵坐标;
//width:所绘制矩形的宽度;
//height:所绘制矩形的⾼度;
void QPainter::drawRect(int x, int y, int width, int height);
- 圆
//参数:
//center:中⼼点坐标
//rx:横坐标
//ry:纵坐标
void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
4.2 绘制文本
- 文本
QPainter类 中不仅提供了绘制图形的功能,还可以使用 QPainter::drawText()
函数来绘制⽂字,也可以使用QPainter::setFont()
设置字体等信息
- 画笔
QPainter 在绘制时,是有⼀个默认的画笔的。在使⽤时也可以⾃定义画笔,在 Qt 中,QPen类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen类 可以设置画笔的线宽、颜⾊、样式、画刷等。
画笔的颜⾊可以在实例化画笔对象时进⾏设置,画笔的宽度是通过 setWidth()
方法进⾏设置,画笔的风格是通过setStyle()
方法进行设置,设置画刷主要是通过 setBrush()
⽅法。
- 设置画笔颜⾊:QPen::QPen(const QColor &color)
- 设置画笔宽度:void QPen::setWidth(int width)
- 设置画笔风格:void QPen::setStyle(Qt::PenStyle style)
其中,画笔的风格如下:
- 画刷
画刷是使用 QBrush类 来描述,画刷大多用于填充。QBrush定义了QPainter的填充模式,具有样式、颜⾊、渐变以及纹理等属性。
画刷的格式中定义了填充的样式,使⽤ Qt::BrushStyle
枚举,默认值是 Qt::NoBrush,也就是不进⾏任何填充
4.3 绘制图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture,它们都是常⽤的绘图设备。
- QImage主要⽤来进⾏ I/O 处理,它对 I/O 处理操作进⾏了优化,⽽且可以⽤来直接访问和操作像素;
- QPixmap 主要⽤来在屏幕上显⽰图像,它对在屏幕上显⽰图像进⾏了优化;
- QBitmap 是 QPixmap 的子类,用来处理颜⾊深度为1的图像,即只能显示黑白两种颜⾊;
- QPicture ⽤来记录并重演 QPainter 命令。
下面我们来简单使用一下QPixmap:
- 平移图片
平移图片实际是通过改变坐标来实现。QPainter类中提供了 translate()
函数 来实现坐标原点的改变
关于绘制图片,还有很多很多的设置,我们这里就不赘述了。
- 旋转图⽚
- 移动画家位置
- 保存/加载画家的状态
前⾯的代码中我们是使⽤ QWidget 作为绘图设备,在 Qt 中还存在下列三个⽐较特殊的绘图设备
- QPixmap
QPixmap 核心特性:
- 使⽤ QPainter 直接在上⾯进⾏绘制图形.
- 通过⽂件路径加载并显⽰图⽚.
- 搭配 QPainter 的 drawPixmap()函数, 可以把这个图⽚绘制到⼀个 QLabel、QPushButton 等控件上.
- 和系统/显⽰设备强相关, 不同系统/显⽰设备下, QPixmap 的显⽰可能会有所差别
- QImage
QImage 的核心特性:
- 使⽤ QPainter 直接在上⾯进⾏绘制图形.
- 通过⽂件路径保存/加载图⽚.
- 能够针对图⽚进⾏像素级别的操作(操作某个指定的像素).
- 独⽴于硬件的绘制系统, 能够在不同系统之上提供⼀致的显⽰.
- QPicture
QPicture 核⼼特性:
- 使⽤ QPainter 直接在上⾯进⾏绘制图形.
- 通过⽂件路径加载并显⽰图⽚.
- 能够记录 QPainter 的操作步骤.
- 独⽴于硬件的绘制系统, 能够在不同系统之上提供⼀致的显⽰.