目录
- 背景介绍
- 基本语法
- [QSS 设置方式](#QSS 设置方式)
- 选择器
-
- 类型选择器
- 类选择器
- [ID 选择器](#ID 选择器)
- 并集选择器
- 子控件选择器 (Sub-Controls)
- 伪类选择器 (Pseudo-States)
- 样式属性
- 控件样式示例
背景介绍
在网页前端开发领域中, CSS 是⼀个至关重要的部分. 描述了⼀个网页的 "样式". 从而起到对网页美化的作用。
所谓样式, 包括不限于大小, 位置, 颜色, 背景, 间距, 字体等等。
网页开发作为 GUI 的典型代表, 也对于其他客户端 GUI 开发产生了影响. Qt 也是其中之⼀。
Qt 仿照 CSS 的模式, 引入了 QSS, 来对 Qt 中的控件做出样式上的设定, 从而允许程序猿写出界面更好看的代码。
同样受到 HTML 的影响, Qt 还引入了
QML来描述界面, 甚至还可以直接把⼀个原生的 html 页面加载到界面上。
当然, 由于 Qt 本身的设计理念和网页前端还是存在⼀定差异的, 因此 QSS 中只能支持部分 CSS 属性.整体来说 QSS 要比 CSS 更简单⼀些。
注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突, 则 QSS 优先级更高。
基本语法
对于 QSS 来说, 基本的语法结构非常简单。
选择器 {
属性名: 属性值;
}
其中:
- 选择器描述了 "哪个 widget 要应用样式规则"
- 属性则是⼀个键值对, 属性名表示要设置哪种样式, 属性值表示了设置的样式的值
QSS 设置方式
指定控件样式设置
QWidget 中包含了 setStyleSheet 方法, 可以直接设置样式。
案例:给按钮设置字体颜色
c
ui->pushButton->setStyleSheet("QPushButton {color: green}");

注意:如果我们给当前控件设置了样式,那么该控件的子空间也会继承该样式。
案例:给Widget设置样式,界面中的按钮控件(父元素是Widget)也会被设置样式。
c
this->setStyleSheet("QWidget{ color: red; }");//给Widget控件设置字体颜色为红色

全局样式设置
还可以通过 QApplication 的 setStyleSheet 方法设置整个程序的全局样式。
全局样式优点:
- 使同⼀个样式针对多个控件生效, 代码更简洁.
- 所有控件样式内聚在⼀起, 便于维护和问题排查.
案例:给所有按钮添加字体颜色
//main.cpp中
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet("QPushButton{color:red;}");
Widget w;
w.show();
return a.exec();
}
运行程序, 可以看到此时三个按钮的颜色都设置为红色了。

注意:如果设置了全局样式,又在某一个控件里面设置了单独的样式,此时,这两方面的样式会叠加起来。如果设置了全局样式,某一个控件的样式和全局样式产生了冲突,此时控件的样式优先级更高。
从文件加载样式表
上述代码都是把样式通过硬编码的方式设置的. 这样使 QSS 代码和 C++ 代码耦合在⼀起了, 并不方便代码的维护.因此更好的做法是把样式放到单独的文件中, 然后通过读取文件的方式来加载样式 。
案例:从文件中加载全局样式。
(1)自己手动创建qss文件,QT creator并没有提供。

(2)创建 resource.qrc 文件, 并设定前缀为 / ,并添加resource.qss文件

(3) 使用Qt Creator 打开 resource.qss , 编写内容

(4) 修改 main.cpp, 新增⼀个函数用来加载样式
c
QString loadQss()
{
//创建QFile对象
QFile file(":/resource.qss");
//打开文件
file.open(QFile::ReadOnly);
if(!file.isOpen())
{
qDebug()<<"文件打开失败";
exit(1);
}
QString style = file.readAll();
//关闭文件
file.close();
return style;
}
(5)修改 main.cpp, 在 main 函数中调用上述函数, 并设置样式
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet(loadQss());
Widget w;
w.show();
return a.exec();
}
(6)运行程序,和设置全局样式一样,三个按钮的字体颜色都是红色

使用 Qt Designer 编辑样式
QSS 也可以通过 Qt Designer 直接编辑, 从而起到实时预览的效果. 同时也能避免 C++ 和QSS 代码的耦合。
案例:改变字体大小
(1)选中控件,点击鼠标右键,选择样式表。

通过这里就可以编写QSS样式了,在这里的修改会被编辑到ui文件中,程序运行时自动生效,而且这里还能进行实时预览。
(2)设置字体大小样式样式

(3)运行程序,看效果。

(4)这种方式设置样式, 样式内容会被以 xml 格式记录到 ui 文件中。

同时在控件的 styleSheet 属性中也会体现
样式设置有很对方法,但是如果最终效果不是我们想要的,我们可以从以下几个思考方向去查找问题所在。
- 全局样式
- 指定控件的样式
- qss文件样式
- ui文件中的样式
...
选择器
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 的控件。 |
| 总体来说, QSS 选择器的规则和 CSS 选择器基本⼀致. |
类型选择器
使用类型选择器时,子列的样式也会改变。
案例:通过修改QWidget样式,来修改子类的样式。
(1)创建一个按钮

(2)给QWidget设置全局样式,修改字体颜色为红色
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet("QWidget{color:red}");
Widget w;
w.show();
return a.exec();
}
(3)运行程序,QWidget按钮的背景颜色变成了红色

类选择器
在上述案例中,如果我们将类型选择器修改为类选择器,就不会影响到子类的样式了。
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet(".QWidget{color:red}");
Widget w;
w.show();
return a.exec();
}
此时按钮的颜色不会发生改变. 此时只是选择 QWidget 类, 而不会选择 QWidget 的子类
QPushButton了.

ID 选择器
ID选择器可以只针对一个控件来进行样式设置。
案例:三个按钮中,使用ID选择器来设置一个按钮的样式。
(1)创建三个按钮

(2)使用一个类型选择器设置按钮的字体颜色为红色
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "QPushButton{color:red;}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
(3)使用id选择器设置一个按钮的字体颜色为绿色,id就是控件的objectName

c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "QPushButton{color:red;}";
style += "#pushButton{color:green;}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
(4)程序运行结果

- 当某个控件同时被类型选择器和 ID 选择器设置了冲突样式时,ID 选择器的样式优先级更高。类似地,当多个不同类型的选择器作用于同一个控件并发生样式冲突时,也会涉及优先级问题。
- Qt 官方文档中有关于优先级规则的具体说明(参见 The Style Sheet Syntax 中的 Conflict Resolution 章节),但这些规则计算起来非常复杂(类似于 CSS 中的优先级机制)。
- 实践中可以简单理解为:选择器描述的范围越精准,其优先级越高。一般来说,ID 选择器的优先级是最高的。
并集选择器
每个逗号前的部分都是一个完整的、独立的选择器,它们可以是类型选择器、类选择器、ID选择器等。每个选择器独立地在控件树上进行匹配。
案例:通过Label、Line Text、PushButton三个控件来演示并集选择器的效果
(1)创建三个控件

(2)通过设置全局样式来修改字体颜色
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "QPushButton,QLabel,QLineEdit{color:red;}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
(3)程序运行结果

并集选择器是⼀种很好的代码复用的方式. 很多时候我们希望界面上的多个元素风格是统⼀
的, 就可以使用并集选择器, 把样式属性同时指定给多种控件。
子控件选择器 (Sub-Controls)
有些控件内部包含了多个 "子控件" . 比如 QComboBox 的下拉后的⾯板, 比如 QSpinBox 的上下按钮等。可以通过子控件选择器 :: , 针对上述子控件进行样式设置.
哪些控件拥有哪些⼦控件, 参考⽂档
Qt Style Sheets Reference中List of Sub-Controls章节
案例:调整下拉框的子控件
(1)创建Combo Box控件

(2)添加图片到resource.qrc文件中

(3)修改Combo Box子控件图片样式

c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "QComboBox::down-arrow{image:url(:/down.png);}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
(4)显示效果

伪类选择器 (Pseudo-States)
伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输入框获取到焦点, 鼠标移动到某个控件上等。
- 当状态具备时, 控件被选中, 样式生效.
- 当状态不具备时, 控件不被选中, 样式失效.

使用 : 的方式定义伪类选择器.
常用的伪类选择器
| 伪类选择器 | 说明 |
|---|---|
:hover |
鼠标放到控件上 |
:pressed |
鼠标左键按下时 |
:focus |
获取输入焦点时 |
:enabled |
元素处于可用状态时 |
:checked |
被勾选时 |
:read-only |
元素为只读状态时 |
这些状态可以使用! 来取反. 比如 :!hover 就是鼠标离开控件时, :!pressed 就是鼠标松开时,等等.
更多伪类选择器的详细情况, 参考
Qt Style Sheets Reference的Pseudo-States章节.
案例:对按钮控件的三种不同的状态进行样式设置。
(1)创建一个按钮控件

(2)设置全局样式,使用伪类选择器对鼠标按下press和鼠标悬停hover两种状态进行样式设置
c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "QPushButton{color:green}";//类型选择器
style += "QPushButton:hover{color:red}";
style += "QPushButton:pressed{color:blue}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
(3)效果展示

同样,上述代码也可以使用事件的方式来实现.
样式属性
QSS 中的样式属性非常多, 不需要都记住. 核心原则还是用到了就去查.
大部分的属性和 CSS 是非常相似的。
文档的
Qt Style Sheets Reference章节详细介绍了哪些控件可以设置属性, 每个控件都能设置哪些属性等。
盒模型 (Box Model)
在文档的 Customizing Qt Widgets Using Style Sheets 的 The Box Model 章节介绍了盒模型。

⼀个遵守盒模型的控件, 由上述几个部分构成:
• Content 矩形区域: 存放控件内容. 比如包含的⽂本/图标等.
• Border 矩形区域: 控件的边框.
• Padding 矩形区域: 内边距. 边框和内容之间的距离.
• Margin 矩形区域: 外边距. 边框到控件 geometry 返回的矩形边界的距离
默认情况下, 外边距, 内边距, 边框宽度都是 0.
可以通过一些 QSS 属性来设置上述的边距和边框的样式。
| QSS 属性 | 说明 |
|---|---|
margin |
设置四个方向的外边距。复合属性。 |
padding |
设置四个方向的内边距。复合属性。 |
border-style |
设置边框样式。 |
border-width |
边框的粗细。 |
border-color |
边框的颜色。 |
border |
复合属性,相当于 border-style + border-width + border-color。 |
案例1:设置边框和内边距
(1)创建一个标签

(2)通过样式表来修改内边距和边框
border:3px solid red等价于border-width:3px,border-style:solid,border-color:red;三个属性的简写形式.
padding-left: 5px; 是给左侧设置内边距.

(3)运行程序,可以看出边框为红色,字体和边框之间的距离就是内边距

案例2:设置外边框
(1)创建一个按钮控件
(2)设置按钮位置,方便看出区别,添加外边框样式
c
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置按钮位置
ui->pushButton->setGeometry(0,0,100,100);
//设置外边框
ui->pushButton->setStyleSheet("QPushButton{border:5px solid red;margin:20px}");
qDebug()<<ui->pushButton->geometry();
}
(3)运行程序, 可以看到, 当前按钮的边框被外边距挤的缩小了. 但是获取到的按钮的Geometry 是不变的.

控件样式示例
案例:自定义按钮
(1)创建按钮控件

(2)修改样式表

(3)结果展示

属性值小结
| 属性 | 说明 |
|---|---|
font-size |
设置文字大小。 |
border-radius |
设置圆角矩形。数值越大,角越"圆"。 |
background-color |
设置背景颜色。 |
