diff --git a/src/gui/panels/step12_viz_panel.py b/src/gui/panels/step12_viz_panel.py index 5f54234..3bcc6cb 100644 --- a/src/gui/panels/step12_viz_panel.py +++ b/src/gui/panels/step12_viz_panel.py @@ -919,13 +919,6 @@ class ImageViewerWidget(QWidget): self.scroll_area.horizontalScrollBar().installEventFilter(self) layout.addWidget(self.scroll_area, 1) - status_layout = QHBoxLayout() - self.status_label = QLabel("就绪") - self.status_label.setStyleSheet("color: #666; font-size: 11px;") - status_layout.addWidget(self.status_label) - status_layout.addStretch() - layout.addLayout(status_layout) - self.setLayout(layout) self.zoom_in_btn.clicked.connect(self.zoom_in) @@ -938,7 +931,6 @@ class ImageViewerWidget(QWidget): """加载并显示图像""" if not image_path or not Path(image_path).exists(): self.image_label.setText("图像不存在") - self.status_label.setText("图像加载失败") return self.current_image_path = image_path @@ -947,7 +939,6 @@ class ImageViewerWidget(QWidget): pixmap = QPixmap(image_path) if pixmap.isNull(): self.image_label.setText("无法加载图像") - self.status_label.setText("图像格式不支持") return self.original_pixmap = pixmap @@ -955,7 +946,6 @@ class ImageViewerWidget(QWidget): file_info = Path(image_path).stat() size_mb = file_info.st_size / (1024 * 1024) - self.status_label.setText(f"{pixmap.width()}x{pixmap.height()} | {size_mb:.2f} MB | {Path(image_path).name} | 适应窗口") def update_image_display(self): """更新图像显示 - 使用防抖避免频繁重绘卡顿""" @@ -1031,14 +1021,12 @@ class ImageViewerWidget(QWidget): self.scale_factor = self._fit_scale self.update_image_display() - self.status_label.setText(f"适应窗口 | 缩放: {self.scale_factor:.1%}") def original_size(self): """原始大小""" self.scale_factor = 1.0 self._fit_scale = None self.update_image_display() - self.status_label.setText("原始大小 | 缩放: 100%") def save_image(self): """保存图像""" @@ -1337,9 +1325,17 @@ class Step12VizPanel(QWidget): def init_ui(self): """初始化UI - 使用全新的三列布局(控制参数 | 独立满高目录树 | 图像查看器)""" + + # 1. 补上缺失的主题样式导入! + from src.gui.styles import ModernStylesheet + + # 2. 增加一句热重载安全清理逻辑,彻底消除 QLayout 冲突警告 + if self.layout() is not None: + QWidget().setLayout(self.layout()) + main_layout = QHBoxLayout() - main_layout.setSpacing(12) - main_layout.setContentsMargins(10, 10, 10, 10) + main_layout.setSpacing(16) + main_layout.setContentsMargins(20, 20, 20, 20) # ========================================== # 第一列:控制面板(目录选择 + 生成配置) @@ -1347,6 +1343,7 @@ class Step12VizPanel(QWidget): control_panel = QWidget() control_layout = QVBoxLayout() control_layout.setContentsMargins(0, 0, 0, 0) + control_layout.setSpacing(16) # 1. 工作目录选择 dir_group = QGroupBox("工作目录") @@ -1355,6 +1352,7 @@ class Step12VizPanel(QWidget): self.work_dir_edit.setPlaceholderText("选择工作目录...") self.work_dir_edit.setReadOnly(True) dir_browse_btn = QPushButton("浏览") + dir_browse_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal')) dir_browse_btn.clicked.connect(self.browse_work_dir) dir_layout.addWidget(self.work_dir_edit, 1) dir_layout.addWidget(dir_browse_btn) @@ -1368,6 +1366,7 @@ class Step12VizPanel(QWidget): self.img_dir_edit.setPlaceholderText("预测结果目录(自动填充)…") self.img_dir_edit.setReadOnly(True) img_dir_browse_btn = QPushButton("浏览") + img_dir_browse_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal')) img_dir_browse_btn.clicked.connect(self.browse_img_dir) img_dir_layout.addWidget(self.img_dir_edit, 1) img_dir_layout.addWidget(img_dir_browse_btn) @@ -1375,8 +1374,10 @@ class Step12VizPanel(QWidget): control_layout.addWidget(img_dir_group) # 3. 可视化配置 - config_group = QGroupBox("可视化配置") + config_group = QGroupBox("⚙️ 可视化配置") config_layout = QVBoxLayout() + config_layout.setSpacing(12) + config_layout.setContentsMargins(16, 20, 16, 16) self.gen_scatter = QCheckBox("模型评估散点图") self.gen_scatter.setChecked(True) @@ -1403,33 +1404,34 @@ class Step12VizPanel(QWidget): self.gen_distribution_map.setToolTip("渲染并汇总 Step 11 生成的 TIF 分布图") config_layout.addWidget(self.gen_distribution_map) - config_layout.addSpacing(10) + config_layout.addSpacing(6) line = QFrame() line.setFrameShape(QFrame.HLine) - line.setStyleSheet("color: #ddd;") + line.setStyleSheet("color: #E2E8F0;") config_layout.addWidget(line) - config_layout.addSpacing(10) + config_layout.addSpacing(6) + # 彻底移除硬编码内联样式,全面接入 ModernStylesheet 主题 self.gen_all_btn = QPushButton("🚀 生成全部") - self.gen_all_btn.setToolTip("生成所有类型的可视化图表") - self.gen_all_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 8px; border-radius: 4px;") + self.gen_all_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('primary')) + self.gen_all_btn.setMinimumHeight(36) self.gen_all_btn.clicked.connect(self.generate_all_visualizations) config_layout.addWidget(self.gen_all_btn) self.scan_btn = QPushButton("📁 扫描目录") - self.scan_btn.setToolTip("扫描工作目录中的图像文件") - self.scan_btn.setStyleSheet("padding: 6px; border-radius: 4px;") + self.scan_btn.setStyleSheet(ModernStylesheet.get_button_stylesheet('normal')) + self.scan_btn.setMinimumHeight(36) self.scan_btn.clicked.connect(self.scan_work_directory) config_layout.addWidget(self.scan_btn) config_group.setLayout(config_layout) control_layout.addWidget(config_group) - control_layout.addStretch() # 把控制面板的内容往上顶 + control_layout.addStretch() control_panel.setLayout(control_layout) - control_panel.setMaximumWidth(280) # 稍微收窄第一列 - control_panel.setMinimumWidth(230) - main_layout.addWidget(control_panel, 0) # stretch=0,不横向拉伸 + control_panel.setMaximumWidth(290) + control_panel.setMinimumWidth(250) + main_layout.addWidget(control_panel, 0) # ========================================== # 第二列:满高独立的目录树(选图与筛选面板) @@ -1439,42 +1441,39 @@ class Step12VizPanel(QWidget): tree_layout = QVBoxLayout() tree_layout.setContentsMargins(0, 0, 0, 0) - tree_group = QGroupBox("图像浏览与筛选") + tree_group = QGroupBox("🖼️ 图像浏览与筛选") group_layout = QVBoxLayout() - group_layout.setSpacing(8) + group_layout.setSpacing(12) + group_layout.setContentsMargins(16, 20, 16, 16) - # 添加过滤控制栏 filter_layout = QFormLayout() filter_layout.setContentsMargins(0, 0, 0, 0) + filter_layout.setSpacing(10) - # 分组模式下拉框 + # 彻底摘除下拉框的硬编码外壳,交由系统的全局 CSS 完美接管 self.view_mode_cb = QComboBox() self.view_mode_cb.addItems(["按水质参数归类", "按图表类型归类", "按物理文件夹"]) self.view_mode_cb.currentIndexChanged.connect(self.update_image_tree_view) - self.view_mode_cb.setStyleSheet("QComboBox { padding: 4px; border-radius: 4px; border: 1px solid #ccc; }") - # 图表类型筛选下拉框 self.chart_filter_cb = QComboBox() self.chart_filter_cb.addItems(["全部图表", "空间分布图", "模型散点图", "光谱曲线图", "统计箱线图", "相关性热力图", "掩膜与预览", "采样点地图"]) self.chart_filter_cb.currentIndexChanged.connect(self.update_image_tree_view) - self.chart_filter_cb.setStyleSheet("QComboBox { padding: 4px; border-radius: 4px; border: 1px solid #ccc; }") filter_layout.addRow("视图模式:", self.view_mode_cb) filter_layout.addRow("类型筛选:", self.chart_filter_cb) group_layout.addLayout(filter_layout) - # 挂载新版大树 self.image_tree = ImageCategoryTree() self.image_tree.itemClicked.connect(self.on_tree_item_clicked) - group_layout.addWidget(self.image_tree, 1) # stretch=1 让树垂直填满 + group_layout.addWidget(self.image_tree, 1) tree_group.setLayout(group_layout) - tree_layout.addWidget(tree_group, 1) # stretch=1 让GroupBox垂直填满 + tree_layout.addWidget(tree_group, 1) tree_panel.setLayout(tree_layout) - tree_panel.setMaximumWidth(320) - tree_panel.setMinimumWidth(260) - main_layout.addWidget(tree_panel, 0) # stretch=0,不抢占右侧图片的宽度 + tree_panel.setMaximumWidth(340) + tree_panel.setMinimumWidth(280) + main_layout.addWidget(tree_panel, 0) # ========================================== # 第三列:图像查看器 @@ -1482,11 +1481,21 @@ class Step12VizPanel(QWidget): right_panel = QWidget() right_layout = QVBoxLayout() right_layout.setContentsMargins(0, 0, 0, 0) + + # 给画板穿上卡片外衣,确保三列视觉上的绝对统称和统一 + viewer_group = QGroupBox("👁️ 图像预览区") + viewer_layout = QVBoxLayout() + viewer_layout.setContentsMargins(8, 20, 8, 8) + self.image_viewer = ImageViewerWidget() self.image_viewer.refresh_btn.clicked.connect(self.scan_work_directory) - right_layout.addWidget(self.image_viewer, 1) + + viewer_layout.addWidget(self.image_viewer, 1) + viewer_group.setLayout(viewer_layout) + + right_layout.addWidget(viewer_group, 1) right_panel.setLayout(right_layout) - main_layout.addWidget(right_panel, 1) # stretch=1,右侧画板填满所有剩余宽度 + main_layout.addWidget(right_panel, 1) self.setLayout(main_layout)