QSS文件加载工具类,在utils包中创建文件qss_loader.py

qss_loader.py
from PyQt5.QtCore import QFile


class QSSLoader:
def __init__(self, path: str) -> None:
self._path = path

def load(self) -> str:
f = QFile(self._path)
f.open(QFile.ReadOnly | QFile.Text)
stylesheet = f.readAll()
return stylesheet.data().decode("utf-8")

单一主题

样式主题文件写入到qss文件中,qss类似早期版本的css,创建ui/style/light.qss目录及文件。

main.py中新增load_qss()方法

main.py
from utils import QSSLoader

class PyQgisSEApp(QMainWindow, Ui_MainWindow):
def __init__(self, app: QgsApplication):
super(PyQgisSEApp, self).__init__()
self.app = app
self.ui = Ui_MainWindow()
self.ui.setupUi(self)

# 装载模块
GUI.GUIPreview.load_preview(self)

# 加载主题文件
self.load_qss()

def load_qss(self):
# 切换主题文件
qss = QSSLoader(f"{os.path.dirname(sys.argv[0])}/ui/style/light.qss").load()
self.ui.centralwidget.setStyleSheet(qss)

主题文件light.qss内容如下:

QWidget, QFrame {
background-color: #fff;
border: none;
}
QTabWidget, QLabel, QToolButton, QPushButton, QLineEdit, QRadioButton {
font-family: 'Microsoft YaHei', 'PingFang SC','SimSun','Arial', sans-serif;
}
/* 输入框 */
QLineEdit {
border-style:none;
padding:2px;
border-radius: 3px;
border: 1px solid rgb(224, 224, 230);
}
QLineEdit:focus {
border: 1px solid #36ad6a;
}

/* Tab样式 */
QTabWidget#tabWidget {
background-color: white;
}
QTabBar {
font-size: 9.5pt;
qproperty-drawBase: 0;
}
QTabBar::tab {
border: none;
margin: 3px 10px 0px 10px;
width: 66px;
padding: 5px 0px;
border-bottom: 2px solid #FFFFFF;
}
QTabBar::tab:selected, QTabBar::tab:hover {
background-color:#FFFFFF;
}
QTabBar::tab:selected {
border-color: #18a058;
font-weight: 500;
}

/* 顶部工具栏样式 */
QFrame#frame_prev_top {
border-top: 1px solid rgba(228,228,228,1);
}

QFrame#frame_prev_top {
padding: 2px;
background-color: rgb(255, 255, 255);
border-bottom: 1px solid rgba(228,228,228,1);
}

QFrame#frame_prev_tools {
padding-left: 6px;
}

/* 工具按钮 */
QToolButton:hover {
background-color: rgba(46, 51, 56, 0.09);
}
QToolButton:checked {
background-color: rgba(46, 51, 56, 0.09);
}
QToolButton:pressed {
background-color: rgba(46, 51, 56, 0.13);
}
QToolButton {
padding: 2px;
border-radius: 4px;
margin-right: 4px;
margin-top: 2px;
margin-bottom: 2px;
}

/* 中间区域左侧样式 */
/* 图层管理上方 */
QFrame#frame_prev_layers_mgr, QFrame#frame_prev_layers_mgr QToolButton {
background-color: #F7F8FA;
}

QFrame#frame_prev_layers_mgr {
border: 0px solid;
border-bottom-width: 1px;
border-bottom-color: #EBECF0;
}
QFrame#frame_prev_layers {
border: 0px solid;
border-right-width: 1px;
border-right-color: #EBECF0;
}

/* 图层管理上方按钮样式 */
QFrame#frame_prev_layers_mgr QToolButton {
margin: 4px 0px;
margin-right: 4px;
}

QFrame#frame_prev_layers_mgr QToolButton:hover {
background-color: #EBECF0;
}
QFrame#frame_prev_layers_mgr QLabel {
font-size: 9pt;
margin-left: 4px;
background-color: #F7F8FA;
}

/* 中间区域右侧样式 */
QFrame#frame_prev_map_mgr {
border: 0px solid;
border-bottom-width: 1px;
border-bottom-color: #EBECF0;
padding-left: 4px;
}

/* 底部区域样式 */
QFrame#frame_prev_bottom {
border: 0px solid #EBECF0;
border-top-width: 1px;
background-color: white;
padding: 1px 10px;
border-bottom: none;
}
QLineEdit#edit_coords_value, QLineEdit#edit_coords_value_inversion {
width: 100px;
margin: 2px 0px;
}
QLineEdit#edit_coords_value, QLineEdit#edit_coords_value_inversion {
width: 140px;
margin: 2px 0px;
}

最终效果如下:

夜间模式

创建ui/style/light/theme.qssui/style/dark/theme.qss两个文件,分别存放白天和夜间主题。

修改main.py代码

main.py
class PyQgisSEApp(QMainWindow, Ui_MainWindow):
def __init__(self, app: QgsApplication):
super(PyQgisSEApp, self).__init__()
self.app = app
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# 装载模块
GUI.GUIPreview.load_preview(self)

# 加载主题文件
self.settings = QSettings('PyQgisSEApp')
self.theme = 'light'
self.load_qss()

def load_qss(self):
# 从配置中加载主题选项
self.theme = self.settings.value('theme', 'light')
self.switch_theme()

def slot_switch_theme(self):
"""
切换主题插槽,用于绑定按钮
"""
self.theme = 'dark' if self.theme == 'light' else 'light'
# 写入配置
self.settings.setValue('theme', self.theme)
self.switch_theme()

def switch_theme(self):
# 切换主题文件
file = f"{os.path.dirname(sys.argv[0])}/ui/style/{self.theme}/theme.qss"
qss = QSSLoader(file).load()
self.ui.centralwidget.setStyleSheet(qss)

# 数据预览页面主题切换
GUI.GUIPreview.switch_theme(self, self.theme)

预览页面添加如下代码,部分组件样式需要代码更改,资源文件自行添加

preview.py
def switch_theme(main, theme):
canvas_color = Qt.white if main.theme == 'light' else QColor(30, 31, 34)
main.preview_canvas.setCanvasColor(canvas_color)

if 'dark' == theme:
main.layerTreeView.setStyleSheet("background-color: rgb(30, 31, 34)")
main.ui.button_prev_clear.setIcon(QIcon(":/icon/action_trash_dark"))
main.ui.button_prev_remove.setIcon(QIcon(":/icon/action_remove_dark"))
else:
main.layerTreeView.setStyleSheet("background-color: white")
main.ui.button_prev_clear.setIcon(QIcon(":/icon/action_trash_light"))
main.ui.button_prev_remove.setIcon(QIcon(":/icon/action_remove_light"))

主题文件dark/theme.qss内容如下:

QWidget, QFrame {
background-color: #2B2D30;
border: none;
}
QTabWidget, QLabel, QToolButton, QPushButton, QLineEdit, QRadioButton {
font-family: 'Microsoft YaHei', 'PingFang SC','SimSun','Arial', sans-serif;
color: #FFF;
}

QSplitter {
background-color: #1E1F22;
}

/* 输入框 */
QLineEdit {
border-style:none;
padding:2px;
border-radius: 3px;
color: white;
border: 1px solid rgb(224, 224, 230);
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
}
QLineEdit:focus {
border: 1px solid #36ad6a;
}

/* Tab样式 */
QTabWidget#tabWidget {
background-color: #2B2D30;
border: none;
}
QTabBar {
font-size: 9.5pt;
qproperty-drawBase: 0;
}
QTabBar::tab {
border: none;
margin: 3px 10px 0px 10px;
width: 66px;
padding: 5px 0px;
color: #FFF;
border-bottom: 2px solid #2B2D30;
}
QTabBar::tab:selected, QTabBar::tab:hover {
background-color:#2B2D30;
}
QTabBar::tab:selected {
border-color: #18a058;
font-weight: 500;
}

/* 顶部工具栏样式 */
QFrame#frame_prev_top {
border-top: 1px solid #1E1F22;
}

QFrame#frame_prev_top {
padding: 2px;
background-color: #2B2D30;
border-bottom: 1px solid #1E1F22;
}

QFrame#frame_prev_tools {
padding-left: 6px;
}

/* 工具按钮 */
QToolButton:hover {
background-color: #4E5157;
}
QToolButton:checked {
background-color: #4E5157;
}
QToolButton:pressed {
background-color: #4E5157;
}
QToolButton {
padding: 2px;
border-radius: 4px;
margin-right: 4px;
margin-top: 2px;
margin-bottom: 2px;
}

/* 中间区域左侧样式 */
/* 图层管理上方 */
QFrame#frame_prev_layers {
background-color: #1E1F22;
}
QFrame#frame_prev_layers_mgr, QFrame#frame_prev_layers_mgr QToolButton {
background-color: #2B2D30;
}

QFrame#frame_prev_layers_mgr {
border: 0px solid #1E1F22;
border-right-width: 1px;
border-right-color: #1E1F22;
border-bottom-width: 1px;
border-bottom-color: #1E1F22;
}

/* 图层管理上方按钮样式 */
QFrame#frame_prev_layers_mgr QToolButton {
margin: 4px 0px;
margin-right: 4px;
}

QFrame#frame_prev_layers_mgr QToolButton:hover {
background-color: #4E5157;
}
QFrame#frame_prev_layers_mgr QLabel {
font-size: 9pt;
margin-left: 4px;
background-color: #2B2D30;
}

/* 中间区域右侧样式 */
QFrame#frame_prev_map_mgr {
border: 0px solid;
border-bottom-width: 1px;
border-bottom-color: #1E1F22;
padding-left: 4px;
}

/* 底部区域样式 */
QFrame#frame_prev_bottom {
border: 0px solid #1E1F22;
border-top-width: 1px;
background-color: #2B2D30;
padding: 1px 10px;
border-bottom: none;
}
QLineEdit#edit_coords_value, QLineEdit#edit_coords_value_inversion {
width: 100px;
margin: 2px 0px;
}
QLineEdit#edit_coords_value, QLineEdit#edit_coords_value_inversion {
width: 140px;
margin: 2px 0px;
}

夜间模式效果如下: