🔥 在网页前端开发领域中,CSS 是一个至关重要的部分,描述了一个网页的 “样式”,从而起到对网页 美化 的作用。
网页开发作为 GUI 的典型代表,也对于其他客户端 GUI 开发产生了影响,Qt 也是其中之一。
注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突,则 QSS 优先级更高。
对于 CSS 来说,基本的语法结构非常简单。
QSS 沿用了其设定:
选择器 {
属性名: 属性值;
}
其中:
例如:
QPushButton { color: red; }
//或者:
QPushButton {
color: red;
}
QPushButton
,都把文本颜色设置为红色编写 QSS 时使用单行 和多行的格式均可。
新建项目,以 Widget 作为基类,构造函数代码如下:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QGridLayout* layout = new QGridLayout();
QPushButton* button1 = new QPushButton("红色");
QPushButton* button2 = new QPushButton("无色");
button1->setStyleSheet("QPushButton{color:red;}");
layout->addWidget(button1, 0, 0);
layout->addWidget(button2, 0, 1);
this->setLayout(layout);
}
结果如下:
**注意:**上述代码中,只针对这一个按钮通过 setStyleSheet
方法设置的样式,此时这个样式仅针对该按钮生效。如果创建其他按钮,其他按钮不会受到影响。
QWidget
中包含了 setStyleSheet
方法,可以直接设置样式。
【子元素受到影响】
A. 在界面上创建两个按钮和一个单行编辑框
B. 修改 widget.cpp
这次不再给按钮设置样式,而是给 Widget 设置样式(Widget 是 QPushButton 的父控件)
可以通过 QApplication
的 setStyleSheet
方法设置整个程序的全局样式。
全局样式优点:
如果通过 全局样式 给某个控件设置了属性 1,通过 指定控件样式 给控件设置属性 2,那么这两个属性都会产生作用
比如:基于上面全局样式的设计,我们给 按钮1 设置字体大小,如下:
可以看到,对于第一个按钮来说,同时具备了颜色和字体大小样式,而第二个按钮只有颜色样式。
说明针对第一个按钮,两种设置方式设置的样式叠加起来了。
CSS 全称为 Cascading Style Sheets
,其中 Cascading
就是 “层叠性” 的意思,QSS 也继承了这样的设定。实际上把 QSS 叫做 QCSS 也许更合适一些。
注意:局部样式无法叠加,除非写到一行中,如下:
如果全局样式和指定控件样式冲突,则指定控件样式优先展示
在 CSS 中也存在类似的优先级规则。通常来说都是 “局部” 优先级高于 “全局” 优先级,相当于全局样式先 “奠定基调”,再通过指定控件样式来 “特事特办”。
上述代码都是把样式通过硬编码的方式设置的,这样使 QSS 代码和 C++ 代码 耦合 在一起了,并不方便代码的维护。
因此更好的做法是把 样式放到单独的文件中,然后通过读取文件的方式来加载样式
操作如下:
A. 在界面上创建一个按钮
B. 创建 resource.qrc 文件(Qt -> Qt Resource File),并设定前缀为 /
C. 创建 style.qss 文件,并添加到 resource.qrc 中
style.qss
是需要程序运行时加载的,为了规避绝对路径的问题,仍然使用 qrc 的方式来组织(即把资源文件内容打包到 cpp 代码中)Qt Creator
没有提供创建 qss 文件的选项,直接 “右键” -> “新建” -> “文本文档”,手动设置文件扩展名为 qss 即可使用 Qt Creator 打开 style.qss,编写内容
新增一个函数来加载样式,如下:
理论上来说 Qt 应该要提供直接从文件加载样式表的接口。
setStyleSheetFromFile(const QString& path)
这种,在内部把读文件操作封好。QSS 也可以通过 Qt Designer 直接编辑,从而起到 实时预览的效果
如下:
这种方式设置样式,样式内容会被以 xml 格式记录到 ui 文件中,如下:
同时在控件的 styleSheet 属性中也会体现:
💡 由于设置样式太灵活,有很多地方都能设置,所以当我们发现一个控件的样式不符合预期的时候,要记得排查这几个地方:
在实际开发中,如果需要设置样式,建议最好 统一使用某一种方式 来设置。
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 的控件。 |
① 在界面上创建一个按钮,修改 main.cpp,设置全局样式
a.setStyleSheet("QWidget{color:red;}");
② 但是 💢如果把上述样式代码修改为下列代码
a.setStyleSheet(".QWidget{color:red;}");
在开发中,如果期望不同的控件样式不同,此时就需要使用到 ID 选择器了
① 在界面上创建 3 个按钮,objectName 为 pushButton、pushButton_2、pushButton_3
② 编写 main.cpp,设置全局样式
#pushButton
和 #pushButton_2
分别设置这两个按钮为绿色和黄色。
当某个控件身上,通过类型选择器和 ID 选择器 设置了冲突的样式 时,ID 选择器样式优先级更高(遵循局部优先)
同理,如果是其他的多种选择器作用同一个控件时出现冲突的样式,也会涉及到优先级问题。Qt 文档上有具体的优先级规则介绍(参见 The Style Sheet Syntax 的 Conflict Resolution 章节)
这里的规则计算起来非常复杂(CSS 中也存在类似的设定)。可以简单的认为,选择器描述的范围越精准,则优先级越高。一般来说,ID 选择器优先级是最高的。
如果属性不冲突,还是会同时生效
创建三个按钮、一个 label、一个单行输入框,编写 main.cpp,设置全局样式
QString style="QPushButton,QLineEdit,QLabel{color:red;}";
a.setStyleSheet(style);
此时就可以看到这三种控件的文字颜色都设置为了红色:
也可以指定 id 选择器:
QString style="#pushButton_2,QLineEdit,QLabel{color:red;}";
有些控件内部包含了多个 “子控件”,比如 QComboBox
的下拉后的面板,比如 QSpinBox
的上下按钮等。
可以通过 子控件选择器 ::
,针对上述子控件进行样式设置。
哪些控件拥有哪些子控件,参考文档 Qt Style Sheets Reference 中 List of Sub-Controls 章节
【设置下拉框的下拉按钮样式】
① 在界面上创建一个下拉框,并创建几个选项
② 创建 resource.qrc,并导入图片 downPull.png
③ 修改 main.cpp,编写全局样式
QString style="QComboBox::down-arrow{ image:url(:/downPull.png)}";
a.setStyleSheet(style);
结果如下:
伪类选择器,是根据 控件所处的某个状态 被选择的。
例如按钮被按下,输入框获取到焦点,鼠标移动到某个控件上等。
使用 :
的方式 定义伪类选择器
常用的伪类选择器:
伪类选择器 | 说明 |
---|---|
:hover | 鼠标放到控件上 |
:pressed | 鼠标左键按下时 |
:focus | 获取输入焦点时 |
:enabled | 元素处于可用状态时 |
:checked | 被勾选时 |
:read-only | 元素为只读状态时 |
这些状态可以使用 ! 来取反,比如 :!hover
就是鼠标离开控件时,:!pressed
就是鼠标松开时,等等。更多伪类选择器的详细情况可以参考 Qt Style Sheets Reference 的 Pseudo-States 章节。
【设置按钮的伪类样式】
在界面上创建一个按钮,编写 main.cpp,创建 全局样式
QString style = "QPushButton { color: red; }";
style += "QPushButton:hover { color: green; }";
style += "QPushButton:pressed { color: blue; }";
a.setStyleSheet(style);
运行程序,结果如下:
上述代码也可以使用事件的方式来实现。
【使用事件方式实现同样效果】
① 创建 MyPushButton 类,继承自 QPushButton
② 把生成代码中的构造函数 改成带参数 QWidget* 版本的构造函数(否则无法和 Qt Designer 生成的代码适配),如下:
// mypushbutton.h
#include <QPushButton>
class MyPushButton : public QPushButton
{
public:
MyPushButton(QWidget* parent);
};
// mypushbutton.cpp
#include "mypushbutton.h"
MyPushButton::MyPushButton(QWidget* parent) : QPushButton(parent)
{
}
③ 在界面上创建按钮,并提升为 MyPushButton 类型
提升完毕后,在右侧对象树这里,就可以看到类型的变化。
④ 重写 MyPushButton 的四个事件处理函数
a. 修改 mypushbutton.h
class MyPushButton : public QPushButton
{
public:
MyPushButton(QWidget* parent);
void mousePressEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
void enterEvent(QEvent* e);
void leaveEvent(QEvent* e);
};
b. 修改 mypushbutton.cpp
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; }");
}
很明显,实现同样的功能,伪类选择器要比事件的方式简单很多。 但是不能就说事件机制就不好,事件可以完成的功能很多,不仅仅是样式的改变,还可以包含其他业务逻辑,这一点是 伪类选择器 无法替代的。
QSS 中的样式属性非常多,大部分的属性和 CSS 是非常相似的。
Qt Style Sheets Reference
章节详细介绍了哪些控件可以设置属性,每个控件都能设置哪些属性等。在文档的 Customizing Qt Widgets Using Style Sheets
的 The Box Model
章节介绍了盒模型
⼀个遵守盒模型的控件,由上述几个部分构成
可以通过一些 QSS 属性来设置上述的边距和边框的样式:
QSS 属性 | 说明 |
---|---|
margin | 设置四个方向的外边距。复合属性。 |
padding | 设置四个方向的内边距。复合属性。 |
border-style | 设置边框样式 |
border-width | 边框的粗细 |
border-color | 边框的颜色 |
这里的复合属性:由多个属性构成,margin 可以拆成如下:
当然实际运用的时候,写 margin: 10px; ==> 表示四个方向都是 10px 的外边距,而写 margin: 10px 20px; 则是上下都是 10px, 左右是 20px, margin: 10px 20px 30px 40px ==> 上右下左(顺时针)
【设置边框和内边距】
在界面上创建一个 label,修改 main.cpp, 设置全局样式
QString style = "QLabel{border: 20px solid green; padding-left: 50px}";
a.setStyleSheet(style);
border: 20px solid green
相当于 border-style: solid; border-width: 2px; border-color: green;
三个属性的简写形式。padding-left: 50px;
是给左侧设置内边距。结果如下:
【设置外边距】
为了方便确定控件位置,演示外边距效果,使用代码创建⼀个按钮。修改 widget.cpp,创建按钮,并设置样式
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton* button = new QPushButton(this);
button->setGeometry(0, 0, 100, 100);
button->setText("按钮");
button->setStyleSheet("QPushButton{border: 5px solid red; margin: 20px}");
qDebug() << button->geometry();
}
运行程序如下:
可以看到,当前按钮的边框被外边距挤的缩小了,但是获取到的按钮的 Geometry 是不变的。
A. 界面上创建一个按钮
B. 右键 -> 改变样式表,使用 Qt Designer 设置样式
C. 执行程序,点击 “按钮”:
属性 | 说明 |
---|---|
font-size | 设置文字大小。 |
border-radius | 设置圆角矩形。 数值设置的越大,角就越圆。 |
background-color | 设置背景颜色。 |
A. 创建一个 resource.qrc
文件,并导入以下图片
⚽ 使用阿里矢量图标库,可以下载到上述图片,下载的时候可以手动选择颜色
注意这里的文件命名。
B. 创建一个复选框,并且用样式表来编辑复选框的样式
QCheckBox {
font-size: 20px;
}
QCheckBox::indicator {
width: 20px;
height: 20px;
}
QCheckBox::indicator:unchecked {
image: url(:/checkbox-unchecked.png);
}
QCheckBox::indicator:unchecked:hover {
image: url(:/checkbox-unchecked_hover.png);
}
QCheckBox::indicator:unchecked:pressed {
image: url(:/checkbox-unchecked_pressed.png);
}
QCheckBox::indicator:checked {
image: url(:/checkbox-checked.png);
}
QCheckBox::indicator:checked:hover {
image: url(:/checkbox-checked_hover.png);
}
QCheckBox::indicator:checked:pressed {
image: url(:/checkbox-checked_pressed.png);
}
要点 | 说明 |
---|---|
::indicator | 子控件选择器。 选中 checkbox 中的对钩部分。 |
:hover | 伪类选择器。 选中鼠标移动上去的状态。 |
:pressed | 伪类选择器。 选中鼠标按下的状态。 |
:checked | 伪类选择器。 选中 checkbox 被选中的状态。 |
:unchecked | 伪类选择器。 选中 checkbox 未被选中的状态。 |
width | 设置子控件宽度。 对于普通控件无效(普通控件使用 geometry 方式设定尺寸)。 |
height | 设置子控件高度。 对于普通控件无效(普通控件使用 geometry 方式设定尺寸)。 |
image | 设置子控件的图片。 像 QSpinBox, QComboBox 等可以使用这个属性来设置子控件的图片。 |
A. 创建 resource.qrc 文件,并导入以下图片
B. 在界面上创建两个单选按钮,并且在 Qt Designer 中编写样式
QWidget QRadioButton {
font-size: 20px;
}
QWidget QRadioButton::indicator {
width: 20px;
height: 20px;
}
QWidget QRadioButton::indicator:unchecked {
image: url(:/radio-unchecked.png);
}
QWidget QRadioButton::indicator:unchecked:hover {
image: url(:/radio-unchecked_hover.png);
}
QWidget QRadioButton::indicator:unchecked:pressed {
image: url(:/radio-unchecked_pressed.png);
}
QWidget QRadioButton::indicator:checked {
image: url(:/radio-checked.png);
}
QWidget QRadioButton::indicator:checked:hover {
image: url(:/radio-checked_hover.png);
}
QWidget QRadioButton::indicator:checked:pressed {
image: url(:/radio-checked_pressed.png);
}
运行程序,如下:
注意 :
A. 在界面上创建一个单行编辑框,在 Qt Designer 中编写样式
QLineEdit {
border-width: 2px;
border-radius: 20px;
border-color: rgb(170, 170, 255);
border-style: solid;
padding: 0 8px;
color: rgb(170, 85, 127);
background:rgb(220, 220, 225);
selection-background-color: rgb(0, 180, 0);
selection-color: rgb(180, 0, 0);
}
B. 执行程序,输入文本,并且选中 :
属性 | 说明 |
---|---|
border-width | 设置边框宽度。 |
border-radius | 设置边框圆角。 |
border-color | 设置边框颜色。 |
border-style | 设置边框风格。 |
padding | 设置内边距。 |
color | 设置文字颜色。 |
background | 设置背景颜色。 |
selection-background-color | 设置选中文字的背景颜色。 |
selection-color | 设置选中文字的文本颜色。 |
A. 在界面上创建一个 ListView
,然后在样式表中编写代码,如下:
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);
}
B. 然后将其变形成为 ListWidget,然后右击进行编辑项目,如下:
C. 执行程序,结果如下:
要点 | 说明 |
---|---|
::item | 选中 QListView 中的具体条目。 |
:hover | 选中鼠标悬停的条目 |
:selected | 选中某个被选中的条目。 |
background | 设置背景颜色 |
border | 设置边框。 |
qlineargradient | 设置渐变色。 |
qlineargradient 有 6 个参数。
例如
【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 进行渐变的。
举个例子:
现在新建一个项目,界面不创建任何任何控件,编写样式,如下:
QWidget {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop: 0 #fff, stop: 1 #000);
}
修改代码》让其当前按照水平从左往右从白色过渡到黑色
QWidget {
background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop: 0 #fff, stop: 1 #000);
}
A. 创建菜单栏,创建若干菜单项和一个分隔符:
B. 编写样式表,如下:
QMenuBar {
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 lightgray, stop:1 darkgray);
spacing: 3px;
}
QMenuBar::item {
padding: 1px 4px;
background: transparent;
border-radius: 4px;
}
QMenuBar::item:selected {
background: #a8a8a8;
}
QMenuBar::item:pressed {
background: #888888;
}
QMenu {
background-color: white;
margin: 0 2px;
}
QMenu::item {
padding: 2px 25px 2px 20px;
border: 3px solid transparent;
}
QMenu::item:selected {
border-color: darkblue;
background: rgba(100, 100, 100, 150);
}
QMenu::separator {
height: 2px;
background: lightblue;
margin-left: 10px;
margin-right: 5px;
}
执行代码,结果如下:
要点 | 说明 |
---|---|
QMenuBar::item | 选中菜单栏中的元素。 |
QMenuBar::item:selected | 选中菜单栏中的被选中的元素。 |
QMenuBar::item:pressed | 选中菜单栏中的鼠标点击的元素。 |
QMenu::item | 选中菜单中的元素 |
QMenu::item:selected | 选中菜单中的被选中的元素。 |
QMenu::separator | 选中菜单中的分割线。 |
A. 在界面上创建元素,并使用 布局管理器 把相关元素包裹一下
minimumHeight
均设置为 30(元素在布局管理器中无法直接设置 width 和 height,使用 minimumWidth
和 minimumHeight
代替,此时垂直方向的 sizePolicy 要设为 fixed)。
设置背景图片
创建 qrc 文件,导入背景图
QFrame
,背景图片就设置到 QFrame
上即可。编写 QFrame
的 QSS 样式:
QFrame{
border-image:url(:/ship.jpg);
}
border-image
设置背景图片,而不是 background-image
。border-image
是可以自动缩放的,这一点在窗口大小发生改变时是非常有意义的。效果如下:
编写 CSS 代码(样式表):
transparent
表示完全透明(应用父元素的背景)。QFrame{
border-image:url(:/ship.jpg);
}
QLineEdit {
color: #8d98a1;
background-color: #405361;
padding: 0 5px;
font-size: 20px;
border-style: none;
border-radius: 10px;
}
QCheckBox {
color: white;
background-color: transparent;
}
QPushButton {
font-size: 20px;
color: white;
background-color: #5555;
border-style: outset;
border-radius: 10px;
}
QPushButton:pressed {
color: black;
background-color: #ced1db;
border-style: inset;
}
然后还需要对两个输入框的 ui 做点改变,如下:
运行程序,最终效果如下:
QFrame
的属性中即可。通常我们建议把样式代码集中放置,方便调整和排查。QSS 本身给 Qt 提供了更丰富的样式设置的能力,但是整体来说 QSS 的功能是不如 CSS 的。
另外,做出好看的界面,光靠 QSS 是不够的,更重要的是需要 专业美工做出设计稿
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有