所有的操作均在下载到本地的QDarkStyleSheet-master项目下进行:

项目地址:https://github.com/ColinDuquesnoy/QDarkStyleSheet/tree/master
我放在了网盘:https://pan.baidu.com/share/init?surl=OP5e_ejyB5Brbao3VNSx7Q 提取码: 2jxr
一、扩充色系
qdarkstyle的colorsystem.py中的所有颜色:
python
class Gray:
B0 = '#000000'
B10 = '#19232D'
B20 = '#293544'
B30 = '#37414F'
B40 = '#455364'
B50 = '#54687A'
B60 = '#60798B'
B70 = '#788D9C'
B80 = '#9DA9B5'
B90 = '#ACB1B6'
B100 = '#B4B8BC'
B110 = '#C0C4C8'
B120 = '#D2D5D8'
B130 = '#DFE1E2'
B140 = '#FAFAFA'
B150 = '#FFFFFF'
class Blue:
B0 = '#000000'
B10 = '#062647'
B20 = '#26486B'
B30 = '#375A7F'
B40 = '#346792'
B50 = '#1A72BB'
B60 = '#057DCE'
B70 = '#259AE9'
B80 = '#37AEFE'
B90 = '#73C7FF'
B100 = '#9FCBFF'
B110 = '#C2DFFA'
B120 = '#CEE8FF'
B130 = '#DAEDFF'
B140 = '#F5FAFF'
B150 = '#FFFFFF'
qdarkstyle的配色系统只有灰色和蓝色两种色系共32个颜色,这显然是不够用的。在原有基础上,增加红、绿、黄、橙、紫色系,作为补充:
python
# colorsystem.py is the full list of colors that can be used to easily create themes. B10 = '#19232D'
class Gray:
B0 = '#000000'
B10 = '#19232D'
B20 = '#293544'
B30 = '#37414F'
B40 = '#455364'
B50 = '#54687A'
B60 = '#60798B'
B70 = '#788D9C'
B80 = '#9DA9B5'
B90 = '#ACB1B6'
B100 = '#B4B8BC'
B110 = '#C0C4C8'
B120 = '#D2D5D8'
B130 = '#DFE1E2'
B140 = '#FAFAFA'
B150 = '#FFFFFF'
class Blue:
B0 = '#000000'
B10 = '#062647'
B20 = '#26486B'
B30 = '#375A7F'
B40 = '#346792'
B50 = '#1A72BB'
B60 = '#057DCE'
B70 = '#259AE9'
B80 = '#37AEFE'
B90 = '#73C7FF'
B100 = '#9FCBFF'
B110 = '#C2DFFA'
B120 = '#CEE8FF'
B130 = '#DAEDFF'
B140 = '#F5FAFF'
B150 = '#FFFFFF'
class Green:
B0 = '#000000'
B10 = '#062D06'
B20 = '#064826'
B30 = '#065A37'
B40 = '#066734'
B50 = '#1ABB1A'
B60 = '#05CE05'
B70 = '#25E925'
B80 = '#37FE37'
B90 = '#73FF73'
B100 = '#9FFF9F'
B110 = '#C2FAC2'
B120 = '#CEFFCE'
B130 = '#DAFFDA'
B140 = '#F5FFF5'
B150 = '#FFFFFF'
class Red:
B0 = '#000000'
B10 = '#2D0606'
B20 = '#480626'
B30 = '#5A0637'
B40 = '#670634'
B50 = '#BB1A1A'
B60 = '#CE0505'
B70 = '#E92525'
B80 = '#FE3737'
B90 = '#FF7373'
B100 = '#FF9F9F'
B110 = '#FAC2C2'
B120 = '#FFCECE'
B130 = '#FFDADA'
B140 = '#FFF5F5'
B150 = '#FFFFFF'
class Purple:
B0 = '#000000'
B10 = '#1A082C'
B20 = '#2D1047'
B30 = '#3F1862'
B40 = '#51207D'
B50 = '#632898'
B60 = '#7530B3'
B70 = '#8740CC'
B80 = '#9950E6'
B90 = '#AB68F0'
B100 = '#BD80F5'
B110 = '#CF98FA'
B120 = '#E1B0FC'
B130 = '#EFC8FD'
B140 = '#F7E0FE'
B150 = '#FFFFFF'
class Yellow:
B0 = '#000000'
B10 = '#2D2D06'
B20 = '#484826'
B30 = '#5A5A37'
B40 = '#676734'
B50 = '#BBBB1A'
B60 = '#CECE05'
B70 = '#E9E925'
B80 = '#FEFE37'
B90 = '#FFFF73'
B100 = '#FFFF9F'
B110 = '#FAFAC2'
B120 = '#FFFFCE'
B130 = '#FFFFDA'
B140 = '#FFFFF5'
B150 = '#FFFFFF'
class Orange:
B0 = '#000000'
B10 = '#2D1906'
B20 = '#482606'
B30 = '#5A3706'
B40 = '#673406'
B50 = '#BB5A1A'
B60 = '#CE7005'
B70 = '#E99A25'
B80 = '#FEB037'
B90 = '#FFC273'
B100 = '#FFD09F'
B110 = '#FAE0C2'
B120 = '#FFE6CE'
B130 = '#FFEDDA'
B140 = '#FFF8F5'
B150 = '#FFFFFF'
class Cyan:
B0 = '#000000'
B10 = '#062D2D'
B20 = '#064848'
B30 = '#065A5A'
B40 = '#066767'
B50 = '#1ABBBB'
B60 = '#05CECE'
B70 = '#25E9E9'
B80 = '#37FEFE'
B90 = '#73FFFF'
B100 = '#9FFFFF'
B110 = '#C2FAFA'
B120 = '#CEFFFF'
B130 = '#DAFFFF'
B140 = '#F5FFFF'
B150 = '#FFFFFF'
class Pink:
B0 = '#000000'
B10 = '#2D0619'
B20 = '#480630'
B30 = '#5A0642'
B40 = '#67064A'
B50 = '#BB1A7F'
B60 = '#CE0590'
B70 = '#E925A8'
B80 = '#FE37C1'
B90 = '#FF73D0'
B100 = '#FF9FDD'
B110 = '#FAC2E8'
B120 = '#FFCEF0'
B130 = '#FFDAF5'
B140 = '#FFF5FC'
B150 = '#FFFFFF'
class Brown:
B0 = '#000000'
B10 = '#261208'
B20 = '#3D2010'
B30 = '#532E18'
B40 = '#693C20'
B50 = '#804828'
B60 = '#995A33'
B70 = '#B36C3E'
B80 = '#CC804A'
B90 = '#E6995C'
B100 = '#F0B37D'
B110 = '#F5C799'
B120 = '#F9D6B3'
B130 = '#FBE2C7'
B140 = '#FDF0DA'
B150 = '#FFFFFF'
ALL = [Gray, Blue, Green, Red, Purple, Yellow, Orange, Cyan, Pink, Brown]
展示和验证:
python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QHBoxLayout
from qdarkstyle.colorsystem import ALL
def get_colors(colorClass):
colors = lambda: [colorClass.B0, colorClass.B10, colorClass.B20, colorClass.B30, colorClass.B40, colorClass.B50,
colorClass.B60, colorClass.B70, colorClass.B80, colorClass.B90, colorClass.B100,
colorClass.B110, colorClass.B120, colorClass.B130, colorClass.B140, colorClass.B150]
return colors()
def hex_to_rgb(hex_color):
"""将十六进制颜色(如#1A72BB)转换为RGB元组 (r, g, b)"""
# 去除#号,统一转为大写(避免大小写问题)
hex_color = hex_color.lstrip('#').upper()
# 校验格式(6位十六进制)
if len(hex_color) != 6:
raise ValueError("颜色格式错误,需为6位十六进制(如#1A72BB)")
# 拆分红、绿、蓝通道并转十进制
r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16)
return [r, g, b]
def invert_color(hex_color):
"""将十六进制颜色(如#1A72BB)反转为相反的颜色"""
# 将十六进制颜色转为RGB元组
colors = hex_to_rgb(hex_color)
for i, color in enumerate(colors):
if 90 < color < 160:
colors[i] = 200
else:
colors[i] = 255 - color
return colors
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
layout = QHBoxLayout(w)
w.setLayout(layout)
def add_color_label(layout, colorClass):
color_list = get_colors(colorClass)
layout1 = QVBoxLayout(w)
color_name= colorClass.__name__
label = QLabel(f"{color_name}")
layout1.addWidget(label)
for color in color_list:
c = invert_color(color)
label = QLabel(f"{color}")
label.setStyleSheet(f"background-color: {color};color:rgb({c[0]},{c[1]},{c[2]});")
label.setFixedSize(120, 40)
layout1.addWidget(label)
layout.addLayout(layout1)
for color in ALL:
add_color_label(layout, color)
w.show()
sys.exit(app.exec())

二、创建一个自定义的主题并离线调用
1. QDarkStyleSheet-master/qdarkstyle目录下,新建文件夹/custom:

2. /custom下创建/rc文件夹,和__init__.py、palette.py文件:

init.py内容为空:
python
# -*- coding: utf-8 -*-
调色板文件,palette.py:(在这里把dark的蓝色系改成了新增的绿色系)
python
# -*- coding: utf-8 -*-
"""QDarkStyle default dark palette."""
# Local imports
from qdarkstyle.colorsystem import Blue, Gray, Green
from qdarkstyle.palette import Palette
class CustomPalettee(Palette):
"""Dark palette variables."""
# Identifier
ID = 'custom'
# Color
COLOR_BACKGROUND_1 = Gray.B10
COLOR_BACKGROUND_2 = Gray.B20
COLOR_BACKGROUND_3 = Gray.B30
COLOR_BACKGROUND_4 = Gray.B40
COLOR_BACKGROUND_5 = Gray.B50
COLOR_BACKGROUND_6 = Gray.B60
COLOR_TEXT_1 = Gray.B130
COLOR_TEXT_2 = Gray.B110
COLOR_TEXT_3 = Gray.B90
COLOR_TEXT_4 = Gray.B80
# 改成了绿色系
COLOR_ACCENT_1 = Green.B20
COLOR_ACCENT_2 = Green.B40
COLOR_ACCENT_3 = Green.B50
COLOR_ACCENT_4 = Green.B70
COLOR_ACCENT_5 = Green.B80
# Color for disabled elements
COLOR_DISABLED = Gray.B70
OPACITY_TOOLTIP = 230
3.QDarkStyleSheet-master/docs/images目录下新建文件夹/custom:

4. 复制QDarkStyleSheet-master/docs/images/dark/palette.svg到刚创建的/custom目录下:

5. 复制qdarkstyle/dark/main.scss到/qdarkstyle/custom

6. 修改QDarkStyleSheet-master/qdarkstyle/utils/main.py:
- 新增:

新增:

新增:

新增:

修改后的完整代码:
python
# -*- coding: utf-8 -*-
"""Script to process QRC files (convert .qrc to _rc.py and .rcc).
The script will attempt to compile the qrc file using the following tools:
- `pyside6-rcc` for PySide6 and QtPy (Python) (Official)
- There is no specific rcc compiler for PyQt6, use `pyside6-rcc` (Python)
- `pyrcc5` for PyQt5 (Python)
- `pyside2-rcc` for PySide2 (Python)
- `rcc` for Qt5/Qt6 (C++)
Delete the compiled files that you don't want to use manually after
running this script.
Links to understand those tools:
- `pyside6-rcc`: https://doc.qt.io/qtforpython/tutorials/basictutorial/qrcfiles.html (Official)
- `pyrcc5`: http://pyqt.sourceforge.net/Docs/PyQt5/resources.html#pyrcc5
- `pyside2-rcc: https://doc.qt.io/qtforpython/overviews/resources.html (Documentation Incomplete)
- `rcc` on Qt6: https://doc.qt.io/qt-6/resources.html
- `rcc` on Qt5: http://doc.qt.io/qt-5/rcc.html
"""
# Standard library imports
import argparse
import logging
import sys
from PySide6.QtWidgets import QApplication
# Third party imports
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
# Local imports
from qdarkstyle import PACKAGE_PATH
from qdarkstyle.dark.palette import DarkPalette
from qdarkstyle.light.palette import LightPalette
from qdarkstyle.custom.palette import CustomPalette
from qdarkstyle.utils import process_palette
_logger = logging.getLogger(__name__)
class QSSFileHandler(FileSystemEventHandler):
"""QSS File observer."""
def __init__(self, parser_args):
"""QSS File observer."""
super(QSSFileHandler, self).__init__()
self.args = parser_args
def on_modified(self, event):
"""Handle file system events."""
if event.src_path.endswith('.qss'):
# TODO: needs implementation for new palettes
process_palette(compile_for=self.args.create)
print('\n')
def main():
# 新增
if not QApplication.instance():
app = QApplication(sys.argv)
"""Process QRC files."""
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--qrc_dir',
default=None,
type=str,
help="QRC file directory, relative to current directory.",)
parser.add_argument('--create',
default='qtpy',
choices=['pyqt5', 'pyqt6', 'pyside2', 'pyside6', 'qtpy', 'pyqtgraph', 'qt', 'qt5', 'all'],
type=str,
help="Choose which one would be generated.")
parser.add_argument('--watch', '-w',
action='store_true',
help="Watch for file changes.")
parser.add_argument('--custom', '-c',
action='store_true',
help="Process custom palette", )
args = parser.parse_args()
if args.watch:
path = PACKAGE_PATH
observer = Observer()
handler = QSSFileHandler(parser_args=args)
observer.schedule(handler, path, recursive=True)
try:
print('\nWatching QSS file for changes...\nPress Ctrl+C to exit\n')
observer.start()
except KeyboardInterrupt:
observer.stop()
observer.join()
elif args.custom:
print(f"args.custom: {args.custom}")
process_palette(palette=CustomPalette, compile_for=args.create)
else:
for palette in [DarkPalette, LightPalette]:
process_palette(palette=palette, compile_for=args.create)
# 新增
sys.exit(app.quit())
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
sys.exit(main())
7. 修改QDarkStyleSheet-master/qdarkstyle/utils/images.py:
注释掉两个_ = QApplication([]):


8. QDarkStyleSheet-master/根目录下创建process_qrc.py:
python
import subprocess
import os
# 1. 配置关键参数(根据实际情况修改)
conda_python_path = r"C:\Users\DY\.conda\envs\pyside\python.exe" # conda环境的python路径
qrc_path = r"E:\QDarkStyleSheet-master\qdarkstyle\utils\__main__.py" # __main__.py的绝对路径
working_dir = r"E:\QDarkStyleSheet-master" # qdarkstyle根目录(必须!否则模块导入失败)
shell = True # Windows建议设为True,Linux/Mac可设为False
# 2. 构造命令(可选:添加--create参数,比如pyside6)
cmd = [
conda_python_path, # conda的python解释器
qrc_path, # 要运行的__main__.py
'--create', 'pyside6', # 传递给__main__.py的参数(可选),本项是选择QT的版本
'--custom' # 是否使用自定义的调色板
]
# 3. 执行命令(指定工作目录+conda环境)
try:
# cwd=working_dir:确保运行时的工作目录是qdarkstyle根目录,模块能正确导入
subprocess.call(cmd, shell=shell, cwd=working_dir)
except Exception as e:
print(f"执行失败:{e}")
运行process_qrc.py,在QDarkStyleSheet-masterqdarkstyle/custom下会生成两个文件:
pyside6_customstyle_rc.py
customstyle.qss
把这两个文件拷贝到别的项目内即可离线调用。
demo:
新建项目,输入:
python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QCheckBox, QComboBox
import pyside6_customstyle_rc # 导入图像资源
if __name__ == '__main__':
app = QApplication(sys.argv)
with open('customstyle.qss', 'r', encoding='utf-8') as f:
stylesheet = f.read()
form = QWidget()
form.setWindowTitle("PySide6 自定义样式")
form.setGeometry(500, 400, 300, 200)
app.setStyleSheet(stylesheet)
btn1 = QPushButton("按钮")
checkBox = QCheckBox("复选框")
comboBox = QComboBox()
comboBox.addItems(["选项1", "选项2", "选项3"])
layout = QVBoxLayout(form)
layout.addWidget(btn1)
layout.addWidget(checkBox)
layout.addWidget(comboBox)
form.show()
sys.exit(app.exec_())

**注:**由于pyside6_customstyle_rc.py和customstyle.qss都使用了pyside6可以读出的格式,所以,离线使用的项目可以不用安装qdarkstyle。
三、深度定制修改的点位
1、使用与默认不同的图像资源
在目录QDarkStyleSheet-master/qdarkstyle/svg下,存储着有可能用到的所有图像资源,可以是公司logo,也可以是背景图片等,当然,默认只有一些零件图标(比如下拉选择框的下拉箭头)和分割线之类的,格式是.svg,你可以修改和增减这些图片文件。
2、怎样改变部件的显示特性
打开QDarkStyleSheet-master/qdarkstyle/qss/_styles.scss

其内容为如下格式:

这个文件是所有的主题共用的。
以QRadioButton为例,它在_styles.scss中的定义为:
python
QRadioButton {
background-color: $COLOR_BACKGROUND_1;
color: $COLOR_TEXT_1;
spacing: 4px;
padding-top: 4px;
padding-bottom: 4px;
border: none;
outline: none;
&:focus {
border: none;
}
&:disabled {
background-color: $COLOR_BACKGROUND_1;
color: $COLOR_DISABLED;
border: none;
outline: none;
}
QWidget {
background-color: $COLOR_BACKGROUND_1;
color: $COLOR_TEXT_1;
spacing: 0px;
padding: 0px;
outline: none;
border: none;
}
&::indicator {
border: none;
outline: none;
margin-left: 2px;
height: 14px;
width: 14px;
&:unchecked {
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked.png');
&:hover,
&:focus,
&:pressed {
border: none;
outline: none;
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_focus.png');
}
&:disabled {
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_unchecked_disabled.png');
}
}
&:checked {
border: none;
outline: none;
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked.png');
&:hover,
&:focus,
&:pressed {
border: none;
outline: none;
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_focus.png');
}
&:disabled {
outline: none;
image: url($PATH_RESOURCES + '/' + $ID + '/rc/radio_checked_disabled.png');
}
}
}
}
通过修改上面的代码,就可以把各个部件的特性连接到不同的颜色变量,还可以增加新的部件和设定。比如,在上述代码中的这一行,定义了背景色:
python
background-color: $COLOR_BACKGROUND_1;
COLOR_BACKGROUND_1对应的变量就是当前主题中的调色板文件中定义的颜色,如果当前主题是custom,它的专属调色板文件:QDarkStyleSheet-master/qdarkstyle/custom/palette.py中COLOR_BACKGROUND_1就对应了一个颜色:Gray.B10

而Gray.B10,则是在QDarkStyleSheet-master/qdarkstyle/colorsystem.py中定义的,它是所有主题共用的:

按需修改以上文件,并执行前面创建的process_qrc.py,就可以得到深度定制的.qss和_rc.py文件并离线使用。
**另注:**项目原版的utils包,我一直跑不通,所以才拆解它的代码,做了以上修改才跑通,如果有高手知道怎样使用原版的utils创建自定义.qss和_rc.py文件,望不吝赐教。