""" 主窗口模块 实现应用程序的主窗口,包括侧边栏导航和主内容区域 集成图片处理功能 """ from PyQt6.QtWidgets import ( QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QStackedWidget, QLabel, QFrame, QScrollArea, QApplication, QFileDialog, QMessageBox ) from PyQt6.QtCore import Qt, QSize, pyqtSignal, QThread, QTimer from PyQt6.QtGui import QIcon, QShortcut, QKeySequence from src.gui.styles import ThemeStyles from src.gui.widgets import ( ScreenshotWidget, ClipboardMonitor, ImagePicker, ImagePreviewWidget, QuickScreenshotHelper, ClipboardImagePicker ) from src.gui.widgets.message_handler import show_info, show_error class MainWindow(QMainWindow): """主窗口类""" # 信号:图片加载完成 image_loaded = pyqtSignal(str) def __init__(self): """初始化主窗口""" super().__init__() self.setWindowTitle("CutThenThink - 智能截图管理") self.setMinimumSize(1000, 700) self.resize(1200, 800) # 图片处理组件 self.screenshot_widget = None self.clipboard_monitor = None self.current_image_path = None # 初始化 UI self._init_ui() self._apply_styles() self._init_shortcuts() # 初始化图片处理组件 self._init_image_components() def _init_ui(self): """初始化用户界面""" # 创建中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) # 主布局 main_layout = QHBoxLayout(central_widget) main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) # 创建侧边栏 self._create_sidebar(main_layout) # 创建主内容区域 self._create_content_area(main_layout) def _create_sidebar(self, parent_layout): """ 创建侧边栏 Args: parent_layout: 父布局 """ # 侧边栏容器 sidebar = QWidget() sidebar.setObjectName("sidebar") sidebar.setFixedWidth(240) # 侧边栏布局 sidebar_layout = QVBoxLayout(sidebar) sidebar_layout.setContentsMargins(8, 16, 8, 16) sidebar_layout.setSpacing(4) # 应用标题 app_title = QLabel("CutThenThink") app_title.setStyleSheet(""" QLabel { color: #8B6914; font-size: 20px; font-weight: 700; padding: 8px; } """) sidebar_layout.addWidget(app_title) # 添加分隔线 separator1 = self._create_separator() sidebar_layout.addWidget(separator1) # 导航按钮组 self.nav_buttons = {} nav_items = [ ("screenshot", "📷 截图处理", "screenshot"), ("browse", "📁 分类浏览", "browse"), ("upload", "☁️ 批量上传", "upload"), ("settings", "⚙️ 设置", "settings"), ] for nav_id, text, _icon_name in nav_items: button = NavigationButton(text) button.clicked.connect(lambda checked, nid=nav_id: self._on_nav_clicked(nid)) sidebar_layout.addWidget(button) self.nav_buttons[nav_id] = button # 添加弹性空间 sidebar_layout.addStretch() # 底部信息 version_label = QLabel("v0.1.0") version_label.setAlignment(Qt.AlignmentFlag.AlignCenter) version_label.setStyleSheet(""" QLabel { color: #999999; font-size: 11px; padding: 8px; } """) sidebar_layout.addWidget(version_label) # 添加到主布局 parent_layout.addWidget(sidebar) # 设置默认选中的导航项 self.nav_buttons["screenshot"].setChecked(True) self.current_nav = "screenshot" def _create_content_area(self, parent_layout): """ 创建主内容区域 Args: parent_layout: 父布局 """ # 内容区域容器 content_area = QWidget() content_area.setObjectName("contentArea") # 内容区域布局 content_layout = QVBoxLayout(content_area) content_layout.setContentsMargins(24, 16, 24, 16) content_layout.setSpacing(16) # 创建堆栈部件用于切换页面 self.content_stack = QStackedWidget() self.content_stack.setObjectName("contentStack") # 创建各个页面 self._create_pages() content_layout.addWidget(self.content_stack) # 添加到主布局 parent_layout.addWidget(content_area) def _create_pages(self): """创建各个页面""" # 截图处理页面 screenshot_page = self._create_screenshot_page() self.content_stack.addWidget(screenshot_page) # 分类浏览页面 browse_page = self._create_browse_page() self.content_stack.addWidget(browse_page) # 批量上传页面 upload_page = self._create_upload_page() self.content_stack.addWidget(upload_page) # 设置页面 settings_page = self._create_settings_page() self.content_stack.addWidget(settings_page) def _create_screenshot_page(self) -> QWidget: """创建截图处理页面""" page = QWidget() layout = QVBoxLayout(page) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(16) # 页面标题 title = QLabel("📷 截图处理") title.setObjectName("pageTitle") layout.addWidget(title) # 快捷操作按钮区域 actions_card = self._create_card("") actions_layout = QVBoxLayout(actions_card) actions_layout.setSpacing(12) actions_title = QLabel("快捷操作") actions_title.setObjectName("sectionTitle") actions_layout.addWidget(actions_title) # 新建截图按钮 self.new_screenshot_btn = QPushButton("📷 新建截图") self.new_screenshot_btn.setObjectName("primaryButton") self.new_screenshot_btn.setMinimumHeight(44) self.new_screenshot_btn.setToolTip("快捷键: Ctrl+Shift+A") self.new_screenshot_btn.clicked.connect(self._on_new_screenshot) actions_layout.addWidget(self.new_screenshot_btn) # 导入图片按钮 self.import_image_btn = QPushButton("📂 导入图片") self.import_image_btn.setMinimumHeight(44) self.import_image_btn.clicked.connect(self._on_import_image) actions_layout.addWidget(self.import_image_btn) # 粘贴剪贴板图片按钮 self.paste_btn = QPushButton("📋 粘贴剪贴板图片") self.paste_btn.setMinimumHeight(44) self.paste_btn.setToolTip("快捷键: Ctrl+Shift+V") self.paste_btn.clicked.connect(self._on_paste_clipboard) actions_layout.addWidget(self.paste_btn) layout.addWidget(actions_card) # 图片预览区域 preview_card = self._create_card("") preview_layout = QVBoxLayout(preview_card) preview_layout.setContentsMargins(16, 16, 16, 16) preview_layout.setSpacing(12) preview_title = QLabel("图片预览") preview_title.setObjectName("sectionTitle") preview_layout.addWidget(preview_title) # 创建图片预览组件 self.image_preview = ImagePreviewWidget() preview_layout.addWidget(self.image_preview) layout.addWidget(preview_card, 1) return page def _create_browse_page(self) -> QWidget: """创建分类浏览页面""" page = QWidget() layout = QVBoxLayout(page) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(16) # 页面标题 title = QLabel("📁 分类浏览") title.setObjectName("pageTitle") layout.addWidget(title) # 内容卡片 content_card = self._create_card("""
这里将显示您的所有截图和分类。
支持的浏览方式:
这里将管理您的云存储上传任务。
功能包括:
配置您的 AI 服务提供商和 API 设置。
支持:OpenAI、Anthropic、Azure
""") scroll_layout.addWidget(ai_card) # OCR 配置卡片 ocr_card = self._create_card("""配置云端 OCR 服务。
支持:百度 OCR、腾讯云 OCR、阿里云 OCR、自定义 API
""") scroll_layout.addWidget(ocr_card) # 云存储配置卡片 cloud_card = self._create_card("""配置云存储服务用于同步。
支持:S3、OSS、COS、MinIO
""") scroll_layout.addWidget(cloud_card) # 界面配置卡片 ui_card = self._create_card("""自定义应用程序外观和行为。
主题、语言、快捷键等
""") scroll_layout.addWidget(ui_card) # 添加弹性空间 scroll_layout.addStretch() scroll.setWidget(scroll_content) layout.addWidget(scroll) return page def _create_card(self, content_html: str) -> QWidget: """ 创建卡片部件 Args: content_html: 卡片内容的 HTML Returns: 卡片部件 """ card = QWidget() card.setObjectName("card") layout = QVBoxLayout(card) layout.setContentsMargins(0, 0, 0, 0) label = QLabel(content_html) label.setWordWrap(True) label.setTextFormat(Qt.TextFormat.RichText) label.setStyleSheet(""" QLabel { color: #2C2C2C; font-size: 14px; line-height: 1.6; } QLabel h2 { color: #8B6914; font-size: 20px; font-weight: 600; margin-bottom: 8px; } QLabel h3 { color: #8B6914; font-size: 16px; font-weight: 600; margin-bottom: 6px; } QLabel p { margin: 4px 0; } QLabel ul { margin: 8px 0; padding-left: 20px; } QLabel li { margin: 4px 0; } """) layout.addWidget(label) return card def _create_separator(self) -> QFrame: """创建分隔线""" separator = QFrame() separator.setObjectName("navSeparator") return separator def _on_nav_clicked(self, nav_id: str): """ 导航按钮点击处理 Args: nav_id: 导航项 ID """ # 取消当前选中的按钮 if self.current_nav in self.nav_buttons: self.nav_buttons[self.current_nav].setChecked(False) # 选中新按钮 self.nav_buttons[nav_id].setChecked(True) self.current_nav = nav_id # 切换页面 nav_order = ["screenshot", "browse", "upload", "settings"] if nav_id in nav_order: index = nav_order.index(nav_id) self.content_stack.setCurrentIndex(index) def _apply_styles(self): """应用样式表""" ThemeStyles.apply_style(self) def _init_shortcuts(self): """初始化全局快捷键""" # 截图快捷键 Ctrl+Shift+A screenshot_shortcut = QShortcut(QKeySequence("Ctrl+Shift+A"), self) screenshot_shortcut.activated.connect(self._on_new_screenshot) # 粘贴剪贴板快捷键 Ctrl+Shift+V paste_shortcut = QShortcut(QKeySequence("Ctrl+Shift+V"), self) paste_shortcut.activated.connect(self._on_paste_clipboard) # 导入图片快捷键 Ctrl+Shift+O import_shortcut = QShortcut(QKeySequence("Ctrl+Shift+O"), self) import_shortcut.activated.connect(self._on_import_image) def _init_image_components(self): """初始化图片处理组件""" # 创建截图组件 self.screenshot_widget = ScreenshotWidget(self) self.screenshot_widget.screenshot_saved.connect(self._on_screenshot_saved) # 注册到全局助手 QuickScreenshotHelper.set_screenshot_widget(self.screenshot_widget) # 创建剪贴板监听器 self.clipboard_monitor = ClipboardMonitor(self) self.clipboard_monitor.image_detected.connect(self._on_clipboard_image_detected) # ========== 图片处理方法 ========== def _on_new_screenshot(self): """新建截图""" if self.screenshot_widget: self.screenshot_widget.take_screenshot() def _on_screenshot_saved(self, filepath: str): """ 截图保存完成回调 Args: filepath: 保存的文件路径 """ self.current_image_path = filepath # 加载到预览组件 self.image_preview.load_image(filepath) show_info(self, "截图完成", f"截图已保存到:\n{filepath}") self.image_loaded.emit(filepath) def _on_import_image(self): """导入图片""" filepath, _ = QFileDialog.getOpenFileName( self, "选择图片", "", "图片文件 (*.png *.jpg *.jpeg *.bmp *.gif *.webp);;所有文件 (*.*)" ) if filepath: self.current_image_path = filepath self.image_preview.load_image(filepath) show_info(self, "导入成功", f"图片已导入:\n{filepath}") self.image_loaded.emit(filepath) def _on_paste_clipboard(self): """粘贴剪贴板图片""" clipboard = QApplication.clipboard() pixmap = clipboard.pixmap() if pixmap.isNull(): show_error(self, "错误", "剪贴板中没有图片") return # 保存剪贴板图片 from datetime import datetime from pathlib import Path import tempfile temp_dir = Path(tempfile.gettempdir()) / "cutthenthink" / "clipboard" temp_dir.mkdir(parents=True, exist_ok=True) timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") filepath = temp_dir / f"clipboard_{timestamp}.png" if pixmap.save(str(filepath)): self.current_image_path = filepath self.image_preview.load_image(filepath) show_info(self, "粘贴成功", f"剪贴板图片已保存:\n{filepath}") self.image_loaded.emit(filepath) else: show_error(self, "错误", "保存剪贴板图片失败") def _on_clipboard_image_detected(self, filepath: str): """ 剪贴板图片检测回调 Args: filepath: 保存的图片路径 """ # 可选:自动加载剪贴板图片或显示通知 pass class NavigationButton(QPushButton): """导航按钮类""" def __init__(self, text: str, icon_path: str = None, parent=None): """ 初始化导航按钮 Args: text: 按钮文字 icon_path: 图标路径(可选) parent: 父部件 """ super().__init__(text, parent) self.setObjectName("navButton") self.setCheckable(True) self.setMinimumHeight(44) # 如果有图标,加载图标 if icon_path: self.setIcon(QIcon(icon_path)) self.setIconSize(QSize(20, 20)) def main(): """ 应用程序入口 初始化并显示主窗口 """ app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec())