PyQt QDarkStyle详解-打造专业暗黑界面的瑞士军刀

PyQt QDarkStyle详解-打造专业暗黑界面的瑞士军刀

一、 QDarkStyle详解

1、QDarkStyle 概述

QDarkStyle 是一个为 Qt 应用程序(包括 PyQt 和 PySide)提供高质量深色主题样式表(QSS - Qt Style Sheets)的第三方库。它旨在提供一个现代、美观且对用户友好的深色界面,替代 Qt 默认的浅色主题。

主要特点

  1. 现代深色主题: 提供符合当前深色 UI 设计趋势的外观。
  2. 广泛的控件支持: 样式表覆盖了大量常用的 Qt 控件,如按钮、标签、输入框、组合框、列表框、表格、树状视图、滚动条、菜单栏、工具栏、状态栏、进度条、滑块、复选框、单选框、分组框、选项卡等。
  3. 一致性: 努力确保不同控件之间的视觉风格一致,提升整体用户体验。
  4. 易于集成: 只需几行代码即可将深色主题应用到你的 PyQt6 应用程序中。
  5. 可定制性(基础): 虽然主要提供预设样式,但也允许开发者通过修改提供的 QSS 文件或在其基础上添加额外的样式规则来进行一定程度的定制。
  6. 活跃维护: 项目通常保持相对活跃的维护状态。

2、安装

使用 pip 安装是最简单的方式:

bash 复制代码
pip install qdarkstyle

3、使用详解

  1. 基本应用(整个应用程序)

    这是最常见的使用方式,将深色主题应用于整个应用程序的所有窗口和控件。

    python 复制代码
    import sys
    from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel
    import qdarkstyle
    
    # 创建应用程序
    app = QApplication(sys.argv)
    
    # !!! 关键步骤:应用 QDarkStyle 主题 !!!
    app.setStyleSheet(qdarkstyle.load_stylesheet())  # 使用默认主题 (qt_material 参数可调整风格)
    # app.setStyleSheet(qdarkstyle.load_stylesheet(style='dark')) # 明确指定 'dark' 主题 (默认就是这个)
    # app.setStyleSheet(qdarkstyle.load_stylesheet(style='light')) # 如果想尝试其提供的浅色主题
    
    # 创建主窗口并添加一些控件
    window = QMainWindow()
    window.setWindowTitle("QDarkStyle Demo")
    button = QPushButton("点击我", window)
    label = QLabel("这是一个标签", window)
    label.move(0, 40)
    
    window.show()
    sys.exit(app.exec())
    • qdarkstyle.load_stylesheet(): 这个函数加载并返回 QDarkStyle 的样式表字符串。
    • app.setStyleSheet(): 将加载的样式表应用到整个 QApplication 对象上。这会影响到应用程序中创建的所有窗口和控件。
  2. 应用到特定窗口

    如果你不想全局应用,只想给某个特定的窗口设置深色主题:

    python 复制代码
    import sys
    from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton
    import qdarkstyle
    
    app = QApplication(sys.argv)
    
    # 创建窗口1 (默认浅色主题)
    window1 = QMainWindow()
    window1.setWindowTitle("Window 1 (Light)")
    
    # 创建窗口2 (应用 QDarkStyle)
    window2 = QMainWindow()
    window2.setWindowTitle("Window 2 (Dark)")
    window2.setStyleSheet(qdarkstyle.load_stylesheet())  # !!! 只应用于 window2 !!!
    
    window1.show()
    window2.show()
    sys.exit(app.exec())
  3. 使用 qt_material 参数调整风格
    QDarkStyle 内部使用了 qt-material 库的一部分。load_stylesheet 函数有一个 style 参数(通常使用默认的 'dark'),但更重要的是 qt_material 参数。它接受一个字符串来指定更具体的视觉风格:

    python 复制代码
    # 应用不同的 'qt_material' 主题变体
    app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_teal.xml'))  # 深青色主题
    # app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_blue.xml'))   # 深蓝色主题
    # app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_cyan.xml'))   # 深青色主题 (另一种)
    # app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_purple.xml')) # 深紫色主题
    # app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_red.xml'))    # 深红色主题
    # app.setStyleSheet(qdarkstyle.load_stylesheet(qt_material='dark_amber.xml'))  # 深琥珀色主题

    这些 .xml 文件定义了主题的主要颜色(Primary Color)、强调色(Accent Color)等。QDarkStyle 内置了这些变体文件。你可以通过查看 QDarkStyle 源码中的 _resources 目录来了解有哪些可用选项(但通常不需要直接操作这些文件)。

  4. 作为 Qt 资源文件使用

    如果你需要将样式表打包到你的应用程序资源中(例如使用 pyrcc),或者想先查看样式表内容,你可以获取原始的 QSS 字符串:

    python 复制代码
    # 获取原始 QSS 内容
    dark_stylesheet = qdarkstyle.load_stylesheet()
    # 或者带参数的
    # dark_stylesheet = qdarkstyle.load_stylesheet(qt_material='dark_blue.xml')
    
    print(dark_stylesheet)  # 查看内容 (内容很长)
    # 你可以保存这个字符串到文件 (.qss),然后用 QFile 读取或添加到 Qt 资源系统
  5. 样式覆盖与自定义

    有时 QDarkStyle 的默认样式可能不完全符合你的需求,或者它没有覆盖到你使用的某个特殊控件。你可以:

    • QDarkStyle 之后应用额外样式: Qt 样式表具有级联特性。后设置的规则会覆盖先设置的规则(如果选择器相同或更具体)。因此,你可以在应用了 QDarkStyle 之后,再给你的窗口或特定控件设置额外的样式规则。

      python 复制代码
      app.setStyleSheet(qdarkstyle.load_stylesheet() + """
          /* 覆盖 QDarkStyle 中的 QPushButton 样式 */
          QPushButton {
              background-color: #FF0000; /* 红色背景 */
              border: none;
          }
          /* 为你自定义的 MySpecialWidget 添加样式 */
          MySpecialWidget {
              background-color: #00FF00;
          }
      """)
    • 修改 QDarkStyle 源码: 直接克隆 QDarkStyle 的 GitHub 仓库,找到对应的 .qss.xml 文件进行修改,然后在你的项目中指向修改后的版本。这种方式更灵活但也更复杂,且不利于后续更新库。

3、注意事项

  • 覆盖范围: 虽然 QDarkStyle 覆盖了大部分常用控件,但并非 100% 覆盖所有 Qt 控件,尤其是非常冷门或第三方自定义控件。你可能需要为这些控件补充样式。
  • 动态切换: QDarkStyle 本身不提供运行时动态切换主题的功能(如通过菜单切换)。实现这个功能需要你自己管理样式表的加载和重新应用(例如,在切换主题的信号槽中重新调用 app.setStyleSheet()window.setStyleSheet())。
  • 兼容性: 确保你使用的 QDarkStyle 版本与你的 PyQt6 版本兼容。通常新版本的 QDarkStyle 会跟进支持新版本的 Qt/PyQt。
  • 图标: QDarkStyle 主要提供的是样式表(颜色、边框、圆角等),不包含图标集。你需要自行提供适合深色背景的图标(例如使用 SVG 图标并根据主题切换颜色,或使用专门为深色主题设计的图标包)。

4、总结

QDarkStyle 是快速为 PyQt6 应用程序添加现代化深色主题的利器。通过简单的 app.setStyleSheet(qdarkstyle.load_stylesheet()) 即可实现全局深色效果。它还提供了通过 qt_material 参数选择不同颜色变体的能力。对于大多数标准应用来说,它开箱即用的效果已经非常不错。如果有个性化需求,可以通过在其后追加额外的 QSS 规则进行覆盖定制。

二、代码示例

1、源码分享

python 复制代码
import sys
import random

from PyQt6 import QtWidgets, QtCore
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget,
    QVBoxLayout, QHBoxLayout, QPushButton,
    QLabel, QSizePolicy
)

import mainWindow
import qdarkstyle

class MainWindow(QMainWindow):
    """主窗口类"""

    def __init__(self):
        super().__init__()
        self.resize(847, 620)
        self.centralwidget = QtWidgets.QWidget(parent=self)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(parent=self.centralwidget)
        self.label.setGeometry(QtCore.QRect(9, 9, 16, 16))
        self.label.setText("")
        self.label.setObjectName("label")
        self.pushButton = QtWidgets.QPushButton(parent=self.centralwidget)
        self.pushButton.setEnabled(False)
        self.pushButton.setGeometry(QtCore.QRect(250, 70, 191, 61))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(parent=self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(480, 70, 191, 61))
        self.pushButton_2.setObjectName("pushButton_2")
        self.progressBar = QtWidgets.QProgressBar(parent=self.centralwidget)
        self.progressBar.setGeometry(QtCore.QRect(230, 170, 501, 23))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.checkBox = QtWidgets.QCheckBox(parent=self.centralwidget)
        self.checkBox.setGeometry(QtCore.QRect(220, 290, 101, 31))
        self.checkBox.setObjectName("checkBox")
        self.toolButton = QtWidgets.QToolButton(parent=self.centralwidget)
        self.toolButton.setGeometry(QtCore.QRect(360, 280, 131, 51))
        self.toolButton.setObjectName("toolButton")
        self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(140, 370, 241, 171))
        self.groupBox.setObjectName("groupBox")
        self.tabWidget = QtWidgets.QTabWidget(parent=self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(430, 370, 261, 151))
        self.tabWidget.setObjectName("tabWidget")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.tabWidget.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.tabWidget.addTab(self.tab_2, "")
        self.comboBox = QtWidgets.QComboBox(parent=self.centralwidget)
        self.comboBox.setGeometry(QtCore.QRect(40, 90, 161, 31))
        self.comboBox.setObjectName("comboBox")
        self.spinBox = QtWidgets.QSpinBox(parent=self.centralwidget)
        self.spinBox.setGeometry(QtCore.QRect(40, 160, 171, 31))
        self.spinBox.setObjectName("spinBox")
        self.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=self)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 847, 21))
        self.menubar.setObjectName("menubar")
        self.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(parent=self)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("MainWindow", "qdarkstyle示例"))
        self.pushButton.setText(_translate("MainWindow", "禁用按钮"))
        self.pushButton_2.setText(_translate("MainWindow", "标准按钮"))
        self.checkBox.setText(_translate("MainWindow", "CheckBox"))
        self.toolButton.setText(_translate("MainWindow", "..."))
        self.groupBox.setTitle(_translate("MainWindow", "GroupBox"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Tab 2"))


if __name__ == "__main__":

    app = QApplication(sys.argv)

    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt6())
    window = MainWindow()
    window.show()

    sys.exit(app.exec())

2、运行展示


相关推荐
懷淰メ1 天前
【AI加持】基于PyQt+YOLO+DeepSeek的车型检测系统(详细介绍)
yolo·目标检测·计算机视觉·pyqt·项目设计·deepseek·车型检测
淮北4942 天前
ubuntu22.04将mp4转换成gif
python·scrapy·flask·beautifulsoup·pyqt·matplotlib
懷淰メ3 天前
【AI加持】基于PyQt+YOLO+DeepSeek的口罩佩戴检测系统(详细介绍)
yolo·计算机视觉·pyqt·口罩检测·deepseek·ai加持
小灰灰搞电子5 天前
PyQt QWebChannel详解-C++与Web页面的无缝双向通信
前端·pyqt
小灰灰搞电子7 天前
PyQt QtAwesome详解:为Qt应用注入字体图标的魅力
pyqt·字体图标
DeepLearningYolo7 天前
基于PyQt的YOLOv5+DeepSORT可视化界面,可实现目标跟踪、模型更换、结果保存和轨迹隐藏等功能。
yolo·目标跟踪·pyqt
TRACER~8512 天前
项目实战:pyqt6实现拼豆图纸生成器
python·pyqt
龙腾AI白云21 天前
大模型Prompt实战:精准生成专业技术文档
plotly·pyqt·fastapi·tornado·dash
CodebySandwich25 天前
QWidget转化为matplotlib绘图窗体
pyqt