📑 目录
- [📌 1. 引言](#📌 1. 引言)
- [🎨 2. QSS 详解](#🎨 2. QSS 详解)
- [2.1 背景介绍](#2.1 背景介绍)
- [2.2 基本语法](#2.2 基本语法)
- [2.3 QSS 设置方式](#2.3 QSS 设置方式)
- [2.3.1 指定控件样式设置](#2.3.1 指定控件样式设置)
- [2.3.2 全局样式设置](#2.3.2 全局样式设置)
- [2.3.3 从文件加载样式表](#2.3.3 从文件加载样式表)
- [2.3.4 使用 Qt Designer 编辑样式](#2.3.4 使用 Qt Designer 编辑样式)
- [2.4 选择器](#2.4 选择器)
- [2.4.1 选择器概况](#2.4.1 选择器概况)
- [2.4.2 子控件选择器 (Sub-Controls)](#2.4.2 子控件选择器 (Sub-Controls))
- [2.4.3 伪类选择器 (Pseudo-States)](#2.4.3 伪类选择器 (Pseudo-States))
- [2.5 样式属性](#2.5 样式属性)
- [2.5.1 盒模型 (Box Model)](#2.5.1 盒模型 (Box Model))
- [2.6 控件样式示例](#2.6 控件样式示例)
- [2.6.1 按钮](#2.6.1 按钮)
- [2.6.2 复选框](#2.6.2 复选框)
- [2.6.4 输入框](#2.6.4 输入框)
- [2.6.5 列表](#2.6.5 列表)
- [2.6.6 菜单栏](#2.6.6 菜单栏)
- [🎯 3. 总结与经典面试题](#🎯 3. 总结与经典面试题)
- [3.1 本章总结](#3.1 本章总结)
- [3.2 经典面试题](#3.2 经典面试题)
📌 1. 引言
在 Qt 开发中,界面优化是提升用户体验的关键环节。本章将围绕两大核心主题展开:
- QSS(Qt Style Sheets):仿照 CSS 的模式,为 Qt 控件提供样式设定能力,让界面更美观。
- 绘图(QPainter):提供底层绘图 API,允许我们在窗口上绘制任意图形,实现更复杂的界面设计。
🎯 学习目标:掌握 QSS 的基本语法、设置方式、选择器与常用控件样式;理解 QPainter 绘图的核心概念与常见图形绘制方法,为后续开发美观、专业的 Qt 应用打下基础。
🎨 2. QSS 详解
2.1 背景介绍
在网页前端开发领域中,CSS 是一个至关重要的部分,它描述了一个网页的"样式",从而起到对网页美化的作用。
所谓样式,包括但不限于大小、位置、颜色、背景、间距、字体等等。
现在的网页很难找到没有 CSS 的,可以说让"界面好看"是一个刚需。
网页开发作为 GUI 的典型代表,也对于其他客户端 GUI 开发产生了影响,Qt 也是其中之一 。
Qt 仿照 CSS 的模式,引入了 QSS ,来对 Qt 中的控件做出样式上的设定,从而允许程序猿写出界面更好看的代码。
同样受到 HTML 的影响,Qt 还引入了 QML 来描述界面,甚至还可以直接把一个原生的 html 页面加载到界面上。这部分内容课堂上并不讨论。
当然,由于 Qt 本身的设计理念和网页前端还是存在一定差异的,因此 QSS 中只能支持部分 CSS 属性。整体来说 QSS 要比 CSS 更简单一些。
🌟 注意:
如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突,则 QSS 优先级更高。
2.2 基本语法
CSS的基本的语法结构比较简单:
css
选择器 {
属性名: 属性值;
}
QSS 沿用了这样的设定:
css
选择器 {
属性名: 属性值;
}
其中:
- 选择器 描述了"哪个 widget 要应用样式规则"。
- 属性 则是一个键值对,属性名表示要设置哪种样式,属性值表示了设置的样式的值。
例如:
css
QPushButton { color: red; }
或者:
css
QPushButton {
color: red;
}
上述代码的含义表示,针对界面上所有的 QPushButton,都把文本颜色设置为 红色,此处的QPushButton是类型选择器。
编写 QSS 时使用单行的格式和多行的格式均可。
📝 代码示例:QSS 基本使用
- 在界面上创建一个按钮。

- 编写代码,设置样式:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->pushButton->setStyleSheet("QPushButton { color: blue; }");
}
- 运行程序,观察效果。可以看到文本已经是蓝色了。

⚠️ 注意: 上述代码中,我们是只针对这一个按钮通过
setStyleSheet方法设置的样式。此时这个样式仅针对该按钮生效。如果创建其他按钮,其他按钮不会受到影响。
2.3 QSS 设置方式
2.3.1 指定控件样式设置
QWidget 中包含了 setStyleSheet 方法,可以直接设置样式。
另一方面,给指定控件设置样式之后,该控件的子元素也会受到影响。
📝 代码示例:子元素受到影响
- 在界面上创建一个按钮。
- 修改
widget.cpp,这次我们不再给按钮设置样式,而是给Widget设置样式(Widget是QPushButton的父控件):
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 给 Widget 本身设置样式
this->setStyleSheet("QPushButton { color: red;} ");
}
- 运行程序,可以看到样式对于子控件按钮同样会生效。

2.3.2 全局样式设置
还可以通过 QApplication 的 setStyleSheet 方法设置整个程序的全局样式。
全局样式优点:
- 使同一个样式针对多个控件生效,代码更简洁。
- 所有控件样式内聚在一起,便于维护和问题排查。
📝 代码示例:使用全局样式
- 在界面上创建三个按钮。

- 编辑
main.cpp,设置全局样式:
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: green; }");
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以看到此时三个按钮的颜色都设置为绿色了。

💡
a.setStyleSheet("QPushButton { color: green; }");既对全部的子控件有效,而且必须是相关的控件,比如QPushButton控件。
📝 代码示例:样式的层叠特性
如果通过全局样式给某个控件设置了属性1,通过指定控件样式给控件设置属性2,那么这两个属性都会产生作用。
- 在界面上创建两个按钮。
❓ 思考:
如果设置了全局样式,然后在某个控件中又设置了其他的样式,会咋样?
- 此时这两方面的样式会"叠加"起来 ------ 层叠性。
如果设置了全局样式,在某个控件中设置的样式和全局样式冲突了,又会咋样?
- 局部更加优先 ------ 即局部样式的优先级更高,覆盖了对应的全局样式。
💡 实际开发过程中,就可以在全局样式中设置比较通用的样式,统一整个程序的界面风格;如果需要对某个界面进行微调,可以使用局部样式来做出调整。
- 编写
main.cpp,设置全局样式,把按钮文本设置为粉色:
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: pink; }");
Widget w;
w.show();
return a.exec();
}
- 编写
widget.cpp,给第一个按钮设置字体大小:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置指定控件样式
ui->pushButton->setStyleSheet("QPushButton { font-size: 60px} ");
}
- 运行程序,可以看到,对于第一个按钮来说,同时具备了颜色和字体大小样式。而第二和第三个按钮只有颜色样式。

说明针对第一个按钮,两种设置方式设置的样式,叠加起来了。
🎹 形如上述这种属性叠加的效果,我们称为 "层叠性"。
CSS 全称为 Cascading Style Sheets,其中 Cascading 就是"层叠性"的意思。QSS 也继承了这样的设定。
📝 代码示例:样式的优先级
如果全局样式,和指定控件样式冲突,则指定控件样式优先展示。
- 在界面上创建两个按钮。

- 编辑
main.cpp,把全局样式设置为红色:
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: red; }");
Widget w;
w.show();
return a.exec();
}
- 编辑
widget.cpp,把第一个按钮样式设为绿色:
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置第一个按钮颜色为绿色
ui->pushButton->setStyleSheet("QPushButton { color: green; }");
}
- 运行程序,观察效果。可以看到第二个按钮已经成为绿色了,但是第一个按钮仍然是红色。

🌅 在 CSS 中也存在类似的优先级规则。通常来说都是 "局部"优先级高于"全局"优先级。
相当于全局样式先"奠定基调",再通过指定控件样式来"特事特办"。
2.3.3 从文件加载样式表
上述代码都是把样式通过硬编码的方式设置的。这样使 QSS 代码和 C++ 代码耦合在一起了,并不方便代码的维护。
因此更好的做法是把样式放到单独的文件中,然后通过读取文件的方式来加载样式。
📝 代码示例:从文件加载全局样式
💡 方案思路:
- 创建 qrc 文件,通过 qrc 文件来管理样式文件。
- 创建单独的 qss 文件,把这样的文件放到 qrc 文件中。
- 编写 C++ 代码,读取 qss 文件中的内容,并设置样式。
这个方案仅供参考,实际开发中可能还有更加方便的做法。
- 在界面上创建一个按钮。

-
创建
resource.qrc文件,并设定前缀为/。 -
创建
style.qss文件,并添加到resource.qrc中。
style.qss是需要程序运行时加载的。为了规避绝对路径的问题,仍然使用qrc的方式来组织(即把资源文件内容打包到 cpp 代码中)。- Qt Creator 没有提供创建
qss文件的选项。咱们直接右键 -> 新建文件 -> 手动设置文件扩展名为 qss 即可。
- 使用 Qt Creator 打开
style.qss,编写内容:
css
QPushBUtton{
color : red;
}
- 修改
main.cpp,新增一个函数用来加载样式:
cpp
QString loadQSS() {
QFile file(":/style.qss");
// 打开文件
file.open(QFile::ReadOnly);
// 读取文件内容。虽然 readAll 返回的是 QByteArray, 但是 QString 提供了 QByteArray 版本的构造函数。
QString style = file.readAll();
// 关闭文件
file.close();
return style;
}
- 修改
main.cpp,在main函数中调用上述函数,并设置样式:
cpp
#include "widget.h"
#include <QApplication>
#include<QFile>
QString loadQSS(){
QFile file(":/style.qss");
//读取文件内容,虽然readAll返回的是QByteArray,但是QString提供了QByteArray版本
//构造函数
QString style = file.readAll();
//关闭文件
file.close();
return style;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//调用loadQSS函数加载上述样式
const QString& style= loadQSS();
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以查看结果。

2.3.4 使用 Qt Designer 编辑样式
QSS 也可以通过 Qt Designer 直接编辑,从而起到实时预览的效果。同时也能避免 C++ 和 QSS 代码的耦合。
💡 更加方便的方式。
📝 代码示例:使用 Qt Designer 编辑样式
-
在界面上创建一个按钮。

-
右键按钮,选择 "改变样式表"。

- 在弹出的样式表编辑器中,可以直接填写样式。填填写完毕, 点击 OK 即可。

- 此时 Qt Designer 的预览界面就会实时显示出样式的变化。

这种方式设置样式,样式内容会被以 xml 格式记录到 ui 文件中:
xml
<property name="styleSheet">
<string notr="true">QPushButton{color:rgb(85, 255, 0);}</string>
</property>
同时在控件的 styleSheet 属性中也会体现。

⚠️ 注意: 由于设置样式太灵活,又很多地方都能设置,就导致当某个控件不符合预期的时候,排查起来就比较麻烦了。
- 全局样式(QApplication 设置的)
- 指定控件的样式(这个控件是否设置了样式)
- 指定控件的父控件(可能从父控件继承过来)
- qss 文件中的样式
- ui 文件中的样式
💡 在实际开发过程中,如果需要设置样式,建议最好统一使用某一种方式来设置。
2.4 选择器
2.4.1 选择器概况
QSS 的选择器支持以下几种:
| 选择器 | 示例 | 说明 |
|---|---|---|
| 全局选择器 | * |
选择所有的 widget。 |
| 类型选择器(type selector) | QPushButton |
选择所有的 QPushButton 和其子类的控件。 |
| 类选择器(class selector) | .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 选择器基本一致。上述选择器中只熟练使用最常用的几个即可(上述加粗的),其他的了解即可!
📝 代码示例:使用类型选择器选中子类控件
- 在界面上创建一个按钮。

- 修改
main.cpp,设置全局样式。

⚠️ 注意: 此处选择器使用的是
QWidget。QPushButton也是QWidget的子类,所以会受到QWidget选择器的影响。
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QWidget { color: red; }");
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以看到按钮的文本颜色已经是红色了。
💡 此时当类型选择器和 id 选择器选中同一个控件的时候,并且设置的样式是冲突的,此时,id 选择器的优先级更高。如果不冲突,这两种效果都会生效。
- 如果把上述样式代码修改为下列代码:
cpp
a.setStyleSheet(".QWidget { color: red; }");
此时按钮的颜色不会发生改变。此时只是选择 QWidget 类,而不会选择 QWidget 的子类 QPushButton 了。

📝 代码示例:使用 id 选择器
- 在界面上创建 3 个按钮,
objectName为pushButton、pushButton_2、pushButton_3。

- 编写
main.cpp,设置全局样式:
- 先通过
QPushButton设置所有的按钮为黄色。 - 再通过
#pushButton和#pushButton_2分别设置这两个按钮为红色和绿色。
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
QString style = "";
style += "QPushButton { color: red; }";
style += "#pushButton { color: green; }";
style += "#pushButton_2 { color: blue; }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 执行程序,观察效果。

📍 当某个控件身上,通过类型选择器和 ID 选择器设置了冲突的样式时,ID 选择器样式优先级更高。
同理,如果是其他的多种选择器作用同一个控件时出现冲突的样式,也会涉及到优先级问题。Qt 文档上有具体的优先级规则介绍(参见 The Style Sheet Syntax 的 Conflict Resolution 章节)。
这里的规则计算起来非常复杂(CSS 中也存在类似的设定),咱们此处对于优先级不做进一步讨论。
实践中我们可以简单的认为,选择器描述的范围越精准,则优先级越高。一般来说,ID 选择器优先级是最高的。
📝 代码示例:使用并集选择器
-
创建按钮、label、单行输入框。

-
编写
main.cpp,设置全局样式:
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton, QLabel, QLineEdit { color: red; } ");
Widget w;
w.show();
return a.exec();
}
- 运⾏程序, 可以看到这三种控件的⽂字颜⾊都设置为了红⾊

⛱ 并集选择器是一种很好的代码复用的方式。 很多时候我们希望多个不同类型的控件共享同一种样式,此时就可以使用并集选择器,把多个选择器用逗号分隔写在一起,从而避免重复编写相同的样式规则,让代码更加简洁、易于维护。
例如上面的例子中,
QPushButton、QLabel、QLineEdit三种控件都统一设置为红色文字,只需要写一条规则即可,而不需要分别给每种控件单独设置样式。
1.4.2 ⼦控件选择器 (Sub-Controls)
有些控件内部包含了多个 "⼦控件" . ⽐如QComboBox的下拉后的⾯板, ⽐如QSpinBox 的上下按钮等.
可以通过⼦控件选择器::, 针对上述⼦控件进⾏样式设置.
📝 代码示例:设置下拉框的下拉按钮样式
- 在界⾯上创建⼀个下拉框, 并创建⼏个选项
- 创建
resource.qrc, 并导⼊图⽚down.svg

- 修改
main.cpp, 编写全局样式
- 使⽤⼦控件选择器
QComboBox::down-arrow选中了QComboBox的下拉按钮. - 再通过
image属性设置图⽚.
cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "";
style += "QComboBox::down-arrow {image:url(:/down.svg)}";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 执⾏程序, 观察效果

📝 代码示例: 修改进度条的颜⾊
- 在界⾯上创建⼀个进度条.

- 在 Qt Designer 右侧的属性编辑器中, 找到
QWidget的styleSheet属性.
编辑如下内容:
• 其中的chunk是选中进度条中的每个 "块" . 使⽤QProgressBar::text则可以选中⽂本.
QProgressBar::chunk {background-color: #FF0000;}同时把
QProcessBar的alignment属性设置为垂直⽔平居中.
- 执⾏程序, 可以看到如下效果. 我们就得到了⼀个红⾊的进度条.

通过上述⽅式, 也可以修改⽂字的颜⾊, 字体⼤⼩等样式
2.4.3 伪类选择器 (Pseudo-States)
伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输⼊框获取到焦点, ⿏标移动到某个控件上等.
• 当状态具备时, 控件被选中, 样式⽣效.
• 当状态不具备时, 控件不被选中, 样常用的伪类选择器:
常⽤的伪类选择器
| 伪类选择器 | 说明 |
|---|---|
:hover |
鼠标放到控件上时 |
:pressed |
鼠标左键按下时 |
:focus |
获取输入焦点时 |
:enabled |
元素处于可用状态时 |
:checked |
被勾选时 |
:read-only |
元素为只读状态时 |
这些状态可以使⽤ !来取反. ⽐如 :!hover 就是⿏标离开控件时, :!pressed 就是⿏标松开时,等等.
📝 代码示例: 设置按钮的伪类样式.
- 在界⾯上创建⼀个按钮

- 编写 main.cpp, 创建全局样式
cpp
#include "widget.h"
#include <QApplication>
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();
}
- 运⾏程序, 可以看到, 默认情况下按钮⽂字是红⾊, ⿏标移动上去是绿⾊, ⿏标按下按钮是蓝⾊.

上述代码也可以使⽤事件的⽅式来实现.
📝 代码示例:使⽤事件⽅式实现同样效果
- 创建
MyPushButton类, 继承⾃QPushButton

- 把⽣成代码中的构造函数改成带参数 QWidget* 版本的构造函数. (否则⽆法和 Qt Designer ⽣成的代码适配).
cpp
********************mypushbutton.h**********************
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include<QPushButton>
class myPushButton : public QPushButton
{
public:
myPushButton(QWidget* parent);
};
#endif // MYPUSHBUTTON_H
*******************mypushbutton.cpp********************
#include "mypushbutton.h"
myPushButton::myPushButton(QWidget* parent):QPushButton(parent)
{
}
- 在界⾯上创建按钮, 并提升为
MyPushButton类型

右键按钮, 选择 "提升为"
填写提升的类名和头⽂件.

提升完毕后, 在右侧对象树这⾥, 就可以看到类型的变化.

- 重写
MyPushButton的四个事件处理函数
mypushbutton.h
cpp
********************mypushbutton.h**********************
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include<QPushButton>
#include<QMouseEvent>
#include<QEvent>
class myPushButton : public QPushButton
{
public:
myPushButton(QWidget* parent);
void mousePressEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
void enterEvent(QEvent* e);
void leaveEvent(QEvent* e);
};
#endif // MYPUSHBUTTON_H
修改 mypushbutton.cpp
• 初始化设为红⾊
• ⿏标进⼊时设为绿⾊, 离开是还原红⾊.
• ⿏标按下时设为蓝⾊, 松开时还原绿⾊(松开时⿏标还是在按钮⾥)
cpp
#include "mypushbutton.h"
//按钮原始是红色
myPushButton::myPushButton(QWidget* parent):QPushButton(parent)
{
this->setStyleSheet("QPushButton {color : red;}");
}
//鼠标点击按钮区域,按钮字体变为蓝色
void myPushButton::mousePressEvent(QMouseEvent *e)
{
this->setStyleSheet("QPushButton {color : blue;}");
}
//鼠标点击并释放按钮区域,按钮字体变为绿色
void myPushButton::mouseReleaseEvent(QMouseEvent *e)
{
this->setStyleSheet("QPushButton {color : green;}");
}
//鼠标进入按钮区域,按钮字体变为绿色
void myPushButton::enterEvent(QEvent *e)
{
this->setStyleSheet("QPushButton {color : green;}");
}
//鼠标离开按钮区域,按钮字体变为红色
void myPushButton::leaveEvent(QEvent *e)
{
this->setStyleSheet("QPushButton {color : red;}");
}
- 运⾏程序, 可以看到效果和上述案例⼀致.

✍ 很明显, 实现同样的功能, 伪类选择器要⽐事件的⽅式简单很多.
但是不能就说事件机制就不好. 事件可以完成的功能很多, 不仅仅是样式的改变, 还可以包含其
他业务逻辑. 这⼀点是伪类选择器⽆法替代的.
🌲2.5 样式属性
QSS 中的样式属性⾮常多, 不需要都记住. 核⼼原则还是⽤到了就去查.
当我们在翻阅官方⽂档的时候会涉及到⼀个关键术语 "盒模型" (Box Model),下面简要的介绍一下"盒模型"。
2.5.1 盒模型 (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。 |
margin:10px四个方向都是10px的外边距
margin:10px 20px:上下是10px,左右是20px
margin:10px,20px,30px,40px上右下左(顺时针)
padding也是可以拆成4个属性
📝 代码⽰例: 设置边框和内边距
-
在界⾯上创建⼀个
label -
修改 main.cpp, 设置全局样式
•
border: 5px solid red相当于border-style: solid; border-width: 5px;border-color: red; 三个属性的简写形式.•
padding-left: 10px; 是给左侧设置内边距.
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyleSheet("QLabel { border: 5px solid red; padding-left: 10px; }");
Widget w;
w.show();
return a.exec();
}
- 运⾏程序, 可以看到样式发⽣了变化

📝 代码⽰例: 设置外边距
为了⽅便确定控件位置, 演⽰外边距效果, 我们使⽤代码创建⼀个按钮.
- 修改 widget.cpp, 创建按钮, 并设置样式.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* btn = new QPushButton(this);
btn->setGeometry(0, 0, 100, 100);
btn->setText("hello");
btn->setStyleSheet("QPushButton { border: 5px solid red; margin: 20px; }");
const QRect& rect = btn->geometry();
qDebug() << rect;
}
- 运⾏程序, 可以看到, 当前按钮的边框被外边距挤的缩⼩了. 但是获取到的按钮的
Geometry是不变的.

2.6 控件样式⽰例
下⾯给出⼀些常⽤控件的样式⽰例.
2.6.1 按钮
📝 代码⽰例: ⾃定义按钮
- 界⾯上创建⼀个按钮

- 右键 -> 改变样式表, 使⽤
Qt Designer设置样式
css
QPushButton {
font-size: 20px;
border: 2px solid #8f8f91;
border-radius: 15px;
background-color: #dadbde;
}
QPushButton:pressed {
background-color: #f6f7fa;
}
- 执⾏程序, 可以看到效果

属性⼩结
| QSS 属性 | 说明 |
|---|---|
font-size |
设置文字大小。 |
border-radius |
设置圆角矩形,数值设置的越大,角就越"圆"。 |
background-color |
设置背景颜色。 |
2.6.2 复选框
📝 代码⽰例: ⾃定义复选框
- 创建⼀个 resource.qrc ⽂件,导入对应的图标.
使⽤⿊⾊作为默认形态.
使⽤蓝⾊作为 hover 形态.
使⽤红⾊作为 pressed 形态.
注意这⾥的⽂件命名.
- 创建⼀个复选框

- 编辑复选框的样式
css
QCheckBox{
font-size : 20px;
}
QCheckBox::indicator{
width : 20px;
height : 20px;
}
QCheckBox::indicator:unchecked{
image:url(:/unchecked.png);
}
QCheckBox::indicator:unchecked:hover{
image:url(:/unchecked_hover.png));
}
QCheckBox::indicator:unchecked:pressed{
image:url(:/unchecked_pressed.png);
}
QCheckBox::indicator:checked{
image:url(:/checked.png);
}
QCheckBox::indicator:checked:hover{
image:url(:/checked_hover.png);
}
QCheckBox::indicator:checked:pressed{
image:url(:/checked_pressed.png);
}
- 运⾏程序, 可以看到此时的复选框就比较丰富了.
要点小结
| 要点 | 说明 |
|---|---|
::indicator |
子控件选择器,选中 checkbox 中的对钩部分。 |
:hover |
伪类选择器,选中鼠标移动上去的状态。 |
:pressed |
伪类选择器,选中鼠标按下的状态。 |
:checked |
伪类选择器,选中 checkbox 被选中的状态。 |
:unchecked |
伪类选择器,选中 checkbox 未被选中的状态。 |
width |
设置子控件宽度。对于普通控件无效(普通控件使用 geometry 方式设定尺寸)。 |
height |
设置子控件高度。对于普通控件无效(普通控件使用 geometry 方式设定尺寸)。 |
image |
设置子控件的图片。像 QSpinBox、QComboBox 等可以使用这个属性来设置子控件的图片。 |
🐳 单选框设置如上,具体操作请自行验证。
2.6.4 输⼊框
📝 代码⽰例: ⾃定义单⾏编辑框
- 在界⾯上创建⼀个单⾏编辑框
- 在
Qt Designer中编写样式.
css
QLineEdit {
border-width: 1px;
border-radius: 10px;
border-color: rgb(58, 58, 58);
border-style: inset;
padding: 0 8px;
color: rgb(255, 255, 255);
background:rgb(100, 100, 100);
selection-background-color: rgb(187, 187, 187);
selection-color: rgb(60, 63, 65);
}

属性小结
| QSS 属性 | 说明 |
|---|---|
border-width |
设置边框宽度。 |
border-radius |
设置边框圆角。 |
border-color |
设置边框颜色。 |
border-style |
设置边框风格。 |
padding |
设置内边距。 |
color |
设置文字颜色。 |
background |
设置背景颜色。 |
selection-background-color |
设置选中文字的背景颜色。 |
selection-color |
设置选中文字的文本颜色。 |
2.6.5 列表
📝 代码⽰例: ⾃定义列表框
- 在界⾯上创建⼀个 ListView

- 编写代码
css
QListView::item:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #FAFBFE, stop: 1 #DCDEF1);
}
QListView::item:selected {
border: 1px solid #6a6ea9;
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #6a6ea9, stop: 1 #888dd9);
}
- 执⾏程序, 观察效果

属性小结
| 要点 | 说明 |
|---|---|
::item |
选中 QListView 中的具体条目。 |
:hover |
选中鼠标悬停的条目。 |
:selected |
选中某个被选中的条目。 |
background |
设置背景颜色。 |
border |
设置边框。 |
qlineargradient |
设置渐变色。 |
✏️ 总结 :关于
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进⾏渐变的.这里的取值比较有限,要么是0,要么是1
代码例⼦: 理解渐变⾊
- 界⾯不创建任何控件
- 编写样式
css
QWidget {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #fff,
stop: 1 #000);
}
当前按照 垂直从上往下 从 ⽩⾊ 过渡到 ⿊⾊
效果如下:

- 修改代码
css

当前按照 ⽔平从左往右 从 ⽩⾊ 过渡到 ⿊⾊
效果如下:

2.6.6 菜单栏
📝代码⽰例: ⾃定义菜单栏
- 创建菜单栏
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建菜单栏
QMenuBar* menuBar = new QMenuBar(this);
//创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("工具");
QMenu* menu3 = new QMenu("编辑");
//将菜单加入到菜单栏中
menuBar->addMenu(menu1);
menuBar->addSeparator();
menuBar->addMenu(menu2);
menuBar->addSeparator();
menuBar->addMenu(menu3);
//创建菜单项
QAction* action1 = new QAction("打开");
QAction* action2 = new QAction("关闭");
QAction* action3 = new QAction("创建");
QAction* action4 = new QAction("打开已有文件");
//将菜单项加入到菜单中
menu1->addAction(action1);
menu1->addSeparator();
menu1->addAction(action2);
menu1->addSeparator();
menu1->addAction(action3);
menu1->addSeparator();
menu1->addAction(action4);
}
Widget::~Widget()
{
delete ui;
}
- 编写样式
css
****************************style.qss************************************
QMenuBar {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 lightgray, stop:1 darkgray);
spacing: 3px; /* spacing between menu bar items */
}
QMenuBar::item {
padding: 1px 4px;
background: transparent;
border-radius: 4px;
}
QMenuBar::item:selected { /* when selected using mouse or keyboard */
background: #a8a8a8;
}
QMenuBar::item:pressed {
background: #888888;
}
QMenu {
background-color: white;
margin: 0 2px; /* some spacing around the menu */
}
QMenu::item {
padding: 2px 25px 2px 20px;
border: 3px solid transparent; /* reserve space for selection border */
}
QMenu::item:selected {
border-color: darkblue;
background: rgba(100, 100, 100, 150);
}
QMenu::separator {
height: 2px;
background: lightblue;
margin-left: 10px;
margin-right: 5px;
}
读取style.qss资源文件的代码如下:
cpp
#include "widget.h"
#include <QApplication>
#include <QFile>
#include <QString>
#include <QDebug>
QString loadQSS()
{
QFile file(":/style.qss");
// 重点:以只读文本模式打开资源文件
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "打开qss失败:" << file.errorString();
return "";
}
QString style = file.readAll();
file.close();
return style;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = loadQSS();
a.setStyleSheet(style);
qDebug()<< style;
Widget w;
w.show();
return a.exec();
}
- 执⾏程序, 观察效果

要点小结
| 要点 | 说明 |
|---|---|
QMenuBar::item |
选中菜单栏中的元素。 |
QMenuBar::item:selected |
选中菜单栏中的被选中的元素。 |
QMenuBar::item:pressed |
选中菜单栏中的鼠标点击的元素。 |
QMenu::item |
选中菜单中的元素。 |
QMenu::item:selected |
选中菜单中的被选中的元素。 |
QMenu::separator |
选中菜单中的分割线。 |
🎯 3. 总结与经典面试题
3.1 本章总结
本章围绕 QSS(Qt Style Sheets) 展开,核心要点如下:
- QSS 是什么 :Qt 仿照 CSS 引入的样式表语言,用于美化 Qt 控件,语法为
选择器 { 属性名: 属性值; }。 - 设置方式 :可通过
QWidget::setStyleSheet指定控件设置、QApplication::setStyleSheet全局设置、从 qss 文件加载、或使用 Qt Designer 编辑。 - 层叠性与优先级:全局样式与局部样式不冲突时叠加生效(层叠性);冲突时局部样式优先,ID 选择器优先级高于类型选择器。
- 选择器 :类型、类、ID、后代、子、并集、属性、子控件(
::)、伪类(:hover、:pressed等)。 - 盒模型:Content、Border、Padding、Margin 四部分,默认边距与边框宽度均为 0。
- 常用控件样式 :按钮、复选框、输入框、列表、菜单栏等均可通过 QSS 定制,渐变可用
qlineargradient实现。
💡 复习提示:QSS 属性繁多,核心原则是「用到了就去查」,重点掌握选择器与优先级规则即可。
3.2 经典面试题
面试题 1:QSS 和 CSS 有什么区别?
参考答案:
QSS(Qt Style Sheets)是 Qt 仿照 CSS 引入的样式表语言,语法结构基本一致(选择器 { 属性: 值; })。但 QSS 只支持部分 CSS 属性,整体比 CSS 更简单。QSS 用于美化 Qt 控件,而 CSS 用于美化网页元素。
面试题 2:QSS 有哪几种设置方式?分别有什么特点?
参考答案:
- 指定控件设置 :通过
widget->setStyleSheet()设置,仅对该控件及其子元素生效。 - 全局设置 :通过
QApplication::setStyleSheet()设置,对整个程序的所有相关控件生效,便于统一风格与维护。 - 从文件加载 :把样式写入独立的
.qss文件,通过QFile读取并设置,避免 C++ 与 QSS 代码耦合。 - Qt Designer 编辑 :在 Designer 中直接编辑样式,可实时预览,样式会以 XML 形式记录到
.ui文件中。
面试题 3:什么是 QSS 的「层叠性」?全局样式和局部样式冲突时谁优先?
参考答案:
层叠性(Cascading)指多个样式规则作用于同一控件时,不冲突的属性会叠加生效。例如全局样式设置了颜色,局部样式设置了字体大小,两者都会生效。当全局样式与局部样式冲突时,局部样式(指定控件样式)优先级更高,会覆盖全局样式。
面试题 4:QSS 支持哪些选择器?ID 选择器和类型选择器冲突时谁优先?
参考答案:
QSS 支持全局选择器(*)、类型选择器(QPushButton)、类选择器(.QPushButton)、ID 选择器(#objectName)、后代选择器、子选择器、并集选择器、属性选择器、子控件选择器(::)和伪类选择器(:)。
当 ID 选择器和类型选择器选中同一控件且样式冲突时,ID 选择器优先级更高。一般来说,选择器描述的范围越精准,优先级越高。
面试题 5:什么是子控件选择器?请举例说明。
参考答案:
子控件选择器使用 :: 语法,用于选中控件内部的子部件。例如 QComboBox::down-arrow 可以选中下拉框的下拉按钮,QCheckBox::indicator 可以选中复选框的对钩部分,QProgressBar::chunk 可以选中进度条的块。可以通过 image、width、height 等属性设置子控件的样式。
面试题 6:什么是伪类选择器?常用的有哪些?
参考答案:
伪类选择器根据控件所处的状态来选择控件,状态具备时样式生效。常用的伪类选择器包括:
| 伪类选择器 | 说明 |
|---|---|
:hover |
鼠标放到控件上时 |
:pressed |
鼠标左键按下时 |
:focus |
获取输入焦点时 |
:enabled |
元素处于可用状态时 |
:checked |
被勾选时 |
:read-only |
元素为只读状态时 |
这些状态还可以用 ! 取反,例如 :!hover 表示鼠标离开控件时。
面试题 7:请简述 QSS 的盒模型(Box Model)。
参考答案:
盒模型由四部分组成:
- Content:存放控件内容(文本/图标)的矩形区域。
- Border:控件的边框。
- Padding:内边距,边框和内容之间的距离。
- Margin :外边距,边框到控件
geometry返回的矩形边界的距离。
默认情况下,外边距、内边距、边框宽度都是 0。可以通过 margin、padding、border-style、border-width、border-color 等属性设置。
面试题 8:如何实现按钮的悬停变色效果?伪类选择器和事件方式哪个更好?
参考答案:
伪类选择器方式:
css
QPushButton { color: red; }
QPushButton:hover { color: green; }
QPushButton:pressed { color: blue; }
事件方式 :继承 QPushButton,重写 enterEvent、leaveEvent、mousePressEvent、mouseReleaseEvent,在事件中调用 setStyleSheet 改变颜色。
对比:实现同样的功能,伪类选择器更简单、代码更少。但事件机制不仅能改变样式,还能处理其他业务逻辑,这是伪类选择器无法替代的。
面试题 9:如何从文件加载 QSS 样式?为什么要使用 qrc 资源文件?
参考答案:
将样式写入独立的 .qss 文件,通过 QFile 读取文件内容并调用 QApplication::setStyleSheet 设置。示例:
cpp
QString loadQSS() {
QFile file(":/style.qss");
file.open(QFile::ReadOnly);
QString style = file.readAll();
file.close();
return style;
}
使用 qrc 资源文件是为了规避绝对路径问题,把资源文件内容打包到 cpp 代码中,程序运行时通过 :/ 前缀访问,便于部署和移植。
面试题 10:如何理解 qlineargradient 渐变?它的参数含义是什么?
参考答案:
qlineargradient 用于设置线性渐变,有 6 个参数:x1, y1 标注起点,x2, y2 标注终点,两点描述渐变方向;stop: 0 和 stop: 1 描述两个颜色,渐变过程就是从 stop: 0 的颜色过渡到 stop: 1 的颜色。
例如:
x1: 0, y1: 0, x2: 0, y2: 1:垂直方向从上向下渐变。x1: 0, y1: 0, x2: 1, y2: 0:水平方向从左向右渐变。x1: 0, y1: 0, x2: 1, y2: 1:从左上往右下渐变。

