[Qt] QSS | Qt Designer | 选择器

devtools/2025/1/18 23:21:52/

目录

一、CSS

1、背景介绍

2、基本语法

3、QSS 设置方式

(1)指定控件样式设置

(2)全局样式设置

(3)从文件加载样式表

(4)使用 Qt Designer 编辑样式

4、选择器

(1)选择器概况

(2)子控件选择器(Sub-Controls)

(3)伪类选择器(Pseudo-States)


一、CSS

1、背景介绍

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

  • 所谓样式,包括不限于大小、位置、颜色、背景、间距、字体等等。
  • 现在的网页很难找到没有 CSS 的,可以说让 “界面好看” 是一个刚需。
  • 对于针对特定专业领域用户的软件产品,界面设计是否重要?
  • 可参考:(11 封私信 / 80 条消息) 对于针对特定专业领域用户的软件产品,界面设计是否重要? - 知乎 (zhihu.com)

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

  • Qt 仿照 CSS 的模式,引入了 QSS,来对 Qt 中的控件做出样式上的设定,从而允许我们写出界面更好看的代码。
  • 同样受到 HTML 的影响,Qt 还引入了 QML 来描述界面,甚至还可以直接把一个原生的 html 页面加载到界面上。
  • 当然,由于 Qt 本身的设计理念和网页前端还是存在一定差异的,因此 QSS 中只能支持部分 CSS 属性。整体来说 QSS 要比 CSS 更简单一些。

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


2、基本语法

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

QSS 沿用了其设定:

选择器 {属性名: 属性值; 
}

其中:

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

例如:

QPushButton { color: red; }
//或者:
QPushButton {color: red;
}

上述代码的含义表示,针对界面上所有的 QPushButton,都把文本颜色设置为红色。

编写 QSS 时使用单行 和多行的格式均可。


【QSS 基本使用】

(1)在界面上创建一个按钮

(2)编写代码,设置样式

在.cpp 文件中设置:

ui->setupUi(this);
ui->pushButton->setStyleSheet("QPushButton {color:green;}");

(3)运行程序

观察效果,可以看到文本已经是绿色了:

注意:上述代码中,只针对这一个按钮通过 setStyleSheet 方法设置的样式,此时这个样式仅针对该按钮生效。如果创建其他按钮,其他按钮不会受到影响。

其它格式:


3、QSS 设置方式

(1)指定控件样式设置

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

另一方面,给指定控件设置样式之后,该控件的子元素也会受到影响。

【子元素受到影响】

A. 在界面上创建两个按钮和一个单行编辑框

B. 修改 widget.cpp

这次不再给按钮设置样式,而是给 Widget 设置样式(Widget 是 QPushButton 的父控件):

C. 运行程序

可以看到样式对于 this 的子控件按钮同样会生效,但是必须是和选择器相关的。


(2)全局样式设置

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

全局样式优点:

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

【使用全局样式】

A. 在界面上创建三个按钮

B. 编辑 main.cpp,设置全局样式

C. 运行程序

可以看到此时三个按钮的颜色都设置为红色了:

【样式的层叠特性】

如果通过全局样式给某个控件设置了属性 1,通过指定控件样式给控件设置属性 2,那么这两个属性都会产生作用

A. 在界面上创建三个按钮

B. 编写 main.cpp,设置全局样式,把按钮文本设置为红色

C. 编写 widget.cpp,给第一个按钮设置字体大小

ui->pushButton->setStyleSheet("QPushButton{font-size:50px;}");

D. 运行程序

可以看到,对于第一个按钮来说,同时具备了颜色和字体大小样式,而第二个按钮只有颜色样式。

说明针对第一个按钮,两种设置方式设置的样式叠加起来了。

形如上述这种属性叠加的效果被称为 “层叠性”。

CSS 全称为 Cascading Style Sheets,其中 Cascading 就是 “层叠性” 的意思,QSS 也继承了这样的设定。实际上把 QSS 叫做 QCSS 也许更合适一些。


【样式的优先级】

如果全局样式和指定控件样式冲突,则指定控件样式优先展示。

A. 在界面上创建三个按钮

B. 编辑 main.cpp,把全局样式设置为红色

C. 编辑 widget.cpp,把第二个按钮样式设为绿色

ui->pushButton_2->setStyleSheet("QPushButton{color:green;}");

D. 运行程序

观察效果,可以看到第二个按钮已经成为绿色了,但是第一个按钮和第三个按钮仍然是红色。

在 CSS 中也存在类似的优先级规则。通常来说都是 “局部” 优先级高于 “全局” 优先级,相当于全局样式先 “奠定基调”,再通过指定控件样式来 “特事特办”。

  • 实际开发中,可以在全局样式中设置比较通用的样式来统一整个程序的界面风格。
  • 如果需要针对某个控件进行微调,可以使用局部样式来做出调整。

(3)从文件加载样式表

上述代码都是把样式通过硬编码的方式设置的,这样使 QSS 代码和 C++ 代码耦合在一起了,并不方便代码的维护。

因此更好的做法是把样式放到单独的文件中,然后通过读取文件的方式来加载样式。

【从文件加载全局样式】

A. 在界面上创建一个按钮

B. 创建 resource.qrc 文件,并设定前缀为 /

C. 创建 style.qss 文件,并添加到 resource.qrc 中

  • style.qss 是需要程序运行时加载的。为了规避绝对路径的问题,仍然使用 qrc 的方式来组织(即把资源文件内容打包到 cpp 代码中)。
  • Qt Creator 没有提供创建 qss 文件的选项,直接 “右键” -> “新建” -> “文本文档”,手动设置文件扩展名为 qss 即可。

D. 使用 Qt Creator 打开 style.qss,编写内容

E. 修改 main.cpp,新增一个函数用来加载样式

#include <QFile>QString loadQSS() {QFile file(":/style.qss");file.open(QFile::ReadOnly);QString style = file.readAll();file.close();return style;
}

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

G. 运行程序

可以看到样式已经生效了:

理论上来说 Qt 应该要提供直接从文件加载样式表的接口。

类似于 setStyleSheetFromFile(const QString& path) 这种,在内部把读文件操作封好。


(4)使用 Qt Designer 编辑样式

QSS 也可以通过 Qt Designer 直接编辑,从而起到实时预览的效果

同时也能把 C++ 和 QSS 代码的解耦合。

【使用 Qt Designer 编辑样式】

A. 在界面上创建一个按钮

B. 选择最外层的窗口,右键按钮,选择 “改变样式表”

C. 在弹出的样式表编辑器中,可以直接填写样式,填写完毕点击 OK 即可

  • 这里进行的修改都会记录到 ui 文件中,并且在程序运行时自动生效,还能进行实时预览。

D. 此时 Qt Designer 的预览界面就会实时显示出样式的变化

E. 运行程序

可以看到样式确实发生了改变

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

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

由于设置样式太灵活,有很多地方都能设置,所以当我们发现一个控件的样式不符合预期的时候,要记得排查这四个地方:

  • 全局样式(QAppplication 设置的)
  • 指定控件样式(这个控件是否设置了样式)
  • qss 文件中的样式
  • ui 文件中的样式
  • 指定控件的父控件的样式(可能是从父控件继承过来的)

在实际开发中,如果需要设置样式,建议最好统一使用某一种方式来设置。


4、选择器

(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 选择器基本一致。


【使用类型选择器选中子类控件】

A. 在界面上创建一个按钮

B. 修改 main.cpp,设置全局样式

a.setStyleSheet("QWidget{color:red;}");
  • 注意 :此处选择器使用的是 QWidget。QPushButton 也是 QWidget 的子类,所以会受到 QWidget 选择器的影响。

C. 运行程序

  • 可以看到按钮的文本颜色已经是红色了

D. 如果把上述样式代码修改为下列代码

a.setStyleSheet(".QWidget{color:red;}");
  • 此时按钮的颜色不会发送改变。此时只是选择 QWidget 类,而不会选择 QWidget 的子类 QPushButton 了。

【使用 id 选择器】

A. 在界面上创建 3 个按钮,objectName 为 pushButton、pushButton_2、pushButton_3

B. 编写 main.cpp,设置全局样式

  • 先通过 QPushButton 设置所有的按钮为红色。
  • 再通过 #pushButton 和 #pushButton_2 分别设置这两个按钮为绿色和黄色。
QString style = "QPushButton { color: red; }";
style += "#pushButton_2 { color: green; }";
style += "#pushButton_3 { color: yellow; }";a.setStyleSheet(style);

C. 执行效果

当某个控件身上,通过类型选择器和 ID 选择器设置了冲突的样式时,ID 选择器样式优先级更高(遵循局部优先)。

同理,如果是其他的多种选择器作用同一个控件时出现冲突的样式,也会涉及到优先级问题。Qt 文档上有具体的优先级规则介绍(参见 The Style Sheet Syntax 的 Conflict Resolution 章节)

这里的规则计算起来非常复杂(CSS 中也存在类似的设定)。可以简单的认为,选择器描述的范围越精准,则优先级越高。一般来说,ID 选择器优先级是最高的。

如果属性不冲突,还是会同时生效


【使用并集选择器】

A. 创建三个按钮、一个 label、一个单行输入框

B. 编写 main.cpp,设置全局样式

QString style="QPushButton,QLineEdit,QLabel{color:red;}";a.setStyleSheet(style);

C. 运行程序

可以看到这三种控件的文字颜色都设置为了红色:

  • 并集选择器是一种很好的代码复用的方式,很多时候我们希望界面上的多个元素风格是统一的,就可以使用并集选择器,把样式属性同时指定给多种控件。

也可以指定 id 选择器:

展示效果:

(2)子控件选择器(Sub-Controls)

有些控件内部包含了多个 “子控件”,比如 QComboBox 的下拉后的面板,比如 QSpinBox 的上下按钮等。

可以通过子控件选择器 ::,针对上述子控件进行样式设置。

哪些控件拥有哪些子控件,参考文档 Qt Style Sheets Reference 中 List of Sub-Controls 章节。


【设置下拉框的下拉按钮样式】

A. 在界面上创建一个下拉框,并创建几个选项

B. 创建 resource.qrc,并导入图片 down.png

C. 修改 main.cpp,编写全局样式

  • 使用子控件选择器 QComboBox::down-arrow 选中了 QComboBox 的下拉按钮。
  • 再通过 image 属性设置图片。
QString style="QComboBox::down-arrow{ image:url(:/downPull.png)}";a.setStyleSheet(style);

D. 执行程序


【修改进度条的颜色】

A. 在界面上创建一个进度条

B. 在 Qt Designer 右侧的属性编辑器中,找到 QWidget 的 styleSheet 属性

编辑如下内容:

  • 其中的 chunk 是选中进度条中的每个 “块”,使用 QProgressBar::text 则可以选中文本。
  • 同时把 QProcessBar 的 alignment 属性设置为垂直水平居中。

  • 此处如果不设置 alignment,进度条中的数字会跑到左上角(这个怀疑是 Qt 本身的 bug,暂时只能先使⽤ alignment 来手动调整一下)。

C. 执行程序

可以看到如下效果,就得到了一个红色的进度条:

通过上述方式,也可以修改文字的颜色,字体大小等样式。


(3)伪类选择器(Pseudo-States)

伪类选择器,是根据控件所处的某个状态被选择的。

例如按钮被按下,输入框获取到焦点,鼠标移动到某个控件上等。

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

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

常用的伪类选择器:

伪类选择器

说明

:hover

鼠标放到控件上

:pressed

鼠标左键按下时

:focus

获取输入焦点时

:enabled

元素处于可用状态时

:checked

被勾选时

:read-only

元素为只读状态时

这些状态可以使用 ! 来取反,比如 :!hover 就是鼠标离开控件时,:!pressed 就是鼠标松开时,等等。更多伪类选择器的详细情况可以参考 Qt Style Sheets Reference 的 Pseudo-States 章节。


【设置按钮的伪类样式】

A. 在界面上创建一个按钮

B. 编写 main.cpp,创建全局样式

 QString style = "QPushButton { color: red; }";style += "QPushButton:hover { color: green; }";style += "QPushButton:pressed { color: blue; }";a.setStyleSheet(style);

C. 运行程序

可以看到默认情况下按钮文字是红色,鼠标移动上去是绿色,鼠标按下按钮是蓝色:

上述代码也可以使用事件的方式来实现。


【使用事件方式实现同样效果】

A. 创建 MyPushButton 类,继承自 QPushButton

B. 把生成代码中的构造函数 改成带参数 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)
{}

C. 在界面上创建按钮,并提升为 MyPushButton 类型

  • 右键按钮,选择 “提升为...”
  • 填写提升的类名和头文件:

提升完毕后,在右侧对象树这里,就可以看到类型的变化。

D. 重写 MyPushButton 的四个事件处理函数

a. 修改 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);
};

b. 修改 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; }");
}

E. 运行程序

可以看到效果和上述案例一致

很明显,实现同样的功能,伪类选择器要比事件的方式简单很多。

但是不能就说事件机制就不好,事件可以完成的功能很多,不仅仅是样式的改变,还可以包含其他业务逻辑,这一点是伪类选择器无法替代的。


http://www.ppmy.cn/devtools/151691.html

相关文章

【设计模式-结构型】装饰器模式

一、什么是装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它的核心思想是在不改变原有对象结构的情况下&#xff0c;动态地给对象增加一些功能&#xff0c;从而达到扩展功能的目的。举个例子&#xff0c;今天在家妈妈给蒸馒…

Oracle 23ai新特性:使用列别名的 GROUP BY 和 HAVING 子句

摘要 随着数据库技术的不断发展&#xff0c;SQL 语言也在不断进化&#xff0c;以更好地满足数据查询和分析的需求。本文将探讨如何在 SQL 查询中使用列别名&#xff08;column alias&#xff09;或列位置&#xff08;column position&#xff09;来简化 GROUP BY 和 HAVING 子…

ios文件管理,沙盒机制以及如何操作“文件”APP,把文件共享到文件app

首先&#xff0c;系统是一个整体&#xff0c;那每个app是相互独立的&#xff0c;系统为每个app分配了一定的存储空间&#xff0c;也就是我们说的沙盒&#xff0c;每个app有自己独立的沙盒&#xff0c;文件存储在沙盒中&#xff0c;正常情况下app相互之间数据是不可以共享以及访…

优化神马关键词排名原理(优化神马搜索引擎关键词排名规则)

优化神马&#xff08;即百度&#xff09;关键词排名的原理主要基于搜索引擎的算法和用户体验的考量。以下是一些关键的优化原理&#xff1a; 一、搜索引擎算法 网页重要性评估&#xff1a; 搜索引擎通过复杂的算法评估网页的重要性和权威性&#xff0c;如基于PageRank的评估方…

ROS进阶:使用URDF和Xacro构建差速轮式机器人模型

前言 本篇文章介绍的是ROS高效进阶内容&#xff0c;使用URDF 语言&#xff08;xml格式&#xff09;做一个差速轮式机器人模型&#xff0c;并使用URDF的增强版xacro&#xff0c;对机器人模型文件进行二次优化。 差速轮式机器人&#xff1a;两轮差速底盘由两个动力轮位于底盘左…

【深度学习量化交易14】正式开源!看海量化交易系统——基于miniQMT的量化交易软件

我是Mr.看海&#xff0c;我在尝试用信号处理的知识积累和思考方式做量化交易&#xff0c;应用深度学习和AI实现股票自动交易&#xff0c;目的是实现财务自由~ 目前我正在开发基于miniQMT的量化交易系统——看海量化交易系统。 前13篇文章&#xff0c;我介绍了我开发的量化交易系…

异步任务与定时任务

一、异步任务 基于TaskExecutionAutoConfiguration配置类中&#xff0c;注册的ThreadPoolTaskExecutor线程池对象进行异步任务执行。 (一)手动执行异步任务 在yml中配置线程池参数 spring: task:execution:pool:core-size: 5 # 核心线程数max-size: 20 # 最大线…

网络安全 | 什么是正向代理和反向代理?

关注&#xff1a;CodingTechWork 引言 在现代网络架构中&#xff0c;代理服务器扮演着重要的角色。它们在客户端和服务器之间充当中介&#xff0c;帮助管理、保护和优化数据流。根据代理的工作方向和用途&#xff0c;代理服务器可分为正向代理和反向代理。本文将深入探讨这两种…