#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2025 Any2MIF Project # All rights reserved. """ Any2MIF - 主窗口类 包含应用程序的主界面和核心功能组织 """ import os import sys from PyQt6.QtWidgets import ( QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QSplitter, QStatusBar, QToolBar, QMessageBox, QFileDialog, QGroupBox, QLabel ) from PyQt6.QtCore import Qt, QSettings, QSize, QTimer from PyQt6.QtGui import QIcon, QAction from ui.file_selector import FileSelector from ui.param_panel import ParamPanel from ui.image_toolbar import ImageToolbar from ui.theme_controller import ThemeController from core.converter import MifConverter from core.batch_manager import BatchManager from core.image_processor import ImageProcessor class MainWindow(QMainWindow): """主窗口类""" def __init__(self, settings: QSettings, parent=None): """初始化主窗口""" super().__init__(parent) self.settings = settings self.converter = MifConverter() self.batch_manager = BatchManager(self.converter) self.image_processor = ImageProcessor() self._init_ui() self._load_settings() self._connect_signals() def _init_ui(self): """初始化UI""" # 设置窗口属性 self.setWindowTitle("Any2MIF - 文件转换器") self.setMinimumSize(900, 600) # 创建中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) # 创建主布局 main_layout = QVBoxLayout(central_widget) main_layout.setContentsMargins(10, 10, 10, 10) main_layout.setSpacing(10) # 创建左侧面板 left_panel = QWidget() left_layout = QVBoxLayout(left_panel) left_layout.setContentsMargins(0, 0, 0, 0) left_layout.setSpacing(10) # 创建文件选择器 self.file_selector = FileSelector(self.settings) left_layout.addWidget(self.file_selector) # 创建图像预览标签 preview_group = QGroupBox("图像预览") preview_layout = QVBoxLayout(preview_group) self.preview_label = QLabel() self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter) # 设置固定高度而不是最小高度,确保在整个应用程序运行期间保持一致 self.preview_label.setFixedHeight(200) self.preview_label.setStyleSheet("background-color: #333333; border: 1px solid #5d5d5d;") preview_layout.addWidget(self.preview_label) left_layout.addWidget(preview_group) # 创建右侧面板 right_panel = QWidget() right_layout = QVBoxLayout(right_panel) right_layout.setContentsMargins(0, 0, 0, 0) right_layout.setSpacing(10) # 创建参数配置面板 self.param_panel = ParamPanel(self.settings) right_layout.addWidget(self.param_panel) # 创建图像处理工具栏 self.image_toolbar = ImageToolbar(self.image_processor, self.settings, self.preview_label) right_layout.addWidget(self.image_toolbar) # 创建分割器 splitter = QSplitter(Qt.Orientation.Horizontal) splitter.addWidget(left_panel) splitter.addWidget(right_panel) main_layout.addWidget(splitter) # 设置分割器比例 splitter.setSizes([int(self.width() * 0.4), int(self.width() * 0.6)]) # 创建状态栏 self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) self.status_bar.showMessage("就绪") # 创建主题控制器(不显示在界面上) self.theme_controller = ThemeController(self.settings) def _load_settings(self): """加载设置""" # 恢复窗口几何形状 geometry = self.settings.value("geometry") if geometry: self.restoreGeometry(geometry) # 应用主题(锁定为深色模式) self.theme_controller.apply_theme("dark") def _connect_signals(self): """连接信号和槽""" # 文件选择器信号 self.file_selector.file_selected.connect(self.on_file_selected) self.file_selector.convert_clicked.connect(self.convert_files) self.file_selector.batch_convert_clicked.connect(self.batch_convert) # 主题控制器信号 self.theme_controller.theme_changed.connect(self.on_theme_changed) # 批量管理器信号 self.batch_manager.progress_updated.connect(self.update_progress) self.batch_manager.conversion_completed.connect(self.on_conversion_completed) def on_file_selected(self, file_path): """处理文件选择事件""" self.status_bar.showMessage(f"已选择文件: {os.path.basename(file_path)}") # 如果是图像文件,启用图像处理工具栏 if self.image_processor.is_image_file(file_path): self.image_toolbar.setEnabled(True) self.image_toolbar.load_image(file_path) # 确保预览标签显示图像 self.preview_label.setVisible(True) else: self.image_toolbar.setEnabled(False) # 隐藏预览标签 self.preview_label.setVisible(False) def on_theme_changed(self, theme): """处理主题变更事件""" self.settings.setValue("theme", theme) def update_progress(self, current, total, file_name): """更新进度信息""" self.status_bar.showMessage(f"正在转换 {file_name}... ({current}/{total})") def on_conversion_completed(self, success_count, fail_count): """处理转换完成事件""" self.status_bar.showMessage(f"转换完成。成功: {success_count}, 失败: {fail_count}") if success_count > 0: QMessageBox.information( self, "转换完成", f"已成功转换 {success_count} 个文件" + (f",{fail_count} 个文件失败" if fail_count > 0 else "") ) elif fail_count > 0: QMessageBox.warning( self, "转换失败", f"所有 {fail_count} 个文件转换失败" ) def convert_files(self): """转换选定的文件""" files = self.file_selector.get_selected_files() if not files: QMessageBox.warning(self, "警告", "请先选择要转换的文件") return # 获取输出目录 output_dir = QFileDialog.getExistingDirectory( self, "选择输出目录", os.path.expanduser("~") ) if not output_dir: return # 获取转换参数 params = self.param_panel.get_params() # 执行转换 for file_path in files: try: # 如果是图像文件且图像处理工具栏已启用,先处理图像 if self.image_processor.is_image_file(file_path) and self.image_toolbar.isEnabled(): processed_image = self.image_toolbar.get_processed_image() if processed_image: # 直接使用处理后的图像进行转换,而不是保存为临时文件 output_file = os.path.join( output_dir, f"{os.path.splitext(os.path.basename(file_path))[0]}.mif" ) self.converter.convert_from_image(processed_image, output_file, params) else: # 如果没有处理后的图像,使用原始文件 output_file = os.path.join( output_dir, f"{os.path.splitext(os.path.basename(file_path))[0]}.mif" ) self.converter.convert(file_path, output_file, params) else: # 非图像文件或图像处理工具栏未启用,直接转换 output_file = os.path.join( output_dir, f"{os.path.splitext(os.path.basename(file_path))[0]}.mif" ) self.converter.convert(file_path, output_file, params) self.status_bar.showMessage(f"已转换: {os.path.basename(file_path)}") except Exception as e: QMessageBox.critical(self, "转换错误", f"转换文件 {os.path.basename(file_path)} 时出错: {str(e)}") QMessageBox.information(self, "转换完成", "文件转换完成") def batch_convert(self): """批量转换文件""" files = self.file_selector.get_selected_files() if not files: QMessageBox.warning(self, "警告", "请先选择要转换的文件") return # 获取输出目录 output_dir = QFileDialog.getExistingDirectory( self, "选择输出目录", os.path.expanduser("~") ) if not output_dir: return # 获取转换参数 params = self.param_panel.get_params() # 检查是否有需要预处理的图像 processed_image = None if self.image_toolbar.isEnabled(): processed_image = self.image_toolbar.get_processed_image() # 启动批量转换,传递处理后的图像 self.batch_manager.start_batch(files, output_dir, params, processed_image) def closeEvent(self, event): """处理窗口关闭事件""" # 保存窗口几何形状 self.settings.setValue("geometry", self.saveGeometry()) super().closeEvent(event)