文章目录
- QSS概述
- QSS 设置方式
- 1. 指定控件设置样式
- 2. 全局样式设置
- 3. 样式的层叠
- 4. 从文件加载样式表
- 5. 使用 Qt Designer 编辑样式
- 选择器
- 选择器概述
- 1. 类选择器
- 2. ID选择器
- 3. 子控件选择器(Sub-Controls)
- 4. 伪类选择器(Pseudo-States)
- 样式属性
- 盒子模型(Box Model)
- 控件样式实例
- 1. 按钮
- 2. 复选框
- 3. 输入框
- 4. 列表
- 5. 菜单栏
- 6. 登录界面
- 总结
QSS概述
俗话说,“人靠衣装,马靠鞍”,一个人的外表和服饰对他人印象非常重要,就如同马匹需要良好的鞍具来显得更气派,网页和应用程序也是如此。
在网页前端开发领域,CSS(Cascading Style Sheets,即“层叠样式表”)
,是一种用于描述网页文档的呈现样式的语言
样式,包括但不限于大小,位置,颜色,背景,字体等
客户端的界面美化同样十分影响用户体验,Qt 仿照 CSS 模式,引入 QSS ,来对 Qt 中的控件做出样式上的设定,从而实现更好看,更有观感的界面。
因为 Qt 本身的设计理念和网页前端存在一定差异,所以 QSS 只能支持部分 CSS 属性,整体来说,简单一些
如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突,则 QSS 优先级更高
基本语法
QSS 沿用了 CSS 的语法结构
选择器 {
属性名: 属性值;
属性名:属性值;
}
选择器
:描述了 哪个 widget 应用该样式规则{}
:分隔样式规则属性
:使用键值对方式,属性名表示要设置哪种样式,属性值表示设置的样式的值
属性名 和 属性值 之间使用 :
分隔,属性之间通过;
分隔
示例如下:
QPushButton {
color: red;
font-size: 30px;
}
给 QPushButton(按钮) 设置样式:
- color:字体颜色
- font-size:字体大小
效果如下:
QSS 设置方式
QWidget
和 QApplication
都提供 setStyleSheet()
方法,继承自上述两个类的子类也同样可以使用该函数
其函数原型如下:
通过字符串的方式,传入 QSS 样式代码
ui->pushButton->setStyleSheet("QPushButton{ color: red; font-size: 30px; }");
效果同上
1. 指定控件设置样式
指定控件就是上述设置方式
ui->pushButton->setStyleSheet("QPushButton{ color: red; font-size: 30px; }");
需要注意的是,给指定控件设置样式后,其子元素也会受到影响
代码示例:界面上有个按钮和标签,设置 QWidget 的样式表,观察按钮和标签变化
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//此处只设置 QWidget 的样式表
this->setStyleSheet("QWidget { color:blue; font-size:30px; }");
}
可以看到,虽然只设置了 QWidget,但是按钮和标签也受到了影响,这是因为按钮和标签都在 QWidget 上,是子元素
2. 全局样式设置
还可以通过 QApplication 设置整个程序的全局样式
全局样式优点:
- 使同一个样式针对多个控件生效,简化代码
- 所有控件样式内聚在一起,便于维护和问题排查
代码示例:通过 QApplication 统一设置界面中 三个按钮 的样式
编写main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//通过QApplication 设置全局样式
a.setStyleSheet("QPushButton { color:green; font-size:30px; }");
Widget w;
w.show();
return a.exec();
}
3. 样式的层叠
对于同一控件,如果同时使用全局样式和指定控件样式,那么结果会如何呢?
- 若是不同的属性,那么都会产生作用。如全局样式设置的是颜色,指定控件样式设置的是字体大小,结果则都会显现。这就是
“层叠性”
- 若是相同的属性,即都设置了颜色,那么结果由指定样式决定。在 CSS 中也存在类似的优先级规则,
通常是 “局部” 优先级高于 “全局”
4. 从文件加载样式表
上述方式都是通过硬编码的方式设置样式,这样会使 QSS 代码和 C++ 代码耦合在一起,并不方便代码的维护
可以使用类似 配置文件
的做法,将样式放到单独的文件中,通过读取文件的方式加载样式
文件使用 qrc
方式组织,规避绝对路径的问题,具体操作可参看QWidget 的 qrc文件部分
代码示例:从文件加载全局样式
- 创建 qss 文件
新建文件 > General > Empty File
创建 .qss文件
编写样式代码
QPushButton {
color: red;
font-size: 30px;
}
- 创建
qrc文件
,并添加 style.qss
3. 编写 main.cpp
,新增函数来加载样式
QString loadQss()
{
//打开样式文件
QFile qss(":/style.qss");
qss.open(QFile::ReadOnly);
//读取样式代码
QString text = qss.readAll();
qss.close();
return text;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//获取样式格式并设置
QString qss = loadQss();
a.setStyleSheet(qss);
Widget w;
w.show();
return a.exec();
}
5. 使用 Qt Designer 编辑样式
QSS 也可以通过 Qt Designer 直接编辑,从而起到实时预览的效果,同时也能避免 C++ 和 QSS 代码的耦合
或者使用右下角的 styleSheet
编辑
Qt Designer本质会将修改 UI文件
,通过qmake将 UI文件 生成为C++代码,再和我们编写的C++代码一起编译,形成可执行程序
综上所述,样式的设置有如下几种方法
- 指定控件样式
- 全局样式
- qss 文件设置
- ui 文件设置
建议QSS的设置使用统一方式,如此方便管理,后续调整和排查也不会乱
选择器
选择器概述
QSS 支持的选择器有如下类型
选择器 | 示例 | 说明 |
---|---|---|
全局选择器 | * | 选择所有的 widget |
类型选择器(type selector) | QPushButton | 选择所有的 QPushButton 和 其子类控件 |
类选择器 | .QPushButton | 选择所有的 QPushButton控件,但不会选择其子类 |
ID选择器 | #pushButton_2 | 选择objectName 为 pushButton_2的控件 |
后代选择器 | QDialog QPushButton | 选择 QDialog 的所有后代(子控件,孙子控件等)中的QPushButton |
子选择器 | QDialog > QPushButton | 选择 QDialog 的所有子控件中的 QPushButton |
并集选择器 | QPushButton,QLineEdit,QComboBox | 接下来的样式对这三个控件都生效 |
属性选择器 | QPushButton[flat=“false”] | 选择所有 QPushButton 中,flat属性为 false的控件 |
1. 类选择器
上述使用的都是类型选择器,其子控件也会受到影响
如
this->setStyleSheet("QWidget { color: red;}");
如果 QWidget上还有子控件,如按钮,标签等,其内容也会被设置为红色
而类选择器只会选择指定的类,不包括其子控件
this->setStyleSheet(".QWidget { color: red; }");
如此只影响 QWidget,不会影响界面上的子控件
2. ID选择器
ID选择器则是更细致的指定,通过 objectName
指定控件
代码示例:
- 界面上包含3个按钮,objectName 为 pushButton,pushButton_2,pushButton_3
2. 编写main.cpp
,设置全局样式
- 先通过
QPushButton
设置所有按钮为黄色 - 再通过
#pushButton
和#pushButton_2
分别设置这两个按钮为红色和绿色
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//设置样式
QString style = "QPushButton { color: yellow; }";
style += "#pushButton { color: red; }";
style += "#pushButton_2 { color: blue; }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
当某个控件,通过 类型选择器 和 ID 选择器设置了冲突的样式时,ID 选择器样式优先级更高
同理,如果是其他的多种选择器作用同一个控件时出现冲突的样式,也会涉及到优先级问题。
Qt 文档上有具体的优先级规则介绍(参看The Style Sheet Syntax 的 Conflict Resolution 章节
)
实际开发中,可以简单的认为,选择器描述的范围越精确,优先级越高
,一般来说,ID 选择器的优先级是最高的
3. 子控件选择器(Sub-Controls)
有些控件内部包含了多个“子控件”。比如 QComboBox
的展开下拉框的按钮,和下拉框都是其子控件
可以通过 子控件选择器::
,针对上述子控件进行样式设置
控件都拥有哪些子控件,可参看
Qt Style Sheets Reference 中的 List of Sub-Controls章节
子控件如:
- QComboBox::down-arrow(下拉框按钮),QComboBox::drop-down(下拉框)
- QProgreeBar::chunk(进度条的每个"快"),QProgressBar::text(进度文本)
代码示例:通过 UI文件 设置 QComboBox 的 下拉框按钮的样式,为其按钮设置一个图标
图标可从阿里巴巴矢量图标库下载:阿里巴巴矢量图标库
- 编写 UI文件,添加一个 QComboBox
2. 使用 qrc文件,管理图标资源
3. 编写 main.cpp
,编写全局样式
- 使用子控件选择器
QComboBox::down-arrow
选中 下拉按钮 - 再通过
image
属性设置图片
a.setStyleSheet("QComboBox::down-arrow { image: url(:/button.png); }");
也可以使用 Qt Designer 添加图片
1). 选择Widget
的样式表,使用子控件选择器,点击“添加资源”
2). 选择要添加的资源,比如qrc文件管理的资源
3). 添加成功
运行结果如下:
4. 伪类选择器(Pseudo-States)
伪类选择器,是根据控件所处的某个状态被选择,类似事件/时间机制。例如按钮被按下,输入框获取到焦点,鼠标移动到某个控件上等
- 当状态具备时,控件被选中,样式生效
- 当状态不具备时,控件不被选中,样式失效
使用:
定义伪类选择器
伪类选择器可以参看 Qt Style Sheets Reference 的 List of Pseudo-States
常用的伪类选择器
伪类选择器 | 说明 |
---|---|
:hover | 鼠标放到控件上 |
:pressed | 鼠标左键按下时 |
:focus | 获取输入焦点时 |
:enabled | 元素处于可用状态时 |
:checked | 被勾选时 |
:read-only | 元素为只读只读状态时 |
状态可以使用!
来取反。比如:!hover
就是鼠标离开控件时,:!pressed
就是鼠标松开
代码示例:
若要鼠标接触到按钮时,按钮文本变为绿色
QPushButton:hover { color: green; }
若要点击按钮时,按钮中的文本颜色变成红色
QPushButton:pressed { color: red; }
样式属性
QSS中的样式属性非常多,详细属性可以参看Qt Style Sheets Reference
盒子模型(Box Model)
在Qt 文档的 Customizing Qt Widgets Using Style Sheets 的 The Box Model
章节中详细介绍了盒子模型
一个遵守盒子模型的控件,由上述几个部分组成:
- Content 矩形区域:存放控件的内容,比如包含的文本/图标等
- Border 矩形区域:控件的边框
- Padding 矩形区域:内边距。边框和内容之间的距离
- Margin 矩形区域:外边距。用于和其他控件分隔距离
默认情况下,外边距,内边距,边框宽度都是0
可以通过一些 QSS 属性来设置上述的边框和边距的样式
QSS属性 | 说明 |
---|---|
margin | 设置四个方向的外边距.复合属性 |
padding | 设置四个方向的内边距.复合属性 |
border-style | 设置边框样式 |
border-width | 边框的粗细 |
border-color | 边框的颜色 |
border | 设置边框.复合属性 |
border复合属性包括 border-width + border-style + border-color
三个属性
例如:
QPushButton { border: 5px solid red; }
就是设置边框的宽度为5px,类型为加粗,颜色为红色
margin 和 padding 的复合属性是包含了上右下左
四个方向
例如:
QPushButton { margin: 5px 6px 7px 8px; }
代表 QPushButton 的上外边距为5px,右外边距为6px,下外边距为7px,左外边距为8px
再例如:
QPushButton { margin: 5px 7px; }
代表 QPushButton 的上下外边距为5px,左右外边距为7px
也可以单独设置一边,例如 margin-left: 5px(左外边距为5px),padding-up: 7px(上内边距为7px)
控件样式实例
一些常用的控件,我们期望其状态是多样的
比如按钮的常态和按下为不同的外观,单选/复选框的常态,按下,按下后也呈现不同的外观表示不同的状态
1. 按钮
期望按钮的常态和按下为两种外观
/*按钮常态样式*/
QPushButton {
font-size: 20px;
border: 3px solid rgb(0, 255, 255);
border-radius: 15px;/*边角的弧度*/
background-color: rgb(170, 255, 255);
}
/*按钮按下样式*/
QPushButton:pressed {
background-color:rgb(0, 255, 255)
}
属性小结
属性 | 说明 |
---|---|
font-size | 设置文字大小 |
border-radius | 设置圆角矩形 数值越大,边角越光滑 |
background-color | 设置背景颜色 |
rgb是指
red green blue
,一个新的颜色由这三个颜色按比例混合形成,每个颜色的数值由 0 ~ 255,rgb(0, 255, 255)就是不要红色,绿色和蓝色拉满
也可以使用background-color: #00ffff
设置,使用十六进制表示颜色,ff转化为十进制就是255
2. 复选框
期望复选框的不同状态有如下外观
要点 | 说明 |
---|---|
::indicator | 子控件选择器 选中对钩部分 |
:hover | 伪类选择器,鼠标接触 |
:pressed | 伪类选择器,鼠标按下 |
:checked | 伪类选择器,CheckBox被选中 |
:unchecked | 伪类选择器,CheckBox未被选中 |
width | 设置子控件宽度,对于普通控件无效(普通控件使用geometry ) |
height | 设置子控件高度,对于普通控件无效,同上 |
image | 设置子控件的图片,例如QSpinBox,QCombox等可以使用这个设置子控件图片 |
过程如下:
- 使用 qrc文件管理图标资源
- 样式代码如下:
/*复选框样式*/
QCheckBox {
font-size: 40px;
}
/*复选框的下拉按钮样式*/
QCheckBox::indicator {
width: 45px;
height: 45px;
}
/*复选框未选中状态*/
QCheckBox::indicator:unchecked {
image: url(:/unchecked.png);
}
/*复选框未选中时鼠标接触*/
QCheckBox::indicator:unchecked:hover {
image: url(:/unchecked-hover.png);
}
/*复选框未选中-按下*/
QCheckBox::indicator:unchecked:pressed {
image: url(:/checked.png);
}
/*复选框选中*/
QCheckBox::indicator:checked {
image: url(:/pressed.png);
}
运行结果如下:
3. 输入框
设置输入框的边框,内边距和选中字体样式
属性 | 说明 |
---|---|
border-width | 设置边框宽度 |
border-radius | 设置边框圆角 |
border-color | 设置边框颜色 |
border-style | 设置边框风格 |
padding | 设置内边距,复合属性 |
color | 设置文字颜色 |
background | 设置背景颜色 |
selection-background-color | 设置选中文字的背景颜色 |
selection-color | 设置选中文字的字体颜色 |
示例样式代码如下:
QLineEdit {
border-width: 3px;
border-radius: 10px;
border-color: rgb(170, 255, 255);
border-style: solid;
padding: 0px 8px; /*上下内边距0,左右内边距8px*/
color: rgb(0, 0, 0);
background: rgb(255, 255, 255);
selection-background-color: rgb(0, 255, 255);
selection-color: rgb(0, 0, 0);
}
运行结果如下:
4. 列表
常见的列表的样式是,鼠标接触和鼠标按下
要点 | 说明 |
---|---|
::item | 选中 QListView 中的具体条目 |
::hover | 选中鼠标悬停的条目 |
:selected | 选中某个被选中的条目 |
background | 设置背景颜色 |
border | 设置边框 |
qlineargradient | 设置渐变色 |
qlineargradient渐变色
有 6个参数
x1, y1
:标注一个起点
x2, y2
:标注一个终点
这两个点描述了一个“方向”
例如:
- x1 = 0, y2 = 0,x2 = 0,y2 = 1 即(0, 0) -> (0, 1):表示垂直方向从上到下,进行颜色渐变
- x1 = 0, y1 = 0, x2 = 1, y2 = 0 即(0, 0) -> (1, 0):表示水平方向从左往右,进行颜色渐变
- x1 = 0, y1 = 0, x2 = 1, y2 = 1即(0, 0) -> (1, 1):表示从左上往右下方向,进行颜色渐变
最后两个参数是
stop0
和stop1
,描述两个颜色,渐变过程就是从 stop0 往 stop1 进行渐变
样式代码如下:
QListWidget::item:hover {
/*设置从左往右的浅蓝渐变浅紫*/
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgb(170, 255, 255), stop: 1 rgb(170, 170, 255));
color: rgb(0, 0, 0);
}
QListWidget::item:selected {
border: 1px solid rgb(170, 0, 255);
/*设置从左往右的深蓝渐变深紫*/
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 rgb(0, 255, 255), stop: 1 rgb(170, 85, 255));
color: rgb(0, 0, 0);
}
运行结果如下:
5. 菜单栏
要点 | 说明 |
---|---|
QMenuBar::item | 菜单栏中的元素 |
QMenuBar::item:selected | 菜单栏中被选中的元素 |
QMenuBar::item:pressed | 菜单栏中被鼠标点击的元素 |
QMenu::item | 菜单项 |
QMenu::item:selected | 被选中的菜单项 |
QMenu::separator | 菜单中的分割线 |
初始菜单外观如下:
样式代码如下:
QMenuBar {
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(170, 255, 255), stop: 1 rgb(170, 170, 255));
spacing: 3px;/*菜单项之间的间隔*/
}
/*QMenuBar的item就是QMenu*/
QMenuBar::item {
color: rgb(0, 0, 0);
border-radius: 3px;/*边角弧度*/
}
QMenuBar::item:selected {
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(0, 255, 255), stop: 1 rgb(170, 85, 255));
}
/*QMenu的item就是QAction*/
QMenu::item {
padding: 2px 25px 2px 20px;
border: 3px solid transparent;
}
QMenu::item:selected {
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(85, 255, 255), stop: 1 rgb(85, 85, 255));
}
/*分隔线*/
QMenu::separator {
height: 2px;
background: black;
margin-left: 10px;
margin-right: 5px;
}
运行结果如下:
6. 登录界面
- 设置 UI文件,添加控件如下:
因为QWidget无法设置背景图片,所以需要再QWidget上套一层 QFrame,将背景图片设置到 QFrame上即可
- 使用 qrc文件管理图片资源
- 使用 QSS 将背景设置到 QFrame上
.QFrame {
border-image: url(:/night_view.jpg);
}
因为 QFrame 上还有 QLabel,若选择器使用 QFrame类型选择器,会影响其子控件,即QLabel的背景也会被设置上图片,所以此处选择类选择器
- 设置输入框样式
QLineEdit {
color: rgb(0, 0, 0);
background-color: rgb(170, 255, 255);
padding: 0px 5px;
font-size: 15px;
border-style: solid;
border-radius: 8px;
}
再设置 placeholderText 和 密码部分还要设置 回显模式为 Password
- 设置复选框样式
QSS代码如下:
QCheckBox {
color: white;
/*transparent表示完全透明(应用父元素的背景)*/
background-color: transparent;
}
- 设置按钮样式
QPushButton {
font-size: 15px;
color: white;
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(170, 255, 255), stop: 1 rgb(170, 170, 255));
border-style: outset;
border-radius:8px;
}
QPushButton:pressed {
font-size: 15px;
color: white;
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(0, 255, 255), stop: 1 rgb(170, 85, 255));
}
最终一个界面的样式代码,建议放在一起
.QFrame {
border-image: url(:/night_view.jpg);
}
QLineEdit {
color: rgb(0, 0, 0);
background-color: rgb(170, 255, 255);
padding: 0px 5px;
font-size: 15px;
border-style: solid;
border-radius: 8px;
}
QCheckBox {
color: white;
background-color: transparent;
}
QPushButton {
font-size: 15px;
color: white;
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(170, 255, 255), stop: 1 rgb(170, 170, 255));
border-style: outset;
border-radius:8px;
}
QPushButton:pressed {
font-size: 15px;
color: white;
background-color: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop: 0 rgb(0, 255, 255), stop: 1 rgb(170, 85, 255));
}
总结
QSS 本身给 Qt 提供了更丰富的样式设置的能力,但想要做出好看的界面,光靠QSS 是不够的,更重要的是需要专业美工
更多参考文档:
- 官方文档中的
Qt Style Sheets Examples
章节 - QSS
感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。