PyQt QDarkStyle详解-打造专业暗黑界面的瑞士军刀
- [一、 QDarkStyle详解](#一、 QDarkStyle详解)
- 二、代码示例

一、 QDarkStyle详解
1、QDarkStyle 概述
QDarkStyle 是一个为 Qt 应用程序(包括 PyQt 和 PySide)提供高质量深色主题样式表(QSS - Qt Style Sheets)的第三方库。它旨在提供一个现代、美观且对用户友好的深色界面,替代 Qt 默认的浅色主题。
主要特点
- 现代深色主题: 提供符合当前深色 UI 设计趋势的外观。
- 广泛的控件支持: 样式表覆盖了大量常用的 Qt 控件,如按钮、标签、输入框、组合框、列表框、表格、树状视图、滚动条、菜单栏、工具栏、状态栏、进度条、滑块、复选框、单选框、分组框、选项卡等。
- 一致性: 努力确保不同控件之间的视觉风格一致,提升整体用户体验。
- 易于集成: 只需几行代码即可将深色主题应用到你的 PyQt6 应用程序中。
- 可定制性(基础): 虽然主要提供预设样式,但也允许开发者通过修改提供的 QSS 文件或在其基础上添加额外的样式规则来进行一定程度的定制。
- 活跃维护: 项目通常保持相对活跃的维护状态。
2、安装
使用 pip 安装是最简单的方式:
bash
pip install qdarkstyle
3、使用详解
-
基本应用(整个应用程序)
这是最常见的使用方式,将深色主题应用于整个应用程序的所有窗口和控件。
pythonimport 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对象上。这会影响到应用程序中创建的所有窗口和控件。
-
应用到特定窗口
如果你不想全局应用,只想给某个特定的窗口设置深色主题:
pythonimport 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()) -
使用
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目录来了解有哪些可用选项(但通常不需要直接操作这些文件)。 -
作为 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 资源系统 -
样式覆盖与自定义
有时
QDarkStyle的默认样式可能不完全符合你的需求,或者它没有覆盖到你使用的某个特殊控件。你可以:-
在
QDarkStyle之后应用额外样式: Qt 样式表具有级联特性。后设置的规则会覆盖先设置的规则(如果选择器相同或更具体)。因此,你可以在应用了QDarkStyle之后,再给你的窗口或特定控件设置额外的样式规则。pythonapp.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、运行展示


