当前位置: 首页 > news >正文

Qt 界面优化(QSS)

目录

  • 1. QSS 概述
    • 1.1 背景介绍
    • 1.2 基本语法
  • 2. QSS 设置方式
    • 2.1 指定控件样式设置
    • 2.2 全局样式设置
    • 2.3 从文件加载样式表
    • 2.4 使用 Qt Designer 编辑样式
  • 3. 选择器
    • 3.1 选择器概况
    • 3.2 子控件选择器 (Sub-Controls)
    • 3.3 伪类选择器 (Pseudo-States)
  • 4. 样式属性
    • 4.1 QSS 样式属性概述
    • 4.2 盒模型 (Box Model)
  • 5. 控件样式示例
    • 5.1 按钮
    • 5.2 复选框
    • 5.3 单选框
    • 5.4 输入框
    • 5.5 列表
    • 5.6 菜单栏
    • 5.7 登录界面
  • 6. QSS 小结

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 的绘图见博客

http://www.xdnf.cn/news/382681.html

相关文章:

  • 【数据结构与算法】——图(二)
  • 《AI大模型应知应会100篇》第54篇:国产大模型API对比与使用指南
  • 【Redis】基础命令数据结构
  • Spring框架核心知识全解析:从基础到实战
  • [面试]SoC验证工程师面试常见问题(六)高速接口篇
  • 含锡电镀废水深度净化技术体系解析化利用的全流程优化
  • pytest自动化测试执行环境切换的两种解决方案
  • 树莓派OS系统详解
  • 动态规划法:爬楼梯
  • C++模板梳理
  • JAVA练习题(3) 开发验证码
  • 如何避免软件腐朽
  • jflash下载时出现 Could not read unit serial number! 的解决方法
  • 数据结构—(概述)
  • 【typenum】 1 说明文件(README.md)
  • 【AI论文】迈向多模态通才之路:通用层级与通用基准
  • 一文讲透MCP的原理及实践
  • Kubernetes生产实战(十二):无工具容器网络连接数暴增指南
  • 【Day 24】HarmonyOS端云一体化开发:云函数
  • C PRIMER PLUS——第8节:字符串和字符串函数
  • 初等数论--欧拉定理及证明
  • 计算最短路径的数量模板(最短路)
  • 【智能指针】
  • 前端项目中单元测试与集成测试的管理实践
  • 基于51单片机的模拟洗衣机控制面板proteus仿真
  • JavaScript篇:async/await 错误处理指南:优雅捕获异常,告别失控的 Promise!
  • Java并发编程,从线程安全到死锁避免的实战解析
  • Java代码日志嵌入打包时间
  • 【排错】dify1.3.1插件市场安装报错问题
  • 《从零开始:构建你的第一个区块链应用》