找回密码
 立即注册
首页 业界区 业界 在PySide6/PyQt6的项目中实现样式切换处理

在PySide6/PyQt6的项目中实现样式切换处理

全愉婉 5 小时前
在桌面应用开发中,“主题切换(深色 / 浅色模式)”已经不再是锦上添花的功能,而是逐渐成为一种用户刚需。尤其对于长时间使用的 ERP 工具类应用来说,良好的视觉舒适度对用户体验影响巨大。本篇随笔针对PySide6/PyQt6的项目的实现案例,介绍如何实现样式切换处理。
Qt 官方本身提供了 QStyle 体系,但如果想做到:

  • 可自定义配色
  • 可作为品牌皮肤
  • 可热切换(无需重启)
  • 多主题共存
  • 可持久化
那么,采用 QSS (Qt Style Sheet) + 统一主题管理器的方案无疑是目前最成熟、最实用、性价比最高的选择。
本文将从 原理 → 架构设计 → 实现方式 → 最佳实践 四个维度,完整介绍在 PySide6 / PyQt6 项目中如何构建一套“企业级主题切换系统”。
一、为什么不能简单地用 setStyle?

很多初学者在做样式适配时,都会走入一个误区:
  1. btn.setStyleSheet("background:red")
  2. table.setStyleSheet("color:white")
  3. ...
复制代码
这种写法短期“能用”,长期会带来三个严重问题:
1. 样式分散,难维护
不同窗口、不同控件中的样式写法彼此独立,一个主题改动需要满项目搜索替换,很容易遗漏。

2. 逻辑和表现混杂
UI 逻辑代码被大量 CSS 淹没,维护成本剧增,违反基本的架构解耦原则。

3. 无法进行主题切换
没有分主题文件结构,一旦需要切换风格就必须“重写所有 setStyle”,几乎不可实现。

✅ 因此,如果项目规模超过 3 个界面,我们就必须放弃零散 setStyle 写法,转而使用 QSS 主题体系。
二、什么是 QSS?

Qt 中的 QSS (Qt Style Sheet) 本质和 CSS 非常类似,几乎可以视为 CSS 在 Qt 世界中的实现。
对 Qt 控件来说:

  • QWidget → HTML 标签
  • QPushButton、QTableView → CSS 选择器
  • background / border / padding / color → 样式属性
例如:
  1. QPushButton {
  2.     background: #3a3a3a;
  3.     border-radius: 6px;
  4.     color: white;
  5. }
复制代码
QSS 能做到:

  • 全局覆盖
  • 继承 & 层级作用
  • 精准控件控制
  • 即时加载刷新
我们希望做到:
业务代码永远不接触 CSS
主题由独立模块统一调度
  1. project/
  2. ├── main.py
  3. ├── core/
  4. │   └── theme_manager.py
  5. └── themes/
  6.     ├── light.qss
  7.     └── dark.qss
复制代码
通过 ThemeManager 将 UI 层与样式层完全隔离,可读性和可维护性大幅提升。
我们需要一个负责三件事的主题管理器统一类:

  • 读取主题文件
  • 调用 Qt API 应用主题
  • 记录并恢复用户选择
QSS 主题文件设计示例:以下是一个简化版本:
浅色主题
  1. QWidget {
  2.     background: #ffffff;
  3.     color: #202020;
  4. }
  5. QPushButton {
  6.     background: #e8e8e8;
  7.     border-radius: 4px;
  8. }
复制代码
深色主题
  1. QWidget {
  2.     background: #2b2b2b;
  3.     color: #f0f0f0;
  4. }
  5. QPushButton {
  6.     background: #3a3a3a;
  7.     color: #ffffff;
  8. }
复制代码
三、UI 中的使用方式

我们通过创建系统相关的菜单,如定义样式切换的菜单,然后绑定对应的菜单信号处理。
  1. action_dark.triggered.connect(lambda: ThemeManager.apply("dark"))
  2. action_light.triggered.connect(lambda: ThemeManager.apply("light"))
复制代码
这样切换的时候,无需重启——Qt 会自动刷新全部控件。
通过样式管理器,实现不同主题演示的即时切换。
主题系统并不是简单的“换几个颜色”。
它是 UI 架构中不可忽视的一环:

  • 影响可维护性
  • 决定代码整洁度
  • 直接关系用户体验

在 PySide6 / PyQt6 中,
QSS + ThemeManager + 动态切换 + 持久化
这一套组合,几乎是目前最成熟可靠的主题实现方案,没有之一。
真正的统一UI的样式,包含 5 个维度:
维度说明色板统一背景色、主色、强调色、警示色字体统一字体家族、字号梯度控件形态圆角、border、padding交互动效hover、press、disable布局密度表格行距、控件间距 
四、具体在PySide6/PyQt6的项目中的实践过程

我们根据前面的介绍,在项目目录中创建两个不同主题样式的文件,如下所示。
1.png

然后根据样式的需要定义对应的相关内容,如下是浅色的主题定义,通过定义对应控件的颜色、字体、背景色等相关属性,实现统一的效果。
2.png

通过辅助类,我们创建几个菜单来实现不同样式的切换。
  1.         theme_menu = menu_bar.addMenu("界面主题")
  2.         light_action = ControlUtil.create_menu(
  3.             self, theme_menu, "浅色主题", "info"
  4.         )
  5.         light_action.triggered.connect(lambda: self.set_theme(1))
  6.         dark_action = ControlUtil.create_menu(
  7.             self, theme_menu, "深色主题", "info"
  8.         )
  9.         dark_action.triggered.connect(lambda: self.set_theme(2))
  10.         system_action = ControlUtil.create_menu(
  11.             self, theme_menu, "初始主题", "info"
  12.         )
  13.         system_action.triggered.connect(lambda: self.set_theme(0))
复制代码
菜单界面效果如下所示。
3.png

其中样式的信号处理,我们通过一个单件的样式总线对象来处理。
  1.     def set_theme(self, theme_type):
  2.         """设置主题颜色"""
  3.         self.theme_type = theme_type
  4.         # 切换主题颜色
  5.         ThemeBus().set_theme_type(self.theme_type)
复制代码
其中,我们对样式总线对象的变化进行信号绑定处理。
  1.         #监听主题变化的事件
  2.         ThemeBus().theme_type_changed.connect(self.on_theme_changed)
复制代码
对主题样式的变化进行处理。
  1.     def on_theme_changed(self, theme_type):
  2.         """主题变化的事件处理"""
  3.         
  4.         theme_map = {
  5.             1: "light",
  6.             2: "dark",
  7.             0: "" #不设置主题,默认使用系统主题
  8.         }
  9.         theme_name = theme_map[self.theme_type]
  10.         self.log.info(f"主题变化: {theme_type}:{theme_name}")
  11.         # 切换主题颜色
  12.         ThemedHelper.apply(theme_type)
复制代码
这个主题的辅助类,主要就是根据当前总线的样式值,加载对应的样式文件进行设置,如果为空,这还原为最初的默认样式。
  1. class ThemedHelper:
  2.     """控件主题辅助类"""
  3.     @staticmethod
  4.     def apply(theme_type: int = 0):
  5.         """应用主题样式"""
  6.         theme_name =  ""
  7.         if theme_type == 1:
  8.             theme_name= "light"
  9.         elif theme_type == 2:
  10.             theme_name= "dark"
  11.         else:
  12.             theme_name = ""
  13.             
  14.         if not theme_name:
  15.             qss = "" # 自动主题, 无需加载 qss 文件
  16.         else:
  17.             with open(f"app/themes/{theme_name}.qss", encoding="utf8") as f:
  18.                 qss = f.read()
  19.         
  20.         app : QApplication = QApplication.instance()
  21.         if app:
  22.             app.setStyle("Fusion")
  23.             app.setStyleSheet(qss)
复制代码
暗色主题的效果如下所示。
4.png

 如果不喜欢厚重的主题,我们也可以切换会原来的默认主题。
5.png

以上就是我们在定义不同主题,实现主题切换的过程,我们可以根据需要,定义更多有特色的主题样式,而具有统一效果的主题样式,我们可以通过AI的询问方式,获得完整的样式代码,从而构建个性化的效果。
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册