数据层(panel_registry.py):13 个 step 从「阶段一/二/三/四」重组为四个模块 模块一 影像预处理(step 1-3) 模块二 特征工程与数据(step 4-7) 模块三 模型训练与反演(step 8-10) 模块四 制图与成果汇编(step 11-13) step_id 顺序、tab_index、面板绑定、Tab 路由全部保持零变化 文本层(water_quality_gui.py / v2):移除 └─ 字符前缀 样式层(styles.py:get_sidebar_stylesheet):扁平无框 + 蓝色高亮主题 - 容器 QListWidget 无框化(border: none / outline: none / 透明背景) - 步骤项 padding 8px 6px + margin 2px 8px + border-radius 4px - hover 极浅蓝灰 #F0F4F8;selected 饱和蓝 #0078D4 + 白字 #FFFFFF - 分类头(stage_header):!enabled 选择器锁定 → 蓝色 #0078D4 + 加粗 + 上下间距 Python 代码侧:stage_item.setForeground 硬编码 #0078D4、stage_font.setBold(True) 作为 QSS 失效兜底 + 代码意图自解释 末尾迭代:四个模块名移除 [ ] 中括号(极简风)
609 lines
20 KiB
Python
609 lines
20 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
现代化样式表和主题管理模块
|
||
Modern Stylesheet and Theme Management Module
|
||
"""
|
||
|
||
class ModernStylesheet:
|
||
"""现代化样式表集合"""
|
||
|
||
# 颜色定义
|
||
COLORS = {
|
||
'main_bg': '#F0F0F0', # 主窗口背景:浅灰
|
||
'panel_bg': '#FFFFFF', # 面板/容器背景:白色
|
||
'text_primary': '#000000', # 主文字:黑色
|
||
'text_secondary': '#666666', # 辅助文字:灰色
|
||
'border': '#D0D0D0', # 边框:浅灰
|
||
'border_light': '#E8E8E8', # 浅边框
|
||
'accent': '#007BFF', # 强调色:蓝色
|
||
'success': '#28A745', # 成功绿
|
||
'error': '#DC3545', # 错误红
|
||
'warning': '#FFC107', # 警告黄
|
||
'hover': '#E8E8E8', # 悬停背景
|
||
'selected': '#0056B3', # 选中色
|
||
}
|
||
|
||
@staticmethod
|
||
def get_main_stylesheet():
|
||
"""获取主样式表"""
|
||
return f"""
|
||
/* 主窗口 */
|
||
QMainWindow {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
}}
|
||
|
||
/* 中央部件和容器 */
|
||
QWidget {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
}}
|
||
|
||
/* 分组框 */
|
||
QGroupBox {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
font-weight: bold;
|
||
border: 0px;
|
||
margin-top: 10px;
|
||
padding-top: 15px;
|
||
padding-left: 9px;
|
||
padding-right: 9px;
|
||
padding-bottom: 9px;
|
||
border-bottom: 1px solid {ModernStylesheet.COLORS['border_light']};
|
||
}}
|
||
|
||
QGroupBox::title {{
|
||
subcontrol-origin: margin;
|
||
subcontrol-position: top left;
|
||
padding: 0 5px;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
}}
|
||
|
||
/* 按钮 */
|
||
QPushButton {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 7px;
|
||
padding: 3px 5px;
|
||
min-height: 25px;
|
||
max-height: 33px;
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
outline: none;
|
||
}}
|
||
|
||
QPushButton:hover {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
}}
|
||
|
||
QPushButton:pressed {{
|
||
background-color: {ModernStylesheet.COLORS['border_light']};
|
||
}}
|
||
|
||
QPushButton:disabled {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
color: {ModernStylesheet.COLORS['text_secondary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border_light']};
|
||
}}
|
||
|
||
QPushButton:focus {{
|
||
outline: none;
|
||
}}
|
||
|
||
/* 输入框 */
|
||
QLineEdit {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 10px;
|
||
padding: 5px 8px;
|
||
min-height: 20px;
|
||
selection-background-color: {ModernStylesheet.COLORS['selected']};
|
||
selection-color: white;
|
||
}}
|
||
|
||
QLineEdit:focus {{
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
}}
|
||
|
||
/* 下拉框 */
|
||
QComboBox {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 5px;
|
||
padding: 5px 8px;
|
||
min-height: 25px;
|
||
selection-background-color: {ModernStylesheet.COLORS['selected']};
|
||
}}
|
||
|
||
QComboBox:focus {{
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
QComboBox::drop-down {{
|
||
border: 0px;
|
||
padding-right: 5px;
|
||
}}
|
||
|
||
QComboBox QAbstractItemView {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
selection-background-color: {ModernStylesheet.COLORS['selected']};
|
||
selection-color: white;
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
}}
|
||
|
||
/* 数值输入框 */
|
||
QSpinBox, QDoubleSpinBox {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 5px;
|
||
padding: 5px 8px;
|
||
min-height: 25px;
|
||
}}
|
||
|
||
QSpinBox:focus, QDoubleSpinBox:focus {{
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
QSpinBox::up-button, QDoubleSpinBox::up-button {{
|
||
border: 0px;
|
||
padding-right: 5px;
|
||
}}
|
||
|
||
QSpinBox::down-button, QDoubleSpinBox::down-button {{
|
||
border: 0px;
|
||
padding-right: 5px;
|
||
}}
|
||
|
||
/* 复选框 */
|
||
QCheckBox {{
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
spacing: 5px;
|
||
}}
|
||
|
||
QCheckBox::indicator {{
|
||
width: 16px;
|
||
height: 16px;
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 3px;
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
}}
|
||
|
||
QCheckBox::indicator:checked {{
|
||
background-color: {ModernStylesheet.COLORS['accent']};
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
/* 单选框 */
|
||
QRadioButton {{
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
spacing: 5px;
|
||
}}
|
||
|
||
QRadioButton::indicator {{
|
||
width: 16px;
|
||
height: 16px;
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 8px;
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
}}
|
||
|
||
QRadioButton::indicator:checked {{
|
||
background: qradial(circle, {ModernStylesheet.COLORS['accent']} 0%, {ModernStylesheet.COLORS['accent']} 40%, {ModernStylesheet.COLORS['panel_bg']} 60%);
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
/* 文本编辑框 */
|
||
QTextEdit {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 5px;
|
||
padding: 5px;
|
||
selection-background-color: {ModernStylesheet.COLORS['selected']};
|
||
selection-color: white;
|
||
}}
|
||
|
||
QTextEdit:focus {{
|
||
border: 1px solid {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
/* 列表部件 */
|
||
QListWidget {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 5px;
|
||
outline: none;
|
||
}}
|
||
|
||
QListWidget::item {{
|
||
padding: 6px;
|
||
border: 0px;
|
||
}}
|
||
|
||
QListWidget::item:hover {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
}}
|
||
|
||
QListWidget::item:selected {{
|
||
background-color: {ModernStylesheet.COLORS['selected']};
|
||
color: white;
|
||
}}
|
||
|
||
/* 滚动区域 */
|
||
QScrollArea {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
border: 0px;
|
||
}}
|
||
|
||
/* 滚动条 */
|
||
QScrollBar:vertical {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
width: 12px;
|
||
border: 0px;
|
||
}}
|
||
|
||
QScrollBar::handle:vertical {{
|
||
background-color: {ModernStylesheet.COLORS['border']};
|
||
border-radius: 6px;
|
||
min-height: 20px;
|
||
}}
|
||
|
||
QScrollBar::handle:vertical:hover {{
|
||
background-color: {ModernStylesheet.COLORS['text_secondary']};
|
||
}}
|
||
|
||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
|
||
border: 0px;
|
||
background-color: transparent;
|
||
}}
|
||
|
||
QScrollBar:horizontal {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
height: 12px;
|
||
border: 0px;
|
||
}}
|
||
|
||
QScrollBar::handle:horizontal {{
|
||
background-color: {ModernStylesheet.COLORS['border']};
|
||
border-radius: 6px;
|
||
min-width: 20px;
|
||
}}
|
||
|
||
QScrollBar::handle:horizontal:hover {{
|
||
background-color: {ModernStylesheet.COLORS['text_secondary']};
|
||
}}
|
||
|
||
QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {{
|
||
border: 0px;
|
||
background-color: transparent;
|
||
}}
|
||
|
||
/* 进度条 */
|
||
QProgressBar {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-radius: 5px;
|
||
padding: 2px;
|
||
text-align: center;
|
||
height: 20px;
|
||
}}
|
||
|
||
QProgressBar::chunk {{
|
||
background-color: {ModernStylesheet.COLORS['success']};
|
||
border-radius: 3px;
|
||
}}
|
||
|
||
/* 标签 */
|
||
QLabel {{
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
background-color: transparent;
|
||
}}
|
||
|
||
/* 标签栏 */
|
||
QTabBar::tab {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-bottom: 0px;
|
||
padding: 8px 12px;
|
||
margin-right: 2px;
|
||
border-radius: 5px 5px 0px 0px;
|
||
}}
|
||
|
||
QTabBar::tab:selected {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-bottom: 2px solid {ModernStylesheet.COLORS['accent']};
|
||
color: {ModernStylesheet.COLORS['accent']};
|
||
}}
|
||
|
||
QTabBar::tab:hover {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
}}
|
||
|
||
QTabWidget::pane {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
border-top: 0px;
|
||
border-radius: 0px 0px 5px 5px;
|
||
}}
|
||
|
||
/* 菜单栏 */
|
||
QMenuBar {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border-bottom: 1px solid {ModernStylesheet.COLORS['border_light']};
|
||
padding: 2px;
|
||
}}
|
||
|
||
QMenuBar::item:selected {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
}}
|
||
|
||
/* 菜单 */
|
||
QMenu {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border: 1px solid {ModernStylesheet.COLORS['border']};
|
||
padding: 4px 0px;
|
||
border-radius: 5px;
|
||
}}
|
||
|
||
QMenu::item:selected {{
|
||
background-color: {ModernStylesheet.COLORS['hover']};
|
||
padding-left: 20px;
|
||
}}
|
||
|
||
QMenu::separator {{
|
||
height: 1px;
|
||
background-color: {ModernStylesheet.COLORS['border_light']};
|
||
margin: 4px 0px;
|
||
}}
|
||
|
||
/* 状态栏 */
|
||
QStatusBar {{
|
||
background-color: {ModernStylesheet.COLORS['panel_bg']};
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
border-top: 1px solid {ModernStylesheet.COLORS['border_light']};
|
||
}}
|
||
|
||
/* 框架 */
|
||
QFrame {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
border: 0px;
|
||
}}
|
||
|
||
/* 对话框 */
|
||
QDialog {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
}}
|
||
|
||
/* 消息框 */
|
||
QMessageBox {{
|
||
background-color: {ModernStylesheet.COLORS['main_bg']};
|
||
}}
|
||
|
||
QMessageBox QLabel {{
|
||
color: {ModernStylesheet.COLORS['text_primary']};
|
||
}}
|
||
"""
|
||
|
||
@staticmethod
|
||
def get_button_stylesheet(style_type='normal'):
|
||
"""获取特定样式的按钮样式表"""
|
||
colors = ModernStylesheet.COLORS
|
||
|
||
if style_type == 'primary':
|
||
# 蓝色主按钮
|
||
return f"""
|
||
QPushButton {{
|
||
background-color: {colors['accent']};
|
||
color: white;
|
||
border: 1px solid {colors['accent']};
|
||
border-radius: 7px;
|
||
padding: 3px 5px;
|
||
min-height: 25px;
|
||
max-height: 33px;
|
||
font-weight: bold;
|
||
}}
|
||
QPushButton:hover {{
|
||
background-color: #0056b3;
|
||
border: 1px solid #0056b3;
|
||
}}
|
||
QPushButton:pressed {{
|
||
background-color: #003d82;
|
||
}}
|
||
QPushButton:disabled {{
|
||
background-color: {colors['hover']};
|
||
color: {colors['text_secondary']};
|
||
border: 1px solid {colors['border_light']};
|
||
}}
|
||
"""
|
||
|
||
elif style_type == 'success':
|
||
# 绿色成功按钮
|
||
return f"""
|
||
QPushButton {{
|
||
background-color: {colors['success']};
|
||
color: white;
|
||
border: 1px solid {colors['success']};
|
||
border-radius: 7px;
|
||
padding: 3px 5px;
|
||
min-height: 25px;
|
||
max-height: 33px;
|
||
font-weight: bold;
|
||
}}
|
||
QPushButton:hover {{
|
||
background-color: #218838;
|
||
border: 1px solid #218838;
|
||
}}
|
||
QPushButton:pressed {{
|
||
background-color: #1a6c28;
|
||
}}
|
||
QPushButton:disabled {{
|
||
background-color: {colors['hover']};
|
||
color: {colors['text_secondary']};
|
||
border: 1px solid {colors['border_light']};
|
||
}}
|
||
"""
|
||
|
||
elif style_type == 'danger':
|
||
# 红色危险按钮
|
||
return f"""
|
||
QPushButton {{
|
||
background-color: {colors['error']};
|
||
color: white;
|
||
border: 1px solid {colors['error']};
|
||
border-radius: 7px;
|
||
padding: 3px 5px;
|
||
min-height: 25px;
|
||
max-height: 33px;
|
||
font-weight: bold;
|
||
}}
|
||
QPushButton:hover {{
|
||
background-color: #c82333;
|
||
border: 1px solid #c82333;
|
||
}}
|
||
QPushButton:pressed {{
|
||
background-color: #9a1a24;
|
||
}}
|
||
QPushButton:disabled {{
|
||
background-color: {colors['hover']};
|
||
color: {colors['text_secondary']};
|
||
border: 1px solid {colors['border_light']};
|
||
}}
|
||
"""
|
||
|
||
else: # normal/default
|
||
return f"""
|
||
QPushButton {{
|
||
background-color: {colors['panel_bg']};
|
||
color: {colors['text_primary']};
|
||
border: 1px solid {colors['border']};
|
||
border-radius: 7px;
|
||
padding: 3px 5px;
|
||
min-height: 25px;
|
||
max-height: 33px;
|
||
}}
|
||
QPushButton:hover {{
|
||
background-color: {colors['hover']};
|
||
border: 1px solid {colors['border']};
|
||
}}
|
||
QPushButton:pressed {{
|
||
background-color: {colors['border_light']};
|
||
}}
|
||
QPushButton:disabled {{
|
||
background-color: {colors['hover']};
|
||
color: {colors['text_secondary']};
|
||
border: 1px solid {colors['border_light']};
|
||
}}
|
||
"""
|
||
|
||
@staticmethod
|
||
def get_toolbar_stylesheet():
|
||
"""获取顶部工具栏样式表"""
|
||
colors = ModernStylesheet.COLORS
|
||
return f"""
|
||
QWidget {{
|
||
background-color: {colors['panel_bg']};
|
||
border-bottom: 1px solid {colors['border_light']};
|
||
}}
|
||
QLabel {{
|
||
color: {colors['text_primary']};
|
||
}}
|
||
QPushButton {{
|
||
background-color: {colors['panel_bg']};
|
||
color: {colors['text_primary']};
|
||
border: 1px solid {colors['border']};
|
||
border-radius: 5px;
|
||
padding: 5px 10px;
|
||
min-height: 25px;
|
||
}}
|
||
QPushButton:hover {{
|
||
background-color: {colors['hover']};
|
||
}}
|
||
"""
|
||
|
||
@staticmethod
|
||
def get_sidebar_stylesheet():
|
||
"""获取左侧边栏样式表
|
||
|
||
设计主题:扁平无框 + 蓝色高亮。
|
||
结构契约:
|
||
- 分类头 stage_header 项已通过 setFlags(~Qt.ItemIsEnabled) 禁用,
|
||
因此 :!enabled 选择器可精确锁定分类头(蓝色加粗)。
|
||
- 可点击的步骤项保持 enabled,进入 :enabled 通道
|
||
(padding/margin 留白 + 圆角 + hover/selected 蓝色现代感)。
|
||
"""
|
||
colors = ModernStylesheet.COLORS
|
||
# 主题色板(蓝色高亮)
|
||
stage_header_color = '#0078D4' # 分类头:亮蓝色加粗
|
||
step_hover_bg = '#F0F4F8' # hover(极浅蓝灰)
|
||
step_selected_bg = '#0078D4' # selected(饱和蓝)
|
||
step_selected_fg = '#FFFFFF' # selected(白字)
|
||
return f"""
|
||
QWidget {{
|
||
background-color: {colors['panel_bg']};
|
||
border-right: 1px solid {colors['border_light']};
|
||
}}
|
||
QLabel {{
|
||
color: {colors['text_primary']};
|
||
font-weight: bold;
|
||
}}
|
||
/* ── 容器:无框化、零描边、零焦点环 ── */
|
||
QListWidget {{
|
||
border: none;
|
||
outline: none;
|
||
background-color: transparent;
|
||
}}
|
||
/* ── 分类头(stage_header,禁用态):亮蓝色 + 加粗 + 上下间距 ── */
|
||
QListWidget::item:!enabled {{
|
||
color: {stage_header_color};
|
||
font-weight: bold;
|
||
background-color: transparent;
|
||
border: none;
|
||
padding: 14px 8px 6px 8px;
|
||
margin-top: 4px;
|
||
}}
|
||
/* ── 步骤项(enabled):padding/margin 留白 + 圆角过渡 ── */
|
||
QListWidget::item:enabled {{
|
||
color: {colors['text_secondary']};
|
||
padding: 8px 6px;
|
||
margin: 2px 8px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
}}
|
||
/* ── 步骤项 hover(未选中态):极浅蓝灰悬浮 ── */
|
||
QListWidget::item:enabled:hover:!selected {{
|
||
background-color: {step_hover_bg};
|
||
color: {colors['text_primary']};
|
||
}}
|
||
/* ── 步骤项 selected:饱和蓝高亮 + 白字 ── */
|
||
QListWidget::item:enabled:selected {{
|
||
background-color: {step_selected_bg};
|
||
color: {step_selected_fg};
|
||
border: none;
|
||
font-weight: bold;
|
||
}}
|
||
/* ── 分隔符占位项:完全透明,零干扰 ── */
|
||
QListWidget::item[separator="true"] {{
|
||
background-color: transparent;
|
||
border: none;
|
||
padding: 0px;
|
||
margin: 0px;
|
||
min-height: 4px;
|
||
}}
|
||
"""
|