目录
1. QSS 概述
1.1 背景介绍
(1)在网页前端开发领域中,CSS 是一个至关重要的部分。描述了一个网页的 “样式”。从而起到对网页美化的作用。
- 所谓样式,包括不限于大小、位置、颜色、背景、间距、字体等等。
- 现在的网页很难找到没有 CSS 的。可以说让 “界面好看” 是⼀个刚需。
- 网页开发作为 GUI 的典型代表,也对于其他客户端 GUI 开发产生了影响。Qt 也是其中之一。
(2)Qt 仿照 CSS 的模式,引入了 QSS来对 Qt 中的控件做出样式上的设定,从而允许程序猿写出界面更好看的代码。
- 同样受到 HTML 的影响,Qt 还引入了 QML 来描述界面,甚至还可以直接把一个原生的 html 页面加载到界面上。
(3)当然,由于 Qt 本身的设计理念和网页前端还是存在一定差异的,因此 QSS 中只能支持部分 CSS 属性。 整体来说 QSS 要比 CSS 更简单⼀些。
- 注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突,则 QSS 优先级更高。
1.2 基本语法
(1)对于 CSS 来说,基本的语法结构非常简单:
选择器 {
属性名: 属性值;
}
- QSS 沿用了这样的设定:
选择器 {
属性名: 属性值;
}
- 其中:
- 选择器 描述了 “哪个 widget 要应用样式规则”。
- 属性 则是⼀个键值对,属性名表示要设置哪种样式,属性值表示了设置的样式的值。
(2)例如:
QPushButton { color: red; }
- 或者:
QPushButton {
color: red;
}
- 上述代码的含义表示,针对界面上所有的 QPushButton,都把文本颜色设置为 红色。
- 编写 QSS 时使用单行的格式和多行的格式均可。
(3)代码示例:QSS 基本使用。
- 在界面上创建⼀个按钮。
- 编写代码,设置样式。
Widget::Widget(QWidget *parent)
:QWidget(parent)
,ui(new Ui::Widget)
{
ui->setupUi(this);
ui->pushButton->setStyleSheet("QPushButton { color: red; }");
}
- 运行程序,观察效果。可以看到文本已经是红色了。
- 注意:上述代码中,我们是只针对这⼀个按钮通过 setStyleSheet 方法设置的样式。此时这个样式仅针对该按钮生效。如果创建其他按钮,其他按钮不会受到影响。
2. QSS 设置方式
2.1 指定控件样式设置
(1)QWidget 中包含了 setStyleSheet 方法,可以直接设置样式。上述代码我们已经演示了上述设置方式。
- 另一方面,给指定控件设置样式之后,该控件的子元素也会受到影响。
(2)代码示例:子元素受到影响。
- 在界面上创建一个按钮。
- 修改 widget.cpp,这次我们不再给按钮设置样式,而是给 Widget 设置样式 (Widget 是 QPushButton 的父控件)。
Widget::Widget(QWidget *parent)
:QWidget(parent)
,ui(new Ui::Widget)
{
ui->setupUi(this);
// 给 Widget 本⾝设置样式.
this->setStyleSheet("QPushButton { color: red;} ");
}
- 运行程序,可以看到样式对于子控件按钮同样会生效。
2.2 全局样式设置
(1)还可以通过 QApplication 的 setStyleSheet 方法设置整个程序的全局样式。全局样式优点:
- 使同⼀个样式针对多个控件生效,代码更简洁。
- 所有控件样式内聚在⼀起,便于维护和问题排查。
(2)代码示例:使用全局样式。
- 在界面上创建三个按钮。
- 编辑 main.cpp,设置全局样式。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QPushButton { color: red; }");
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以看到此时三个按钮的颜色都设置为红色了。
(3)代码示例:样式的层叠特性。
- 如果通过全局样式给某个控件设置了属性1,通过指定控件样式给控件设置属性2,那么这两个属性都会产生作用。
- 在界面上创建两个按钮。
- 编写 main.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,给第一个按钮设置字体大小。
Widget::Widget(QWidget *parent)
:QWidget(parent)
,ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置指定控件样式
ui->pushButton->setStyleSheet("QPushButton { font-size: 50px} ");
}
- 运行程序,可以看到,对于第⼀个按钮来说,同时具备了颜色和字体大小样式。而第二个按钮只有颜色样式。
- 说明针对第⼀个按钮,两种设置方式设置的样式叠加起来了。
- 形如上述这种属性叠加的效果,我们称为 “层叠性”。
- CSS 全称为 Cascading Style Sheets,其中 Cascading 就是 “层叠性” 的意思。QSS 也继承了这样的设定。
- 实际上把 QSS 叫做 QCSS 也许更合适⼀些。
(4)代码示例:样式的优先级。
- 如果全局样式和指定控件样式冲突,则指定控件样式优先展示。
- 在界面上创建两个按钮。
- 编辑 main.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,把第⼀个按钮样式设为绿色。
Widget::Widget(QWidget *parent)
:QWidget(parent)
,ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置第⼀个按钮颜⾊为绿⾊
ui->pushButton->setStyleSheet("QPushButton { color: green; }");
}
- 运行程序,观察效果。可以看到第⼀个按钮已经成为绿色了,但是第⼆个按钮仍然是红色。
- 在 CSS 中也存在类似的优先级规则。通常来说都是 “局部” 优先级高于 “全局” 优先级。
- 相当于全局样式先 “奠定基调”,再通过指定控件样式来 “特事特办”。
2.3 从文件加载样式表
(1)上述代码都是把样式通过硬编码的方式设置的。这样使 QSS 代码和 C++ 代码耦合在⼀起了,并不方便代码的维护。
- 因此更好的做法是把样式放到单独的文件中,然后通过读取文件的方式来加载样式。
(2)代码示例:从文件加载全局样式。
- 在界面上创建⼀个按钮。
- 创建 resource.qrc 文件,并设定前缀为 / 。
- 创建 style.qss 文件,并添加到 resource.qrc 中。
- style.qss 是需要程序运行时加载的。为了规避绝对路径的问题,仍然使用 qrc 的方式来组织。(即把资源文件内容打包到 cpp 代码中)。
- Qt Creator 没有提供创建 qss 文件的选项。咱们直接 右键 -> 新建文件 -> 手动设置文件扩展名为 qss 即可。
- 使用 Qt Creator 打开 style.qss,编写内容。
QPushButton {
color: red;
}
- 修改 main.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 函数中调用上述函数,并设置样式。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 调⽤上述函数加载样式
const QString& style = loadQSS();
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以看到样式已经生效了。
2.4 使用 Qt Designer 编辑样式
(1)QSS 也可以通过 Qt Designer 直接编辑,从而起到实时预览的效果。同时也能避免 C++ 和 QSS 代码的耦合。代码示例:使用 Qt Designer 编辑样式。
- 在界面上创建⼀个按钮。
- 右键按钮,选择 “改变样式表”。
- 在弹出的样式表编辑器中,可以直接填写样式。填写完毕,点击 OK 即可。
- 此时 Qt Designer 的预览界面就会实时显示出样式的变化。
- 运行程序,可以看到样式确实发生了改变。
- 这种方式设置样式,样式内容会被以 xml 格式记录到 ui 文件中。
property name="styleSheet">
<string notr="true">QPushButton { color: red; }</string>
</property>
- 同时在控件的 styleSheet 属性中也会体现。
- 当我们发现⼀个控件的样式不符合预期的时候,要记得排查这四个地方:
- 全局样式。
- 指定控件样式。
- qss 文件中的样式 。
- ui 文件中的样式。
3. 选择器
3.1 选择器概况
(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 选择器基本⼀致。
- 上述选择器咱们也不需要全都掌握,就只熟悉最常用的几个即可(上述加粗的)。
(2)代码示例:使用类型选择器选中子类控件。
- 在界面上创建⼀个按钮。
- 修改 main.cpp,设置全局样式。
- 注意:此处选择器使用的是 QWidget。QPushButton 也是 QWidget 的子类,所以会受到 QWidget 选择器的影响。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
a.setStyleSheet("QWidget { color: red; }");
Widget w;
w.show();
return a.exec();
}
- 运行程序,可以看到按钮的文本颜色已经是红色了。
- 如果把上述样式代码修改为下列代码:
a.setStyleSheet(".QWidget { color: red; }");
- 此时按钮的颜色不会发生改变。此时只是选择 QWidget 类,而不会选择 QWidget 的子类 QPushButton 了。
(3)代码示例:使用 id 选择器。
- 在界面上创建 3 个按钮,objectName 为 pushButton,pushButton_2,pushButton_3。
- 编写 main.cpp,设置全局样式。
- 先通过 QPushButton 设置所有的按钮为黄色。
- 再通过 #pushButton 和 #pushButton_2 分别设置这两个按钮为红色和绿色。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// 设置全局样式
QString style = "";
style += "QPushButton { color: yellow; }";
style += "#pushButton { color: red; }";
style += "#pushButton_2 { color: green; }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 执行程序,观察效果。
- 当某个控件身上通过类型选择器和 ID 选择器设置了冲突的样式时,ID 选择器样式优先级更高。
- 同理,如果是其他的多种选择器作用同⼀个控件时出现冲突的样式,也会涉及到优先级问题。
- Qt 文档上有具体的优先级规则介绍 (参见 The Style Sheet Syntax 的 Conflict Resolution 章节)。
- 这里的规则计算起来非常复杂(CSS 中也存在类似的设定),咱们此处对于优先级不做进⼀步讨论。
- 实践中我们可以简单的认为,选择器描述的范围越精准,则优先级越高。⼀般来说,ID 选择器优先级是最高的。
(4)代码示例:使用并集选择器。
- 创建按钮,label,单行输入框。
- 编写 main.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();
}
- 运行程序,可以看到这三种控件的文字颜色都设置为了红色。
- 并集选择器是⼀种很好的代码复用的方式。很多时候我们希望界面上的多个元素风格是统⼀的,就可以使用并集选择器,把样式属性同时指定给多种控件。
3.2 子控件选择器 (Sub-Controls)
(1)有些控件内部包含了多个 “子控件”。比如 QComboBox 的下拉后的面板,比如 QSpinBox 的上下按钮等。
- 可以通过子控件选择器 :: ,针对上述子控件进行样式设置。
- 哪些控件拥有哪些子控件,参考⽂档 Qt Style Sheets Reference 中 List of Sub-Controls 章节。
(2)代码示例:设置下拉框的下拉按钮样式。
- 在界面上创建一个下拉框,并创建几个选项。
- 创建 resource.qrc ,并导入图片 down.png。
- 图标可以从阿里巴巴矢量图标库下载:https://www.iconfont.cn/search/index?
searchType=icon&q=down - 修改 main.cpp,编写全局样式。
- 使用子控件选择器 QComboBox::down-arrow 选中了 QComboBox 的下拉按钮。
- 再通过 image 属性设置图。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString style = "";
style += "QComboBox::down-arrow { image: url(:/down.png) }";
a.setStyleSheet(style);
Widget w;
w.show();
return a.exec();
}
- 执行程序,观察效果。
(3)代码示例:修改进度条的颜色。
- 在界面上创建⼀个进度条。
- 在 Qt Designer 右侧的属性编辑器中,找到 QWidget 的 styleSheet 属性。编辑如下内容:
- 其中的 chunk 是选中进度条中的每个 “块”。使用 QProgressBar::text 则可以选中文本。
QProgressBar::chunk {background-color: #FF0000;}
- 同时把 QProcessBar 的 alignment 属性设置为垂直水平居中。
- 此处如果不设置 alignment,进度条中的数字会跑到左上角。这个怀疑是 Qt 本身的 bug,暂时只能先使用 alignment 来手动调整下。
- 执行程序,可以看到如下效果。我们就得到了一个红色的进度条。
- 通过上述方式,也可以修改文字的颜色,字体大小等样式。
3.3 伪类选择器 (Pseudo-States)
(1)伪类选择器是根据控件所处的某个状态被选择的。例如按钮被按下,输入框获取到焦点,鼠标移动到某个控件上等。
- 当状态具备时,控件被选中,样式生效。
- 当状态不具备时,控件不被选中,样式失效。
- 使用 : 的方式定义伪类选择器。
(2)常用的伪类选择器:
伪类选择器 | 说明 |
---|---|
:hover | 鼠标放到控件上 |
:pressed | 鼠标左键按下时 |
:focus | 获取输入焦点时 |
:enabled | 元素处于可用状态时 |
:checked | 被勾选时 |
:read-only | 元素为只读状态时 |
- 这些状态可以使用 ! 来取反。比如 :!hover 就是鼠标离开控件时,:!pressed 就是鼠标松开时等等。
- 更多伪类选择器的详细情况参考 Qt Style Sheets Reference 的 Pseudo-States 章节。
(3)代码示例:设置按钮的伪类样式。
- 在界面上创建⼀个按钮。
- 编写 main.cpp,创建全局样式。
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();
}
- 运行程序,可以看到,默认情况下按钮文字是红色,鼠标移动上去是绿色,鼠标按下按钮是蓝色。
- 上述代码也可以使用事件的方式来实现。
(4)代码示例:使用事件方式实现同样效果。
- 创建 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 的四个事件处理函数。修改 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);
}
- 修改 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; }");
}
- 运行程序,可以看到效果和上述案例⼀致:
- 很明显实现同样的功能,伪类选择器要比事件的方式简单很多。
- 但是不能就说事件机制就不好。事件可以完成的功能很多,不仅仅是样式的改变,还可以包含其他业务逻辑。这⼀点是伪类选择器无法替代的。
4. 样式属性
4.1 QSS 样式属性概述
(1)QSS 中的样式属性非常多,不需要都记住。核心原则还是用到了就去查。
- 大部分的属性和 CSS 是非常相似的。
- 文档的 Qt Style Sheets Reference 章节详细介绍了哪些控件可以设置属性, 每个控件都能设置哪些属性等。
- 相关的代码示例在后面具体介绍。
- 在翻阅文档的时候涉及到⼀个关键术语 “盒模型” (Box Model)。这里我们需要介绍⼀下。
4.2 盒模型 (Box Model)
(1)在文档的 Customizing Qt Widgets Using Style Sheets 的 The Box Model 章节介绍了盒模型。
(2)一个遵守盒模型的控件,由上述几个部分构成:
- Content 矩形区域:存放控件内容。比如包含的文本/图标等。
- Border 矩形区域:控件的边框。
- Padding 矩形区域:内边距。边框和内容之间的距离。
- Margin 矩形区域:外边距。边框到控件 geometry 返回的矩形边界的距离。
- 默认情况下,外边距,内边距,边框宽度都是 0。
(3)可以通过一些 QSS 属性来设置上述的边距和边框的样式。
QSS 属性 | 说明 |
---|---|
margin | 设置四个方向的外边距、复合属性。 |
padding | 设置四个方向的内边距。复合属性。 |
border-style | 设置边框样式。 |
border-width | 边框的粗细。 |
border-color | 边框的颜色。 |
border | 复合属性,相当于 border-style + border-width + border-color。 |
(4)代码示例:设置边框和内边距。
- 在界面上创建⼀个 label。
- 修改 main.cpp, 设置全局样式:
- border: 5px solid red 相当于 border-style: solid; border-width: 5px;
- border-color: red; 三个属性的简写形式。
- padding-left: 10px; 是给左侧设置内边距。
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();
}
- 运行程序,可以看到样式发生了变化。
(5)代码示例:设置外边距。
- 为了方便确定控件位置,演示外边距效果,我们使用代码创建⼀个按钮。
- 修改 widget.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 是不变的。
5. 控件样式示例
(1)下面给出一些常用控件的样式示例。
5.1 按钮
(1)代码示例:自定义按钮。
- 界面上创建⼀个按钮。
- 右键 -> 改变样式表,使用 Qt Designer 设置样式。
QPushButton {
font-size: 20px;
border: 2px solid #8f8f91;
border-radius: 15px;
background-color: #dadbde;
}
QPushButton:pressed {
background-color: #f6f7fa;
}
- 执行程序,可以看到效果。
(2)属性小结:
属性 | 说明 |
---|---|
font-size | 设置文字大小。 |
border-radius | 设置圆角矩形。数值设置的越大,角就 “越圆”。 |
background-color | 设置背景颜色。 |
- 形如 #dadbde 是计算机中通过十六进制表示颜色的方式。
5.2 复选框
(1)代码示例:自定义复选框。
- 创建⼀个 resource.qrc 文件,并导入以下图片。
- 使用黑色作为默认形态。
- 使用蓝色作为 hover 形态。
- 使用红色作为 pressed 形态。
- 注意这里的文件命名。
- 使用阿里矢量图标库,可以下载到上述图片。下载的时候可以手动选择颜色。
- 创建⼀个复选框:
- 编辑复选框的样式:
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);
}
- 运行程序,可以看到此时的复选框就变的丰富起来了。
- 此处截图看不出来效果。
(2)小结:
要点 | 说明 |
---|---|
::indicator | 子控件选择器。选中 checkbox 中的对钩部分。 |
:hover | 伪类选择器。选中鼠标移动上去的状态。 |
:pressed | 伪类选择器。选中鼠标按下的状态。 |
:checked | 伪类选择器。选中 checkbox 被选中的状态。 |
:unchecked | 伪类选择器。选中 checkbox 未被选中的状态。 |
width | 设置子控件宽度。对于普通控件无效 (普通控件使用 geometry 方式设定尺寸)。 |
height | 设置子控件高度。对于普通控件无效 (普通控件使用 geometry 方式设定尺寸)。 |
image | 设置子控件的图片。像 QSpinBox,QComboBox 等可以使用这个属性来设置子控件的图片。 |
5.3 单选框
(1)代码示例:自定义单选框。
- 创建 resource.qrc 文件,并导入以下图片。
- 使用黑色作为默认形态。
- 使用蓝色作为 hover 形态。
- 使用红色作为 pressed 形态。
- 注意这里的文件命名。
- 在界面上创建两个单选按钮。
- 在 Qt Designer 中编写样式:
- 此处为了让所有 QRadioButton 都能生效,把样式设置在 Widget 上了。并且使用后代选择器选中了 QWidget 里面的 QRadioButton。
- 注意!!
- QSS 中有些属性,子元素能继承父元素(例如 font-size, color 等)。但是也有很多属性是不能继承的。
- 具体哪些能继承哪些不能继承,规则比较复杂,咱们不去具体研究。实践中我们编写更精准的选择器是上策。
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);
}
- 运行程序,观察效果。
- 此处截图看不出来效果。
(2)小结:
要点 | 说明 |
---|---|
::indicator | 子控件选择器。选中 radioButton 中的对钩部分。 |
:hover | 伪类选择器。选中鼠标移动上去的状态。 |
:pressed | 伪类选择器。选中鼠标按下的状态。 |
:checked | 伪类选择器。选中 radioButton 被选中的状态。 |
:unchecked | 伪类选择器。选中 radioButton 未被选中的状态。 |
width | 设置子控件宽度。对于普通控件无效 (普通控件使用 geometry 方式设定尺寸)。 |
height | 设置子控件高度。对于普通控件无效 (普通控件使用 geometry 方式设定尺寸)。 |
image | 设置子控件的图片。像 QSpinBox,QComboBox 等可以使用这个属性来设置子控件的图片。 |
5.4 输入框
(1)代码示例:自定义单行编辑框。
- 在界面上创建⼀个单行编辑框。
- 在 Qt Designer 中编写样式。
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);
}
- 执行程序观察效果。
(2)小结:
属性 | 说明 |
---|---|
border-width | 设置边框宽度。 |
border-radius | 设置边框圆角。 |
border-color | 设置边框颜色。 |
border-style | 设置边框风格。 |
padding | 设置内边距。 |
color | 设置文字颜色。 |
background | 设置背景颜色。 |
selection-background-color | 设置选中文字的背景颜色。 |
selection-color | 设置选中文字的文本颜色。 |
5.5 列表
(1)代码示例:自定义列表框。
- 在界面上创建⼀个 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);
}
- 执行程序,观察效果。
(2)小结:
要点 | 说明 |
---|---|
::item | 选中 QListView 中的具体条目。 |
:hover | 选中鼠标悬停的条目。 |
:selected | 选中某个被选中的条目。 |
background | 设置背景颜色。 |
border | 设置边框。 |
qlineargradient | 设置渐变色。 |
(3)关于 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 进行渐变的。
(4)代码例子:理解渐变色。
- 界面不创建任何控件。
- 编写样式。
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);
}
- 当前按照 水平从左往右 从 白色 过渡到 黑色。
- 执行效果。
5.6 菜单栏
(1)代码示例:自定义菜单栏。
- 创建菜单栏。
创建若干菜单项和一个分隔符。
- 编写样式。
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;
}
- 执行程序,观察效果。
(2)小结:
要点 | 说明 |
---|---|
QMenuBar::item | 选中菜单栏中的元素。 |
QMenuBar::item:selected | 选中菜单来中的被选中的元素。 |
QMenuBar::item:pressed | 选中菜单栏中的鼠标点击的元素。 |
QMenu::item | 选中菜单中的元素。 |
QMenu::item:selected | 选中菜单中的被选中的元素。 |
QMenu::separator | 选中菜单中的分割线。 |
5.7 登录界面
(1)基于上述学习过的 QSS 样式,制作⼀个美化版本的登录界面。
- 在界面上创建元素。
- 使用布局管理器,把上述元素包裹⼀下。
- 使用 QVBoxLayout 来管理上述控件。
- 两个输入框和按钮的 minimumHeight 均设置为 50。(元素在布局管理器中无法直接设置 width 和 height,使用 minimumWidth 和 minimumHeight 代替,此时垂直方向的 sizePolicy 要设为 fixed)。
- 右键 QCheckBox,选择 Layout Alignment 可以设置 checkbox 的对齐方式(左对齐,居中对齐,右对齐)。
- 设置背景图片。
- 把上述控件添加⼀个父元素 QFrame,并设置 QFrame 和 窗口⼀样大。
顶层窗口的 QWidget 无法设置背景图片。因此我们需要再套上⼀层 QFrame。背景图片就设置到 QFrame 上即可。
- 创建 resource.qrc,并导入图片。
- 编写 QSS 样式:
- 使用 border-image 设置背景图片,而不是 background-image。主要是因为 borderimage 是可以自动缩放的。这⼀点在窗口大小发生改变时是非常有意义的。
QFrame {
border-image: url(:/cat.jpg);
}
- 此时效果为:
- 设置输入框样式。编写 QSS 代码:
QLineEdit {
color: #8d98a1;
background-color: #405361;
padding: 0 5px;
font-size: 20px;
border-style: none;
border-radius: 10px;
}
- 运行程序效果:
- 设置 checkbox 样式:背景色使用 transparent 表示完全透明 (应用父元素的背景)。
QCheckBox {
color: white;
background-color: transparent;
}
- 执行效果。
- 设置按钮样式。
QPushButton {
font-size: 20px;
color: white;
background-color: #555;
border-style: outset;
border-radius: 10px;
}
QPushButton:pressed {
color: black;
background-color: #ced1db;
border-style: inset;
}
- 执行程序。
- 最终完整样式代码。这些代码设置到 QFrame 的属性中即可。通常我们建议把样式代码集中放置,方便调整和排查。
QFrame {
border-image: url(:/cat.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: #555;
border-style: outset;
border-radius: 10px;
}
QPushButton:pressed {
color: black;
background-color: #ced1db;
border-style: inset;
}
6. QSS 小结
(1)QSS 本十年给 Qt 提供了更丰富的样式设置的能力,但是整体来说 QSS 的功能是不如 CSS 的。
- 在 CSS 中,整个网页的样式都是 CSS ⼀手负责,CSS 功能更强大,并且也更可控。
- 相比之下,Qt 中是以原生 api 为主,来控制控件之间的尺寸,位置等,QSS 只是起到辅助的作用。
- 而且 Qt 中提供的⼀些 “组合控件” (像 QComboBox, QSpinBox 等) 内部的结构是不透明的,此时进行⼀些样式设置也会存在⼀定的局限性。
- 另外,做出好看的界面,光靠 QSS 是不够的。更重要的是需要专业美工做出设计稿。
- 因此通过 QSS 的学习,我们的目的是了解这个技术,而不要求大家立即就能做出非常好看的界面。
(2)更多参考内容:
- 官方文档中的 Qt Style Sheets Examples 章节。
- https://github.com/GTRONICK/QSS
(3)Qt 的绘图见博客:https://blog.csdn.net/m0_65558082/article/details/147825991?spm=1001.2014.3001.5502