QT -- QSS界面优化

目录

背景介绍

在网页前端开发领域中, CSS 是⼀个至关重要的部分. 描述了⼀个网页的 "样式". 从而起到对网页美化的作用。

所谓样式, 包括不限于大小, 位置, 颜色, 背景, 间距, 字体等等

网页开发作为 GUI 的典型代表, 也对于其他客户端 GUI 开发产生了影响. Qt 也是其中之⼀。

Qt 仿照 CSS 的模式, 引入了 QSS, 来对 Qt 中的控件做出样式上的设定, 从而允许程序猿写出界面更好看的代码。

同样受到 HTML 的影响, Qt 还引入了 QML 来描述界面, 甚至还可以直接把⼀个原生的 html 页面加载到界面上。

当然, 由于 Qt 本身的设计理念和网页前端还是存在⼀定差异的, 因此 QSS 中只能支持部分 CSS 属性.整体来说 QSS 要比 CSS 更简单⼀些。

注意:如果通过 QSS 设置的样式和通过 C++ 代码设置的样式冲突, 则 QSS 优先级更高。

基本语法

对于 QSS 来说, 基本的语法结构非常简单。

复制代码
选择器 {
 属性名: 属性值; 
}

其中:

  • 选择器描述了 "哪个 widget 要应用样式规则"
  • 属性则是⼀个键值对, 属性名表示要设置哪种样式, 属性值表示了设置的样式的值

QSS 设置方式

指定控件样式设置

QWidget 中包含了 setStyleSheet 方法, 可以直接设置样式。

案例:给按钮设置字体颜色

c 复制代码
ui->pushButton->setStyleSheet("QPushButton {color: green}");

注意:如果我们给当前控件设置了样式,那么该控件的子空间也会继承该样式。

案例:给Widget设置样式,界面中的按钮控件(父元素是Widget)也会被设置样式。

c 复制代码
this->setStyleSheet("QWidget{ color: red; }");//给Widget控件设置字体颜色为红色

全局样式设置

还可以通过 QApplicationsetStyleSheet 方法设置整个程序的全局样式。

全局样式优点:

  • 使同⼀个样式针对多个控件生效, 代码更简洁.
  • 所有控件样式内聚在⼀起, 便于维护和问题排查.

案例:给所有按钮添加字体颜色

复制代码
//main.cpp中
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyleSheet("QPushButton{color:red;}");
    Widget w;
    w.show();
    return a.exec();
}

运行程序, 可以看到此时三个按钮的颜色都设置为红色了。

注意:如果设置了全局样式,又在某一个控件里面设置了单独的样式,此时,这两方面的样式会叠加起来。如果设置了全局样式,某一个控件的样式和全局样式产生了冲突,此时控件的样式优先级更高。

从文件加载样式表

上述代码都是把样式通过硬编码的方式设置的. 这样使 QSS 代码和 C++ 代码耦合在⼀起了, 并不方便代码的维护.因此更好的做法是把样式放到单独的文件中, 然后通过读取文件的方式来加载样式

案例:从文件中加载全局样式。

(1)自己手动创建qss文件,QT creator并没有提供。

(2)创建 resource.qrc 文件, 并设定前缀为 / ,并添加resource.qss文件

(3) 使用Qt Creator 打开 resource.qss , 编写内容

(4) 修改 main.cpp, 新增⼀个函数用来加载样式

c 复制代码
QString loadQss()
{
    //创建QFile对象
    QFile file(":/resource.qss");
    //打开文件
    file.open(QFile::ReadOnly);
    if(!file.isOpen())
    {
        qDebug()<<"文件打开失败";
        exit(1);
    }
    QString style = file.readAll();
    //关闭文件
    file.close();
    return style;
}

(5)修改 main.cpp, 在 main 函数中调用上述函数, 并设置样式

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyleSheet(loadQss());
    Widget w;
    w.show();
    return a.exec();
}

(6)运行程序,和设置全局样式一样,三个按钮的字体颜色都是红色


使用 Qt Designer 编辑样式

QSS 也可以通过 Qt Designer 直接编辑, 从而起到实时预览的效果. 同时也能避免 C++ 和QSS 代码的耦合。

案例:改变字体大小

(1)选中控件,点击鼠标右键,选择样式表。

通过这里就可以编写QSS样式了,在这里的修改会被编辑到ui文件中,程序运行时自动生效,而且这里还能进行实时预览。

(2)设置字体大小样式样式

(3)运行程序,看效果。

(4)这种方式设置样式, 样式内容会被以 xml 格式记录到 ui 文件中。

同时在控件的 styleSheet 属性中也会体现

样式设置有很对方法,但是如果最终效果不是我们想要的,我们可以从以下几个思考方向去查找问题所在。

  • 全局样式
  • 指定控件的样式
  • qss文件样式
  • ui文件中的样式
    ...

选择器

QSS 的选择器支持持以下几种:

选择器类型 示例 说明
全局选择器 * 选择所有的 widget。
类型选择器 QPushButton 选择所有的 QPushButton 及其子类的控件。
类选择器 .QPushButton 选择所有的 QPushButton 控件,不会选择子类。
ID 选择器 #pushButton_2 选择 objectNamepushButton_2 的控件。
后代选择器 QDialog QPushButton 选择 QDialog 的所有后代(子控件、孙子控件等)中的 QPushButton
子选择器 QDialog > QPushButton 选择 QDialog 的所有子控件中的 QPushButton
并集选择器 QPushButton, QLineEdit, QComboBox 选择 QPushButtonQLineEditQComboBox 这三种控件。
属性选择器 QPushButton[flat="false"] 选择所有 QPushButton 中,flat 属性为 false 的控件。
总体来说, QSS 选择器的规则和 CSS 选择器基本⼀致.

类型选择器

使用类型选择器时,子列的样式也会改变。

案例:通过修改QWidget样式,来修改子类的样式。

(1)创建一个按钮

(2)给QWidget设置全局样式,修改字体颜色为红色

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyleSheet("QWidget{color:red}");
    Widget w;
    w.show();
    return a.exec();
}

(3)运行程序,QWidget按钮的背景颜色变成了红色

类选择器

在上述案例中,如果我们将类型选择器修改为类选择器,就不会影响到子类的样式了。

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    a.setStyleSheet(".QWidget{color:red}");
    Widget w;
    w.show();
    return a.exec();
}

此时按钮的颜色不会发生改变. 此时只是选择 QWidget 类, 而不会选择 QWidget 的子类

QPushButton了.

ID 选择器

ID选择器可以只针对一个控件来进行样式设置。

案例:三个按钮中,使用ID选择器来设置一个按钮的样式。

(1)创建三个按钮

(2)使用一个类型选择器设置按钮的字体颜色为红色

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style = "QPushButton{color:red;}";
    a.setStyleSheet(style);
    Widget w;
    w.show();
    return a.exec();
}

(3)使用id选择器设置一个按钮的字体颜色为绿色,id就是控件的objectName

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style = "QPushButton{color:red;}";
    style += "#pushButton{color:green;}";
    a.setStyleSheet(style);
    Widget w;
    w.show();
    return a.exec();
}

(4)程序运行结果

  • 当某个控件同时被类型选择器和 ID 选择器设置了冲突样式时,ID 选择器的样式优先级更高。类似地,当多个不同类型的选择器作用于同一个控件并发生样式冲突时,也会涉及优先级问题。
  • Qt 官方文档中有关于优先级规则的具体说明(参见 The Style Sheet Syntax 中的 Conflict Resolution 章节),但这些规则计算起来非常复杂(类似于 CSS 中的优先级机制)。
  • 实践中可以简单理解为:选择器描述的范围越精准,其优先级越高。一般来说,ID 选择器的优先级是最高的。

并集选择器

每个逗号前的部分都是一个完整的、独立的选择器,它们可以是类型选择器、类选择器、ID选择器等。每个选择器独立地在控件树上进行匹配。

案例:通过Label、Line Text、PushButton三个控件来演示并集选择器的效果

(1)创建三个控件

(2)通过设置全局样式来修改字体颜色

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style = "QPushButton,QLabel,QLineEdit{color:red;}";
    a.setStyleSheet(style);
    Widget w;
    w.show();
    return a.exec();
}

(3)程序运行结果

并集选择器是⼀种很好的代码复用的方式. 很多时候我们希望界面上的多个元素风格是统⼀

的, 就可以使用并集选择器, 把样式属性同时指定给多种控件。


子控件选择器 (Sub-Controls)

有些控件内部包含了多个 "子控件" . 比如 QComboBox 的下拉后的⾯板, 比如 QSpinBox 的上下按钮等。可以通过子控件选择器 :: , 针对上述子控件进行样式设置.

哪些控件拥有哪些⼦控件, 参考⽂档 Qt Style Sheets ReferenceList of Sub-Controls 章节

案例:调整下拉框的子控件

(1)创建Combo Box控件

(2)添加图片到resource.qrc文件中

(3)修改Combo Box子控件图片样式

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style = "QComboBox::down-arrow{image:url(:/down.png);}";
    a.setStyleSheet(style);
    Widget w;
    w.show();
    return a.exec();
}

(4)显示效果

伪类选择器 (Pseudo-States)

伪类选择器, 是根据控件所处的某个状态被选择的. 例如按钮被按下, 输入框获取到焦点, 鼠标移动到某个控件上等。

  • 当状态具备时, 控件被选中, 样式生效.
  • 当状态不具备时, 控件不被选中, 样式失效.

使用 : 的方式定义伪类选择器.

常用的伪类选择器

伪类选择器 说明
:hover 鼠标放到控件上
:pressed 鼠标左键按下时
:focus 获取输入焦点时
:enabled 元素处于可用状态时
:checked 被勾选时
:read-only 元素为只读状态时

这些状态可以使用! 来取反. 比如 :!hover 就是鼠标离开控件时, :!pressed 就是鼠标松开时,等等.

更多伪类选择器的详细情况, 参考 Qt Style Sheets ReferencePseudo-States 章节.

案例:对按钮控件的三种不同的状态进行样式设置。

(1)创建一个按钮控件

(2)设置全局样式,使用伪类选择器对鼠标按下press和鼠标悬停hover两种状态进行样式设置

c 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style = "QPushButton{color:green}";//类型选择器
    style += "QPushButton:hover{color:red}";
    style += "QPushButton:pressed{color:blue}";
    a.setStyleSheet(style);
    Widget w;
    w.show();
    return a.exec();
}

(3)效果展示

同样,上述代码也可以使用事件的方式来实现.

样式属性

QSS 中的样式属性非常多, 不需要都记住. 核心原则还是用到了就去查.

大部分的属性和 CSS 是非常相似的。

文档的 Qt Style Sheets Reference 章节详细介绍了哪些控件可以设置属性, 每个控件都能设置哪些属性等。

盒模型 (Box Model)

在文档的 Customizing Qt Widgets Using Style SheetsThe Box Model 章节介绍了盒模型。

⼀个遵守盒模型的控件, 由上述几个部分构成:

Content 矩形区域: 存放控件内容. 比如包含的⽂本/图标等.

Border 矩形区域: 控件的边框.

Padding 矩形区域: 内边距. 边框和内容之间的距离.

Margin 矩形区域: 外边距. 边框到控件 geometry 返回的矩形边界的距离

默认情况下, 外边距, 内边距, 边框宽度都是 0.

可以通过一些 QSS 属性来设置上述的边距和边框的样式。

QSS 属性 说明
margin 设置四个方向的外边距。复合属性。
padding 设置四个方向的内边距。复合属性。
border-style 设置边框样式。
border-width 边框的粗细。
border-color 边框的颜色。
border 复合属性,相当于 border-style + border-width + border-color

案例1:设置边框和内边距

(1)创建一个标签

(2)通过样式表来修改内边距和边框

border:3px solid red等价于border-width:3px,border-style:solid,border-color:red;三个属性的简写形式.

padding-left: 5px; 是给左侧设置内边距.

(3)运行程序,可以看出边框为红色,字体和边框之间的距离就是内边距

案例2:设置外边框

(1)创建一个按钮控件

(2)设置按钮位置,方便看出区别,添加外边框样式

c 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //设置按钮位置
    ui->pushButton->setGeometry(0,0,100,100);
    //设置外边框
    ui->pushButton->setStyleSheet("QPushButton{border:5px solid red;margin:20px}");
    qDebug()<<ui->pushButton->geometry();
}

(3)运行程序, 可以看到, 当前按钮的边框被外边距挤的缩小了. 但是获取到的按钮的Geometry 是不变的.

控件样式示例

案例:自定义按钮

(1)创建按钮控件

(2)修改样式表

(3)结果展示

属性值小结

属性 说明
font-size 设置文字大小。
border-radius 设置圆角矩形。数值越大,角越"圆"。
background-color 设置背景颜色。
相关推荐
JANGHIGH2 小时前
c++ 多线程(四)
开发语言·c++
小尧嵌入式2 小时前
C++模板
开发语言·c++·算法
仰泳的熊猫2 小时前
1120 Friend Numbers
数据结构·c++·算法·pat考试
BestOrNothing_20152 小时前
C++ 成员函数运算符重载深度解析
c++·八股·运算符重载·operator·this指针·const成员函数·const引用
ALex_zry2 小时前
C++中经典的定时器库与实现方式
开发语言·c++
槿花Hibiscus2 小时前
C++基础:session实现和http server类最终组装
服务器·c++·http·muduo
仰泳的熊猫2 小时前
1116 Come on! Let‘s C
数据结构·c++·算法·pat考试
BTU_YC3 小时前
python 内网部署
开发语言·python
千疑千寻~3 小时前
【QML】C++访问QML控件
c++·qml