目录
- 0.前言
- 1.基本语法
- 设置方式
- 1.指定控件样式设置
- 2.全局样式设置
- 3.从文件加载样式表
- 4.使⽤Qt Designer编辑样式
- 5.总结
- 3.选择器
- 1.选择器概况
- 2.子控件选择器
- 3.伪类选择器
0.前言
- Qt仿照CSS(层叠样式表)的模式,引⼊了QSS
- Qt本⾝的设计理念和⽹⻚前端还是存在⼀定差异的,因此QSS中只能⽀持部分CSS属性
- 整体来说QSS要⽐CSS更简单⼀些
- 注意:如果通过QSS设置的样式和通过C++代码设置的样式冲突,则QSS优先级更⾼
1.基本语法
-
语法:
- 对于CSS来说,基本的语法结构⾮常简单
选择器{ 属性名 : 属性值; }
- QSS沿⽤了这样的设定
选择器{ 属性名 : 属性值; }
- 对于CSS来说,基本的语法结构⾮常简单
-
说明:
-
选择器:描述了"哪个Widget要应⽤样式规则"
- 指定控件之后,此时的样式会针对这个指定控件生效,也会对其子控件生效
- 既要考虑到子控件,也要考虑到此时选择器是针对那个"类型"的控件
- 属性:是⼀个键值对,属性名表⽰要设置哪种样式,属性值表⽰了设置的样式的值
-
选择器:描述了"哪个Widget要应⽤样式规则"
-
示例:
QPushButton{ color : red; }
设置方式
1.指定控件样式设置
-
QWidget
中包含了setStyleSheet()
⽅法,可以直接设置样式 -
示例:
ui->pushButton->setStyleSheet("QPushButton { color: red; }");
2.全局样式设置
- 通过
QApplication
的setStyleSheet()
⽅法设置整个程序的全局样式 -
全局样式优点:
- 使同⼀个样式针对多个控件⽣效,代码更简洁
- 所有控件样式内聚在⼀起,便于维护和问题排查
-
示例:
int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setStyleSheet("QPushButton { color: red; }"); // ... }
-
如果设置了全局样式,然后在某个控件里又设置了其他的样式,会怎样?
- 两方面的样式会"叠加"起来 --> 样式的层叠特性
-
如果设置了全局样式,在某个控件里设置的样式和全局样式冲突了,会怎样?
- 局部样式的优先级更高,覆盖对应的全局样式
-
总结:
- 实际开发中,可以在全局样式中设置比较通用的样式,统一整个程序的界面风格
- 如果需要针对某个个控件进行微调,可以使用局部样式来做出调整
3.从文件加载样式表
- 上述方法都是把样式通过硬编码的⽅式设置的
- 这样使QSS代码和C++代码耦合在⼀起了,并不⽅便代码的维护
- 更好的做法是把样式放到单独的⽂件中,通过读取⽂件的⽅式来加载样式
-
示例:
QString LoadQSS() { QFile file(":/"); file.open(QFile::ReadOnly); QString style = file.readAll(); file.close(); return style; } int main(int argc, char *argv[]) { QApplication a(argc, argv); // 设置全局样式 a.setStyleSheet(LoadQSS()); // ... }
4.使⽤Qt Designer编辑样式
- QSS也可以通过Qt Designer直接编辑,从⽽起到实时预览的效果,同时也能避免C++和QSS代码的耦合
- 这种⽅式设置样式,样式内容会被以xml格式记录到ui⽂件中
- 具体操作本篇文章不做展开,在软件内部很容易就能知道如何操作
5.总结
- 当发现⼀个控件的样式不符合预期的时候,要记得排查这四个地⽅
- 全局样式(QApplication 设置的)
- 指定控件样式
- 指定控件父控件的样式(可能是从父控件继承过来的)
- QSS文件中的样式
- ui文件中的样式
- 实际开发中,如果需要设置样式,建议最好统一使用某一种方式来进行设置
3.选择器
1.选择器概况
- QSS的选择器⽀持以下⼏种,其规则和CSS选择器基本一致
-
全局选择器:选择所有的
widget
-
类型选择器(type selector):以
QPushButton
为例- 选择所有的
QPushButton
和其⼦类的控件
- 选择所有的
-
类选择器(class selector):以
.QPushButton
为例- 选择所有的
QPushButton
的控件,不会选择⼦类
- 选择所有的
-
ID选择器:以
#pushButton_2
为例- 选择
objectName
为pushButton_2
的控件 - 通过类型选择器和ID选择器设置了冲突的样式时,ID选择器样式优先级更⾼
- 选择
-
后代选择器:以
QDialog QPushButton
为例- 选择
QDialog
的所有后代(⼦控件,孙⼦控件等)中的QPushButton
- 选择
-
⼦选择器:以
QDialog>QPushButton
为例- 选择
QDialog
的所有⼦控件中的QPushButton
- 选择
-
并集选择器:以
QPushButton, QLineEdit, QComboBox
为例- 选择
QPushButton, QLineEdit, QComboBox
这三种控件,接下来的样式会针对这三种控件都⽣效 -
并集选择器是⼀种很好的代码复⽤的⽅式
- 很多时候希望界⾯上的多个元素⻛格是统⼀的,就可以使⽤并集选择器,把样式属性同时指定给多种控件
- 选择
-
属性选择器:以
QPushButton[flat="false"]
为例- 选择所有
QPushButton
中,flat
属性为false
的控件
- 选择所有
-
全局选择器:选择所有的
-
优先级问题?
-
简单总结:
- 选择器描述的范围越精准,则优先级越⾼
- ⼀般来说,ID选择器优先级是最⾼的
- Qt⽂档上有具体的优先级规则介绍(参⻅The Style Sheet Syntax的Conflict Resolution章节)
-
简单总结:
-
示例:
// QString style = "QPushButton { color: red; font-size: 50px; }"; // style += "#pushButton_2 { color: green;} "; // style += "#pushButton_3 { color: blue;} "; // 并集选择器:如果想要设置的属性一样,可以用以下代码 QString style = "#pushButton_2, QLineEdit, QLabel { color: red; }"; a.setStyleSheet(style);
2.子控件选择器
-
有些控件内部包含了多个"⼦控件"
-
例如:
QComboBox
的下拉后的⾯板、QSpinBox
的上下按钮等 - 哪些控件拥有哪些⼦控件,参考⽂档Qt Style Sheets Reference中List of Sub-Controls章节
-
例如:
- 可以通过⼦控件选择器
::
,针对上述子空间进行样式设置 -
示例:
QString style = "QComboBox::down-arrow { image: url(:/); }"; a.setStyleSheet(style);
3.伪类选择器
-
根据控件所处的某个状态被选择的,也可以理解为"伪状态选择器"
- 当状态具备时,控件被选中,样式⽣效
- 当状态不具备时,控件不被选中,样式失效
- 例如:按钮被按下、输⼊框获取到焦点、⿏标移动到某个控件上等
- 使⽤
:
的⽅式定义伪类选择器 -
常用的伪类选择器:
-
:hover
:鼠标放到控件上 -
:pressed
:⿏标左键按下时 -
:focus
:获取输⼊焦点时 -
:enabled
:元素处于可⽤状态时 -
:checked
:被勾选时 -
:read-only
:元素为只读状态时 - 以上状态都可以用
!
来取反-
例如:
:!hover
就是⿏标离开控件时,:!pressed
就是⿏标松开时
-
例如:
-
- 更多伪类选择器的详细情况,参考Qt Style Sheets Reference的Pseudo-States章节
- 此处同样的功能,事件也可以实现,但是用伪类选择器要比事件的方式简单很多
-
示例:
QString style = "QPushButton { color: red; } "; // 默认状态 style += "QPushButton:hover { color: green; } "; // 特定状态 style += "QPushButton:pressed { color: blue; }"; // 特定状态 a.setStyleSheet(style);