From c293f420c24eea9707afe9c2432ab069c9d87a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E5=85=B4=E9=9C=96?= <3189844089@qq.com> Date: Mon, 27 Oct 2025 10:58:05 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E5=AD=97=E4=BD=93=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/word_style_ui.py | 45 +++++++++++++++++++ src/word_main_window.py | 22 +++++++++- test_color_feature.py | 66 ++++++++++++++++++++++++++++ test_color_preserve.py | 78 ++++++++++++++++++++++++++++++++ 字体颜色功能说明.md | 88 +++++++++++++++++++++++++++++++++++++ 5 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 test_color_feature.py create mode 100644 test_color_preserve.py create mode 100644 字体颜色功能说明.md diff --git a/src/ui/word_style_ui.py b/src/ui/word_style_ui.py index 98c29f3..8b36789 100644 --- a/src/ui/word_style_ui.py +++ b/src/ui/word_style_ui.py @@ -96,9 +96,14 @@ class WordRibbon(QFrame): self.underline_btn = self.create_toggle_button("U", "underline") self.underline_btn.clicked.connect(self.on_underline_clicked) + # 字体颜色按钮 + self.color_btn = self.create_color_button("A", "color") + self.color_btn.clicked.connect(self.on_color_clicked) + font_style_layout.addWidget(self.bold_btn) font_style_layout.addWidget(self.italic_btn) font_style_layout.addWidget(self.underline_btn) + font_style_layout.addWidget(self.color_btn) font_main_layout = QVBoxLayout() font_main_layout.addLayout(font_layout) @@ -146,6 +151,17 @@ class WordRibbon(QFrame): editing_group.setLayout(editing_layout) layout.addWidget(editing_group) + # 数学公式组 + math_group = self.create_ribbon_group("数学公式") + self.formula_btn = self.create_ribbon_button("插入公式", "Alt+=", "formula") + self.equation_btn = self.create_ribbon_button("快速公式", "", "equation") + + math_layout = QVBoxLayout() + math_layout.addWidget(self.formula_btn) + math_layout.addWidget(self.equation_btn) + math_group.setLayout(math_layout) + layout.addWidget(math_group) + layout.addStretch() def on_font_changed(self, font): @@ -168,6 +184,10 @@ class WordRibbon(QFrame): """下划线按钮点击处理""" pass + def on_color_clicked(self): + """字体颜色按钮点击处理""" + pass + def create_weather_group(self): """创建天气组件组""" if self.weather_group is not None: @@ -433,6 +453,31 @@ class WordRibbon(QFrame): } """) return btn + + def create_color_button(self, text, icon_name): + """创建颜色选择按钮""" + btn = QToolButton() + btn.setText(text) + btn.setToolButtonStyle(Qt.ToolButtonTextOnly) + btn.setFixedSize(30, 25) + btn.setStyleSheet(""" + QToolButton { + border: 1px solid #d0d0d0; + border-radius: 2px; + background-color: transparent; + font-size: 12px; + font-weight: bold; + color: #333333; + } + QToolButton:hover { + background-color: #f0f0f0; + } + QToolButton:pressed { + background-color: #e1e1e1; + border: 1px solid #c0c0c0; + } + """) + return btn class WordStatusBar(QStatusBar): def __init__(self, parent=None): diff --git a/src/word_main_window.py b/src/word_main_window.py index aa4e950..8f88747 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -517,8 +517,9 @@ class WordStyleMainWindow(QMainWindow): self.ribbon.font_combo.currentFontChanged.connect(self.on_font_changed) self.ribbon.font_size_combo.currentTextChanged.connect(self.on_font_size_changed) self.ribbon.bold_btn.clicked.connect(self.on_bold_clicked) - self.ribbon.italic_btn.clicked.connect(self.on_italic_clicked) - self.ribbon.underline_btn.clicked.connect(self.on_underline_clicked) + self.ribbon.italic_btn.clicked.connect(self.on_italic_clicked) + self.ribbon.underline_btn.clicked.connect(self.on_underline_clicked) + self.ribbon.color_btn.clicked.connect(self.on_color_clicked) # 查找和替换按钮信号 if hasattr(self.ribbon, 'find_btn'): @@ -920,6 +921,23 @@ class WordStyleMainWindow(QMainWindow): # 如果没有选中文本,更改整个文档的默认下划线样式 self.text_edit.setFontUnderline(checked) + def on_color_clicked(self): + """字体颜色按钮点击处理 - 保留之前内容的颜色""" + from PyQt5.QtWidgets import QColorDialog + + # 显示颜色选择对话框,默认使用当前文本颜色 + current_color = self.text_edit.textColor() + color = QColorDialog.getColor(current_color, self, "选择字体颜色") + + if color.isValid(): + # 只设置后续输入的默认颜色,不影响已有内容 + self.text_edit.setTextColor(color) + + # 如果有选中文本,提示用户颜色只对新输入生效 + cursor = self.text_edit.textCursor() + if cursor.hasSelection(): + self.status_bar.showMessage("字体颜色已设置,新输入的文本将使用该颜色", 2000) + def update_weather_display(self, weather_data): """更新天气显示""" if 'error' in weather_data: diff --git a/test_color_feature.py b/test_color_feature.py new file mode 100644 index 0000000..46b39ed --- /dev/null +++ b/test_color_feature.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +""" +测试字体颜色功能的简单脚本 +""" + +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'src')) + +from PyQt5.QtWidgets import QApplication, QTextEdit, QPushButton, QVBoxLayout, QWidget, QColorDialog +from PyQt5.QtGui import QColor, QTextCharFormat, QTextCursor +from PyQt5.QtCore import Qt + +def test_color_function(): + """测试字体颜色功能""" + app = QApplication(sys.argv) + + # 创建主窗口 + window = QWidget() + window.setWindowTitle("字体颜色测试") + window.setGeometry(100, 100, 400, 300) + + # 创建文本编辑器 + text_edit = QTextEdit() + text_edit.setPlainText("这是一段测试文本。请选择这段文字并点击颜色按钮来更改颜色。") + + # 创建颜色按钮 + color_btn = QPushButton("选择颜色") + + def change_color(): + """更改字体颜色""" + color = QColorDialog.getColor(Qt.black, window, "选择字体颜色") + if color.isValid(): + cursor = text_edit.textCursor() + if cursor.hasSelection(): + # 如果有选中文本,只更改选中文本的颜色 + fmt = cursor.charFormat() + fmt.setForeground(color) + cursor.setCharFormat(fmt) + print(f"已更改选中文本颜色为: {color.name()}") + else: + # 如果没有选中文本,更改整个文档的默认颜色 + text_edit.setTextColor(color) + print(f"已更改默认文本颜色为: {color.name()}") + + color_btn.clicked.connect(change_color) + + # 布局 + layout = QVBoxLayout() + layout.addWidget(text_edit) + layout.addWidget(color_btn) + + window.setLayout(layout) + window.show() + + print("字体颜色测试窗口已打开") + print("操作说明:") + print("1. 在文本编辑器中选择一些文字") + print("2. 点击'选择颜色'按钮") + print("3. 选择颜色并确认") + print("4. 观察选中文本的颜色是否改变") + + sys.exit(app.exec_()) + +if __name__ == "__main__": + test_color_function() \ No newline at end of file diff --git a/test_color_preserve.py b/test_color_preserve.py new file mode 100644 index 0000000..9967736 --- /dev/null +++ b/test_color_preserve.py @@ -0,0 +1,78 @@ +# 字体颜色功能测试脚本 - 验证保留之前内容的颜色 +import sys +from PyQt5.QtWidgets import QApplication, QTextEdit, QPushButton, QVBoxLayout, QWidget, QColorDialog +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QColor, QTextCharFormat, QFont + +class ColorTestWindow(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle("字体颜色功能测试 - 保留之前内容的颜色") + self.setGeometry(100, 100, 600, 400) + + layout = QVBoxLayout() + + # 创建文本编辑器 + self.text_edit = QTextEdit() + self.text_edit.setPlainText("这是一段测试文本。\n这行文字将保持原有颜色。\n新输入的文字将使用新颜色。") + + # 设置一些初始颜色来模拟原有内容 + cursor = self.text_edit.textCursor() + cursor.select(cursor.Document) + cursor.setPosition(0) + + # 给第一行设置红色 + cursor.movePosition(cursor.StartOfLine) + cursor.movePosition(cursor.EndOfLine, cursor.KeepAnchor) + fmt = QTextCharFormat() + fmt.setForeground(QColor("red")) + cursor.setCharFormat(fmt) + + # 给第二行设置蓝色 + cursor.movePosition(cursor.NextBlock) + cursor.movePosition(cursor.EndOfLine, cursor.KeepAnchor) + fmt.setForeground(QColor("blue")) + cursor.setCharFormat(fmt) + + layout.addWidget(self.text_edit) + + # 创建颜色选择按钮 + self.color_btn = QPushButton("选择新颜色(保留原有内容颜色)") + self.color_btn.clicked.connect(self.on_color_clicked) + layout.addWidget(self.color_btn) + + # 创建说明标签 + self.info_label = QLabel("点击按钮选择颜色,新输入的文本将使用新颜色,原有内容颜色保持不变") + layout.addWidget(self.info_label) + + self.setLayout(layout) + + def on_color_clicked(self): + """字体颜色按钮点击处理 - 保留之前内容的颜色""" + # 显示颜色选择对话框,默认使用当前文本颜色 + current_color = self.text_edit.textColor() + color = QColorDialog.getColor(current_color, self, "选择字体颜色") + + if color.isValid(): + # 只设置后续输入的默认颜色,不影响已有内容 + self.text_edit.setTextColor(color) + + # 如果有选中文本,提示用户颜色只对新输入生效 + cursor = self.text_edit.textCursor() + if cursor.hasSelection(): + self.info_label.setText("字体颜色已设置,新输入的文本将使用该颜色(原有内容颜色保持不变)") + else: + self.info_label.setText(f"新颜色已设置: {color.name()},后续输入将使用该颜色") + +if __name__ == "__main__": + app = QApplication(sys.argv) + window = ColorTestWindow() + window.show() + + print("测试说明:") + print("1. 文本编辑器中有三行文字,第一行红色,第二行蓝色,第三行默认黑色") + print("2. 点击颜色选择按钮选择新颜色") + print("3. 在文本末尾输入新文字,观察新文字使用新颜色而原有文字颜色不变") + print("4. 测试验证:保留之前内容的颜色功能是否正常工作") + + sys.exit(app.exec_()) \ No newline at end of file diff --git a/字体颜色功能说明.md b/字体颜色功能说明.md new file mode 100644 index 0000000..5f2b43e --- /dev/null +++ b/字体颜色功能说明.md @@ -0,0 +1,88 @@ +# 字体颜色功能说明 + +我已经成功为你的MagicWord应用添加了字体颜色工具!以下是添加的功能: + +## 🎯 重要更新:保留之前内容的颜色 + +**根据你的需求,字体颜色功能已修改为保留原有内容的颜色!** + +### 修改后的功能特性 +- ✅ **保留原有内容颜色**:已有文本的颜色完全保持不变 +- ✅ **只影响新输入**:新输入的文本将使用选定的颜色 +- ✅ **智能提示**:选择文本时会提示颜色只对新输入生效 +- ✅ **向后兼容**:不会影响现有的粗体、斜体、下划线等格式 + +## 新增功能 + +### 1. 字体颜色按钮 +- 在"开始"标签页的"字体"组中,添加了一个新的颜色按钮(显示为"A") +- 该按钮位于加粗(B)、斜体(I)、下划线(U)按钮的右侧 + +### 2. 颜色选择功能 +- 点击颜色按钮会弹出颜色选择对话框 +- 用户可以选择任意颜色 +- **重要**:只影响后续输入的文本,不会改变已有内容的颜色 + +## 技术实现 + +### UI界面修改 +1. **word_style_ui.py** 中添加了: + - `color_btn` 按钮创建 + - `create_color_button()` 方法用于创建颜色按钮 + - `on_color_clicked()` 方法作为按钮点击事件的处理函数 + +2. **word_main_window.py** 中修改了: + - 颜色按钮的信号连接 + - `on_color_clicked()` 方法:简化为只设置默认颜色,不影响已有内容 + +### 功能特性 +- 使用 PyQt5 的 `QColorDialog` 提供颜色选择界面 +- **只设置默认文本颜色**,不修改已有内容的格式 +- 智能状态栏提示,告知用户颜色的应用范围 +- 保持与现有字体样式(粗体、斜体、下划线)的一致性 + +## 使用方法 + +### 设置新文本颜色 +1. 点击颜色按钮(A) +2. 在弹出的颜色对话框中选择所需颜色 +3. 点击"确定" +4. **后续输入的所有文本都将使用该颜色** +5. **已有文本的颜色完全保持不变** + +### 颜色选择提示 +- 如果选择了文本,会提示:"字体颜色已设置,新输入的文本将使用该颜色" +- 如果没有选择文本,会显示新颜色的具体信息 + +## 界面位置 + +字体颜色工具位于: +开始标签页 → 字体组 → 样式按钮区域(B、I、U按钮右侧) + +## 🔧 技术实现细节 + +### 修改后的核心逻辑 +```python +def on_color_clicked(self): + """字体颜色按钮点击处理 - 保留之前内容的颜色""" + # 只设置后续输入的默认颜色,不影响已有内容 + self.text_edit.setTextColor(color) + + # 友好的用户提示 + if cursor.hasSelection(): + self.status_bar.showMessage("字体颜色已设置,新输入的文本将使用该颜色", 2000) +``` + +这个实现确保: +- ✅ 用户可以自由设置新文本的颜色 +- ✅ 所有已有内容的颜色完全保留 +- ✅ 用户体验友好,有明确的操作反馈 + +## 🚀 优势 + +1. **非破坏性**:不会意外改变已有内容的格式 +2. **直观易用**:用户明确知道颜色设置的影响范围 +3. **灵活性高**:可以随时更改新文本的颜色而不影响历史内容 +4. **兼容性好**:与所有现有功能完美配合 + +这个新增功能与现有的字体样式工具完美集成,提供了完整且安全的文本格式化能力! \ No newline at end of file -- 2.34.1 From dc28b1708e9ff3ef5dd7b8c9ae5105845c5dfb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=B3=E5=85=B4=E9=9C=96?= <3189844089@qq.com> Date: Mon, 27 Oct 2025 10:58:30 +0800 Subject: [PATCH 02/11] 222 --- src/ui/word_style_ui.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ui/word_style_ui.py b/src/ui/word_style_ui.py index 8b36789..693f307 100644 --- a/src/ui/word_style_ui.py +++ b/src/ui/word_style_ui.py @@ -151,17 +151,6 @@ class WordRibbon(QFrame): editing_group.setLayout(editing_layout) layout.addWidget(editing_group) - # 数学公式组 - math_group = self.create_ribbon_group("数学公式") - self.formula_btn = self.create_ribbon_button("插入公式", "Alt+=", "formula") - self.equation_btn = self.create_ribbon_button("快速公式", "", "equation") - - math_layout = QVBoxLayout() - math_layout.addWidget(self.formula_btn) - math_layout.addWidget(self.equation_btn) - math_group.setLayout(math_layout) - layout.addWidget(math_group) - layout.addStretch() def on_font_changed(self, font): -- 2.34.1 From cdcd943ac8cf0f00bda9ac66e771d3f696949c91 Mon Sep 17 00:00:00 2001 From: Lesacm <1500309685@qq.com> Date: Mon, 27 Oct 2025 11:02:24 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E5=A4=B4=E9=83=A8UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/word_main_window.py | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/word_main_window.py b/src/word_main_window.py index 41b49b8..a570d74 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -302,40 +302,40 @@ class WordStyleMainWindow(QMainWindow): exit_action.triggered.connect(self.close) file_menu.addAction(exit_action) - # 编辑菜单 - edit_menu = menubar.addMenu('编辑(E)') + # 开始菜单 + start_menu = menubar.addMenu('开始(S)') # 撤销 undo_action = QAction('撤销(U)', self) undo_action.setShortcut('Ctrl+Z') undo_action.triggered.connect(self.undo) - edit_menu.addAction(undo_action) + start_menu.addAction(undo_action) # 重做 redo_action = QAction('重做(R)', self) redo_action.setShortcut('Ctrl+Y') redo_action.triggered.connect(self.redo) - edit_menu.addAction(redo_action) + start_menu.addAction(redo_action) - edit_menu.addSeparator() + start_menu.addSeparator() # 剪切 cut_action = QAction('剪切(T)', self) cut_action.setShortcut('Ctrl+X') cut_action.triggered.connect(self.cut) - edit_menu.addAction(cut_action) + start_menu.addAction(cut_action) # 复制 copy_action = QAction('复制(C)', self) copy_action.setShortcut('Ctrl+C') copy_action.triggered.connect(self.copy) - edit_menu.addAction(copy_action) + start_menu.addAction(copy_action) # 粘贴 paste_action = QAction('粘贴(P)', self) paste_action.setShortcut('Ctrl+V') paste_action.triggered.connect(self.paste) - edit_menu.addAction(paste_action) + start_menu.addAction(paste_action) # 视图菜单 view_menu = menubar.addMenu('视图(V)') @@ -402,7 +402,24 @@ class WordStyleMainWindow(QMainWindow): show_weather_action = QAction('显示详细天气', self) show_weather_action.triggered.connect(self.show_detailed_weather) weather_menu.addAction(show_weather_action) - + #插入 + insert_menu = menubar.addMenu('插入(I)') + #绘图 + paint_menu = menubar.addMenu('绘图(D)') + #设计 + design_menu = menubar.addMenu('设计(G)') + #布局 + layout_menu = menubar.addMenu('布局(L)') + #引用 + reference_menu = menubar.addMenu('引用(R)') + #邮件 + mail_menu = menubar.addMenu('邮件(M)') + #审阅 + review_menu = menubar.addMenu('审阅(W)') + #视图 + view_menu = menubar.addMenu('视图(V)') + #开发工具 + developer_menu = menubar.addMenu('开发工具(Q)') # 帮助菜单 help_menu = menubar.addMenu('帮助(H)') @@ -410,7 +427,8 @@ class WordStyleMainWindow(QMainWindow): about_action = QAction('关于 MagicWord', self) about_action.triggered.connect(self.show_about) help_menu.addAction(about_action) - + + def create_document_area(self, main_layout): """创建文档编辑区域""" -- 2.34.1 From ba63017a376265495267972433ca2725dcceccdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Mon, 27 Oct 2025 21:35:56 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix(word=5Fmain=5Fwindow):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=8F=9C=E5=8D=95=E6=A0=8F=E5=9C=A8macOS=E4=B8=8A?= =?UTF-8?q?=E7=9A=84=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 设置menubar.setNativeMenuBar(False)以确保菜单栏样式在macOS上正确应用 --- src/word_main_window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/word_main_window.py b/src/word_main_window.py index 91a4217..3a18006 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -247,6 +247,7 @@ class WordStyleMainWindow(QMainWindow): def create_menu_bar(self): """创建菜单栏""" menubar = self.menuBar() + menubar.setNativeMenuBar(False) menubar.setStyleSheet(""" QMenuBar { background-color: #f3f2f1; -- 2.34.1 From 51801354474321dcee45659de9bef48a8c48db02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Mon, 27 Oct 2025 22:35:30 +0800 Subject: [PATCH 05/11] =?UTF-8?q?feat(=E4=B8=BB=E9=A2=98):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E4=B8=BB=E9=A2=98=E7=AE=A1=E7=90=86=E5=99=A8=E5=B9=B6?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=B7=B1=E8=89=B2/=E6=B5=85=E8=89=B2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现主题管理器功能,支持自动检测系统主题并提供深色/浅色模式切换 为功能区、菜单栏、文本编辑器等组件添加主题样式支持 在视图菜单中添加模式切换选项,允许用户手动选择主题 --- src/ui/theme_manager.py | 665 ++++++++++++++++++++++++++++++++++++++++ src/ui/word_style_ui.py | 303 +++++++++++++++++- src/word_main_window.py | 324 ++++++++++++++++++-- 3 files changed, 1259 insertions(+), 33 deletions(-) create mode 100644 src/ui/theme_manager.py diff --git a/src/ui/theme_manager.py b/src/ui/theme_manager.py new file mode 100644 index 0000000..2b99e10 --- /dev/null +++ b/src/ui/theme_manager.py @@ -0,0 +1,665 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +主题管理器 - 负责检测系统主题并管理应用主题切换 +""" + +from PyQt5.QtWidgets import QApplication +from PyQt5.QtGui import QPalette, QColor +from PyQt5.QtCore import QObject, pyqtSignal +import platform +import subprocess +import os + + +class ThemeManager(QObject): + """主题管理器类""" + + # 主题切换信号 + theme_changed = pyqtSignal(bool) # True表示深色模式,False表示浅色模式 + + def __init__(self): + super().__init__() + self._is_dark_theme = False + self._auto_detect = True + self._detection_timer = None + + def is_dark_theme(self): + """检测是否为深色主题""" + if self._auto_detect: + return self._detect_system_theme() + return self._is_dark_theme + + def _detect_system_theme(self): + """检测系统主题""" + try: + # macOS系统主题检测 + if platform.system() == 'Darwin': + return self._detect_macos_theme() + # Windows系统主题检测 + elif platform.system() == 'Windows': + return self._detect_windows_theme() + # Linux系统主题检测 + else: + return self._detect_linux_theme() + except Exception as e: + print(f"主题检测失败: {e}") + return False + + def _detect_macos_theme(self): + """检测macOS系统主题""" + try: + # 使用osascript命令检测macOS主题 + result = subprocess.run([ + 'osascript', '-e', + 'tell application "System Events" to tell appearance preferences to return dark mode' + ], capture_output=True, text=True, timeout=5) + + if result.returncode == 0: + return 'true' in result.stdout.lower() + + # 备用方法:检测系统设置 + result = subprocess.run([ + 'defaults', 'read', '-g', 'AppleInterfaceStyle' + ], capture_output=True, text=True, timeout=5) + + if result.returncode == 0: + return 'dark' in result.stdout.lower() + + except (subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError): + pass + + # 使用Qt的调色板检测作为备用方法 + return self._detect_by_palette() + + def _detect_windows_theme(self): + """检测Windows系统主题""" + try: + # Windows 10/11 注册表检测 + import winreg + + key_path = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize' + value_name = 'AppsUseLightTheme' + + try: + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path) as key: + value, _ = winreg.QueryValueEx(key, value_name) + return value == 0 # 0表示深色模式 + except (OSError, FileNotFoundError): + pass + + except ImportError: + pass + + # 使用Qt的调色板检测作为备用方法 + return self._detect_by_palette() + + def _detect_linux_theme(self): + """检测Linux系统主题""" + try: + # 检测GTK主题 + result = subprocess.run([ + 'gsettings', 'get', 'org.gnome.desktop.interface', 'gtk-theme' + ], capture_output=True, text=True, timeout=5) + + if result.returncode == 0: + theme_name = result.stdout.strip().strip("'") + return any(dark_name in theme_name.lower() for dark_name in ['dark', 'night']) + + # 检测颜色方案 + result = subprocess.run([ + 'gsettings', 'get', 'org.gnome.desktop.interface', 'color-scheme' + ], capture_output=True, text=True, timeout=5) + + if result.returncode == 0: + return 'dark' in result.stdout.lower() + + except (subprocess.TimeoutExpired, subprocess.SubprocessError, FileNotFoundError): + pass + + # 使用Qt的调色板检测作为备用方法 + return self._detect_by_palette() + + def _detect_by_palette(self): + """使用Qt调色板检测主题""" + app = QApplication.instance() + if app is None: + return False + + palette = app.palette() + + # 检测背景色和文本色的亮度 + window_color = palette.color(QPalette.Window) + text_color = palette.color(QPalette.WindowText) + + # 计算亮度 + def get_luminance(color): + return (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255 + + window_luminance = get_luminance(window_color) + text_luminance = get_luminance(text_color) + + # 如果背景比文本暗,则为深色主题 + return window_luminance < text_luminance + + def get_theme_stylesheet(self, is_dark=None): + """获取主题样式表""" + if is_dark is None: + is_dark = self.is_dark_theme() + + if is_dark: + return self._get_dark_stylesheet() + else: + return self._get_light_stylesheet() + + def _get_dark_stylesheet(self): + """深色主题样式表""" + return """ + /* 深色主题样式 */ + + /* 全局文字颜色 */ + QWidget { + color: #e0e0e0; + } + + /* 主窗口 */ + QMainWindow { + background-color: #1e1e1e; + } + + /* 菜单栏 */ + QMenuBar { + background-color: #2d2d2d; + border: 1px solid #3c3c3c; + font-size: 12px; + color: #e0e0e0; + } + + QMenuBar::item { + background-color: transparent; + padding: 4px 10px; + color: #e0e0e0; + } + + QMenuBar::item:selected { + background-color: #3c3c3c; + } + + /* 菜单 */ + QMenu { + background-color: #2d2d2d; + border: 1px solid #3c3c3c; + font-size: 12px; + color: #e0e0e0; + } + + QMenu::item { + padding: 4px 20px; + color: #e0e0e0; + } + + QMenu::item:selected { + background-color: #3c3c3c; + } + + /* 功能区 */ + QFrame { + background-color: #2d2d2d; + border: 1px solid #3c3c3c; + } + + /* 组框 */ + QGroupBox { + font-size: 11px; + font-weight: normal; + color: #e0e0e0; + background-color: #2d2d2d; + border: 1px solid #3c3c3c; + border-radius: 0px; + margin-top: 5px; + padding-top: 5px; + } + + QGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 5px 0 5px; + color: #e0e0e0; + } + + /* 按钮 */ + QToolButton { + border: 1px solid #3c3c3c; + border-radius: 3px; + background-color: #3c3c3c; + font-size: 11px; + color: #e0e0e0; + padding: 3px 6px; + } + + QToolButton:hover { + background-color: #4a4a4a; + border: 1px solid #5a5a5a; + } + + QToolButton:pressed { + background-color: #2a2a2a; + border: 1px solid #1a1a1a; + } + + QToolButton:checked { + background-color: #0078d4; + border: 1px solid #106ebe; + } + + /* 切换按钮 */ + QToolButton[checkable="true"] { + border: 1px solid #3c3c3c; + border-radius: 2px; + background-color: #3c3c3c; + font-size: 12px; + font-weight: bold; + color: #e0e0e0; + } + + QToolButton[checkable="true"]:hover { + background-color: #4a4a4a; + } + + QToolButton[checkable="true"]:checked { + background-color: #0078d4; + border: 1px solid #106ebe; + } + + /* 下拉框 - 修复文字不可见问题 */ + QComboBox { + background-color: #3c3c3c; + border: 1px solid #5a5a5a; + border-radius: 2px; + color: #e0e0e0; + padding: 2px 5px; + selection-background-color: #4a4a4a; + selection-color: #e0e0e0; + } + + QComboBox:hover { + background-color: #4a4a4a; + border: 1px solid #6a6a6a; + } + + QComboBox::drop-down { + border: none; + width: 15px; + background-color: #3c3c3c; + } + + QComboBox::down-arrow { + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid #e0e0e0; + } + + /* 下拉框弹出列表 */ + QComboBox QAbstractItemView { + background-color: #3c3c3c; + border: 1px solid #5a5a5a; + color: #e0e0e0; + selection-background-color: #4a4a4a; + selection-color: #e0e0e0; + } + + /* 字体下拉框特殊处理 */ + QFontComboBox { + background-color: #3c3c3c; + border: 1px solid #5a5a5a; + border-radius: 2px; + color: #e0e0e0; + padding: 2px 5px; + selection-background-color: #4a4a4a; + selection-color: #e0e0e0; + } + + QFontComboBox:hover { + background-color: #4a4a4a; + border: 1px solid #6a6a6a; + } + + QFontComboBox QAbstractItemView { + background-color: #3c3c3c; + border: 1px solid #5a5a5a; + color: #e0e0e0; + selection-background-color: #4a4a4a; + selection-color: #e0e0e0; + } + + /* 文本编辑器 */ + QTextEdit { + background-color: #1e1e1e; + border: 1px solid #3c3c3c; + color: #e0e0e0; + padding: 20px; + line-height: 1.5; + } + + /* 状态栏 */ + QStatusBar { + background-color: #2d2d2d; + border-top: 1px solid #3c3c3c; + font-size: 11px; + color: #e0e0e0; + } + + /* 标签 */ + QLabel { + color: #e0e0e0; + background-color: transparent; + } + + /* 滚动条 */ + QScrollBar:vertical { + background-color: #2d2d2d; + width: 12px; + border: none; + } + + QScrollBar::handle:vertical { + background-color: #5a5a5a; + border-radius: 6px; + min-height: 20px; + } + + QScrollBar::handle:vertical:hover { + background-color: #6a6a6a; + } + + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + border: none; + background: none; + } + """ + + def _get_light_stylesheet(self): + """浅色主题样式表 - 白底黑字""" + return """ + /* 浅色主题样式 - 白底黑字 */ + + /* 全局文字颜色 */ + QWidget { + color: #333333; + } + + /* 主窗口 */ + QMainWindow { + background-color: #f3f2f1; + } + + /* 菜单栏 */ + QMenuBar { + background-color: #ffffff; + border: 1px solid #d0d0d0; + font-size: 12px; + color: #333333; + } + + QMenuBar::item { + background-color: transparent; + padding: 4px 10px; + color: #333333; + } + + QMenuBar::item:selected { + background-color: #f0f0f0; + } + + /* 菜单 */ + QMenu { + background-color: #ffffff; + border: 1px solid #d0d0d0; + font-size: 12px; + color: #333333; + } + + QMenu::item { + padding: 4px 20px; + color: #333333; + } + + QMenu::item:selected { + background-color: #f0f0f0; + } + + /* 功能区 */ + QFrame { + background-color: #ffffff; + border: 1px solid #d0d0d0; + } + + /* 组框 */ + QGroupBox { + font-size: 11px; + font-weight: normal; + color: #333333; + background-color: #ffffff; + border: 1px solid #d0d0d0; + border-radius: 0px; + margin-top: 5px; + padding-top: 5px; + } + + QGroupBox::title { + subcontrol-origin: margin; + left: 10px; + padding: 0 5px 0 5px; + color: #333333; + } + + /* 按钮 */ + QToolButton { + border: 1px solid #d0d0d0; + border-radius: 3px; + background-color: #ffffff; + font-size: 11px; + color: #333333; + padding: 3px 6px; + } + + QToolButton:hover { + background-color: #f0f0f0; + border: 1px solid #0078d7; + } + + QToolButton:pressed { + background-color: #e0e0e0; + border: 1px solid #005a9e; + } + + QToolButton:checked { + background-color: #0078d7; + border: 1px solid #005a9e; + color: #ffffff; + } + + /* 切换按钮 */ + QToolButton[checkable="true"] { + border: 1px solid #d0d0d0; + border-radius: 2px; + background-color: #ffffff; + font-size: 12px; + font-weight: bold; + color: #333333; + } + + QToolButton[checkable="true"]:hover { + background-color: #f0f0f0; + } + + QToolButton[checkable="true"]:checked { + background-color: #0078d7; + border: 1px solid #005a9e; + color: #ffffff; + } + + /* 下拉框 - 白底黑字 */ + QComboBox { + background-color: #ffffff; + border: 1px solid #d0d0d0; + border-radius: 2px; + color: #333333; + padding: 2px 5px; + selection-background-color: #f0f0f0; + selection-color: #333333; + } + + QComboBox:hover { + background-color: #f0f0f0; + border: 1px solid #0078d7; + } + + QComboBox::drop-down { + border: none; + width: 15px; + background-color: #ffffff; + } + + QComboBox::down-arrow { + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid #333333; + } + + /* 下拉框弹出列表 */ + QComboBox QAbstractItemView { + background-color: #ffffff; + border: 1px solid #d0d0d0; + color: #333333; + selection-background-color: #f0f0f0; + selection-color: #333333; + } + + /* 字体下拉框特殊处理 - 白底黑字 */ + QFontComboBox { + background-color: #ffffff; + border: 1px solid #d0d0d0; + border-radius: 2px; + color: #333333; + padding: 2px 5px; + selection-background-color: #f0f0f0; + selection-color: #333333; + } + + QFontComboBox:hover { + background-color: #f0f0f0; + border: 1px solid #0078d7; + } + + QFontComboBox::drop-down { + border: none; + width: 15px; + background-color: #ffffff; + } + + QFontComboBox::down-arrow { + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid #333333; + } + + QFontComboBox QAbstractItemView { + background-color: #ffffff; + border: 1px solid #d0d0d0; + color: #333333; + selection-background-color: #f0f0f0; + selection-color: #333333; + } + + /* 文本编辑器 */ + QTextEdit { + background-color: #ffffff; + border: 1px solid #d0d0d0; + color: #000000; + padding: 20px; + line-height: 1.5; + } + + /* 状态栏 */ + QStatusBar { + background-color: #ffffff; + border-top: 1px solid #d0d0d0; + font-size: 11px; + color: #333333; + } + + /* 标签 */ + QLabel { + color: #333333; + background-color: transparent; + } + + /* 滚动条 */ + QScrollBar:vertical { + background-color: #ffffff; + width: 12px; + border: none; + } + + QScrollBar::handle:vertical { + background-color: #c0c0c0; + border-radius: 6px; + min-height: 20px; + } + + QScrollBar::handle:vertical:hover { + background-color: #a0a0a0; + } + + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + border: none; + background: none; + } + """ + + def set_dark_theme(self, is_dark): + """设置深色主题""" + self._is_dark_theme = is_dark + self._auto_detect = False + self.theme_changed.emit(is_dark) + + def enable_auto_detection(self, enabled=True): + """启用/禁用自动主题检测""" + self._auto_detect = enabled + if enabled: + self.theme_changed.emit(self.is_dark_theme()) + + def get_current_theme_colors(self): + """获取当前主题颜色配置""" + is_dark = self.is_dark_theme() + + if is_dark: + return { + 'background': '#1e1e1e', + 'surface': '#2d2d2d', + 'surface_hover': '#3c3c3c', + 'text': '#e0e0e0', + 'text_secondary': '#b0b0b0', + 'border': '#3c3c3c', + 'accent': '#0078d4', + 'accent_hover': '#106ebe' + } + else: + return { + 'background': '#f3f2f1', + 'surface': '#ffffff', + 'surface_hover': '#f0f0f0', + 'text': '#333333', + 'text_secondary': '#666666', + 'border': '#d0d0d0', + 'accent': '#0078d7', + 'accent_hover': '#005a9e' + } + + +# 全局主题管理器实例 +theme_manager = ThemeManager() \ No newline at end of file diff --git a/src/ui/word_style_ui.py b/src/ui/word_style_ui.py index 065a8de..4e34b64 100644 --- a/src/ui/word_style_ui.py +++ b/src/ui/word_style_ui.py @@ -10,6 +10,9 @@ import requests import json from datetime import datetime +# 导入主题管理器 +from .theme_manager import theme_manager + class WordRibbonTab(QWidget): def __init__(self, parent=None): super().__init__(parent) @@ -33,6 +36,9 @@ class WordRibbon(QFrame): self.quote_group = None # 每日一言组件组 self.ribbon_layout = None # 功能区布局 self.setup_ui() + + # 初始化主题 + self.init_theme() def setup_ui(self): self.setFrameStyle(QFrame.NoFrame) @@ -80,7 +86,7 @@ class WordRibbon(QFrame): self.font_combo.currentFontChanged.connect(self.on_font_changed) self.font_size_combo = QComboBox() self.font_size_combo.addItems(['8', '9', '10', '11', '12', '14', '16', '18', '20', '22', '24', '26', '28', '36', '48', '72']) - self.font_size_combo.setFixedWidth(50) + self.font_size_combo.setFixedWidth(70) self.font_size_combo.setCurrentText('12') self.font_size_combo.currentTextChanged.connect(self.on_font_size_changed) @@ -114,6 +120,7 @@ class WordRibbon(QFrame): # 段落组 paragraph_group = self.create_ribbon_group("段落") + paragraph_group.setFixedWidth(320) # 增加宽度以适应更宽的按钮 # 对齐方式 align_layout = QHBoxLayout() @@ -142,13 +149,24 @@ class WordRibbon(QFrame): # 编辑组 editing_group = self.create_ribbon_group("编辑") - self.find_btn = self.create_ribbon_button("查找", "Ctrl+F", "find") - self.replace_btn = self.create_ribbon_button("替换", "Ctrl+H", "replace") - editing_layout = QVBoxLayout() + # 创建查找替换按钮,使用更适合水平排列的样式 + self.find_btn = QToolButton() + self.find_btn.setText("查找") + self.find_btn.setToolButtonStyle(Qt.ToolButtonTextOnly) + self.find_btn.setFixedSize(50, 25) # 设置适合水平排列的尺寸 + + self.replace_btn = QToolButton() + self.replace_btn.setText("替换") + self.replace_btn.setToolButtonStyle(Qt.ToolButtonTextOnly) + self.replace_btn.setFixedSize(50, 25) # 设置适合水平排列的尺寸 + + editing_layout = QHBoxLayout() # 改为水平布局 editing_layout.addWidget(self.find_btn) editing_layout.addWidget(self.replace_btn) + editing_layout.addStretch() # 添加弹性空间 editing_group.setLayout(editing_layout) + editing_group.setFixedWidth(120) # 设置编辑组宽度以适应查找替换按钮 layout.addWidget(editing_group) layout.addStretch() @@ -177,6 +195,275 @@ class WordRibbon(QFrame): """字体颜色按钮点击处理""" pass + def init_theme(self): + """初始化主题""" + # 连接主题切换信号 + theme_manager.theme_changed.connect(self.on_theme_changed) + + # 应用当前主题 + self.apply_theme() + + def apply_theme(self): + """应用主题样式""" + is_dark = theme_manager.is_dark_theme() + + # 更新功能区背景 + colors = theme_manager.get_current_theme_colors() + self.ribbon_area.setStyleSheet(f""" + QFrame {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-top: none; + }} + QGroupBox {{ + background-color: {colors['surface']}; + color: {colors['text']}; + border: 1px solid {colors['border']}; + }} + QGroupBox::title {{ + color: {colors['text']}; + background-color: transparent; + }} + QLabel {{ + color: {colors['text']}; + background-color: transparent; + }} + """) + + # 更新下拉框样式 + self.update_combo_styles(is_dark) + + def update_combo_styles(self, is_dark): + """更新下拉框样式""" + colors = theme_manager.get_current_theme_colors() + + # 字体下拉框样式 + if hasattr(self, 'font_combo'): + self.font_combo.setStyleSheet(f""" + QFontComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QFontComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QFontComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QFontComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + # 字体大小下拉框样式 + if hasattr(self, 'font_size_combo'): + self.font_size_combo.setStyleSheet(f""" + QComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + # 更新字体工具栏按钮样式 + self.update_font_button_styles(is_dark) + + def update_font_button_styles(self, is_dark): + """更新字体工具栏按钮样式""" + colors = theme_manager.get_current_theme_colors() + + # 字体样式按钮样式 (B, I, U) + font_button_style = f""" + QToolButton {{ + border: 1px solid {colors['border']}; + border-radius: 2px; + background-color: {colors['surface']}; + font-size: 12px; + font-weight: bold; + color: {colors['text']}; + }} + QToolButton:hover {{ + background-color: {colors['surface_hover']}; + }} + QToolButton:checked {{ + background-color: {colors['accent']}; + border: 1px solid {colors['accent']}; + color: {colors['surface']}; + }} + """ + + # 应用到字体样式按钮 + for btn_name in ['bold_btn', 'italic_btn', 'underline_btn']: + if hasattr(self, btn_name): + getattr(self, btn_name).setStyleSheet(font_button_style) + + # 颜色按钮样式 (A) + color_button_style = f""" + QToolButton {{ + border: 1px solid {colors['border']}; + border-radius: 2px; + background-color: {colors['surface']}; + font-size: 12px; + font-weight: bold; + color: {colors['text']}; + }} + QToolButton:hover {{ + background-color: {colors['surface_hover']}; + }} + QToolButton:pressed {{ + background-color: {colors['accent']}; + border: 1px solid {colors['accent']}; + color: {colors['surface']}; + }} + """ + + # 应用到颜色按钮 + if hasattr(self, 'color_btn'): + self.color_btn.setStyleSheet(color_button_style) + + # 段落对齐按钮样式 (左对齐、居中、右对齐、两端对齐) + paragraph_button_style = f""" + QToolButton {{ + border: 1px solid {colors['border']}; + border-radius: 2px; + background-color: {colors['surface']}; + font-size: 12px; + font-weight: bold; + color: {colors['text']}; + }} + QToolButton:hover {{ + background-color: {colors['surface_hover']}; + }} + QToolButton:checked {{ + background-color: {colors['accent']}; + border: 1px solid {colors['accent']}; + color: {colors['surface']}; + }} + """ + + # 应用到段落对齐按钮 + for btn_name in ['align_left_btn', 'align_center_btn', 'align_right_btn', 'align_justify_btn']: + if hasattr(self, btn_name): + getattr(self, btn_name).setStyleSheet(paragraph_button_style) + + # 编辑按钮样式 (查找、替换) + edit_button_style = f""" + QToolButton {{ + border: 1px solid {colors['border']}; + border-radius: 3px; + background-color: {colors['surface']}; + font-size: 11px; + color: {colors['text']}; + padding: 3px 6px; + }} + QToolButton:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + QToolButton:pressed {{ + background-color: {colors['accent']}; + border: 1px solid {colors['accent']}; + color: {colors['surface']}; + }} + """ + + # 应用到编辑按钮 + for btn_name in ['find_btn', 'replace_btn']: + if hasattr(self, btn_name): + getattr(self, btn_name).setStyleSheet(edit_button_style) + + # 城市选择下拉框样式 + if hasattr(self, 'city_combo'): + self.city_combo.setStyleSheet(f""" + QComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + # 每日一言类型下拉框样式 + if hasattr(self, 'quote_type_combo'): + self.quote_type_combo.setStyleSheet(f""" + QComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + def on_theme_changed(self, is_dark): + """主题切换槽函数""" + self.apply_theme() + def create_weather_group(self): """创建天气组件组""" if self.weather_group is not None: @@ -423,7 +710,13 @@ class WordRibbon(QFrame): btn.setText(text) btn.setCheckable(True) btn.setToolButtonStyle(Qt.ToolButtonTextOnly) - btn.setFixedSize(30, 25) + # 根据文本长度设置宽度,中文字符需要更宽 + if len(text) <= 1: + btn.setFixedSize(30, 25) # 单个字符(如B、I、U) + elif len(text) <= 2: + btn.setFixedSize(45, 25) # 两个字符(如"居中") + else: + btn.setFixedSize(60, 25) # 三个字符及以上(如"左对齐"、"两端对齐") btn.setStyleSheet(""" QToolButton { border: 1px solid #d0d0d0; diff --git a/src/word_main_window.py b/src/word_main_window.py index 3a18006..fbf8eb3 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -17,6 +17,9 @@ from ui.word_style_ui import WeatherAPI from file_parser import FileParser from input_handler.input_processor import InputProcessor +# 导入主题管理器 +from ui.theme_manager import theme_manager + class WeatherFetchThread(QThread): weather_fetched = pyqtSignal(dict) @@ -98,6 +101,9 @@ class WordStyleMainWindow(QMainWindow): self.setWindowTitle("文档1 - MagicWord") self.setGeometry(100, 100, 1200, 800) + # 初始化主题 + self.init_theme() + # 设置应用程序图标 self.set_window_icon() @@ -120,6 +126,252 @@ class WordStyleMainWindow(QMainWindow): # 初始化时刷新天气 self.refresh_weather() + def init_theme(self): + """初始化主题""" + # 连接主题切换信号 + theme_manager.theme_changed.connect(self.on_theme_changed) + + # 应用当前主题 + self.apply_theme() + + def apply_theme(self): + """应用主题样式""" + is_dark = theme_manager.is_dark_theme() + + # 应用主题样式表 + stylesheet = theme_manager.get_theme_stylesheet(is_dark) + if stylesheet.strip(): # 只在有样式内容时应用 + self.setStyleSheet(stylesheet) + + # 更新组件样式 + self.update_component_styles(is_dark) + + def update_component_styles(self, is_dark): + """更新组件样式""" + colors = theme_manager.get_current_theme_colors() + + # 更新菜单栏样式 + if hasattr(self, 'menubar'): + self.menubar.setStyleSheet(f""" + QMenuBar {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + font-size: 12px; + color: {colors['text']}; + }} + + QMenuBar::item {{ + background-color: transparent; + padding: 4px 10px; + color: {colors['text']}; + }} + + QMenuBar::item:selected {{ + background-color: {colors['surface_hover']}; + }} + + QMenuBar::item:pressed {{ + background-color: {colors['accent']}; + color: {colors['surface']}; + }} + """) + + # 更新文件菜单样式 + if hasattr(self, 'file_menu') and self.file_menu is not None: + self.file_menu.setStyleSheet(f""" + QMenu {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + font-size: 12px; + color: {colors['text']}; + }} + + QMenu::item {{ + padding: 4px 20px; + color: {colors['text']}; + background-color: transparent; + }} + + QMenu::item:selected {{ + background-color: {colors['surface_hover']}; + }} + + QMenu::item:pressed {{ + background-color: {colors['accent']}; + color: {colors['surface']}; + }} + """) + + # 更新视图菜单样式 + if hasattr(self, 'view_menu') and self.view_menu is not None: + self.view_menu.setStyleSheet(f""" + QMenu {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + font-size: 12px; + color: {colors['text']}; + }} + + QMenu::item {{ + padding: 4px 20px; + color: {colors['text']}; + background-color: transparent; + }} + + QMenu::item:selected {{ + background-color: {colors['surface_hover']}; + }} + + QMenu::item:pressed {{ + background-color: {colors['accent']}; + color: {colors['surface']}; + }} + """) + + # 更新开始菜单样式 + if hasattr(self, 'start_menu') and self.start_menu is not None: + self.start_menu.setStyleSheet(f""" + QMenu {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + font-size: 12px; + color: {colors['text']}; + }} + + QMenu::item {{ + padding: 4px 20px; + color: {colors['text']}; + background-color: transparent; + }} + + QMenu::item:selected {{ + background-color: {colors['surface_hover']}; + }} + + QMenu::item:pressed {{ + background-color: {colors['accent']}; + color: {colors['surface']}; + }} + """) + + # 更新文本编辑器样式 + if hasattr(self, 'text_edit'): + self.text_edit.setStyleSheet(f""" + QTextEdit {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 0px; + font-family: 'Calibri', 'Microsoft YaHei', '微软雅黑', sans-serif; + font-size: 12pt; + color: {colors['text']}; + padding: 40px; + line-height: 1.5; + }} + """) + + # 更新滚动区域样式 + if hasattr(self, 'scroll_area'): + self.scroll_area.setStyleSheet(f""" + QScrollArea {{ + background-color: {colors['background']}; + border: none; + }} + QScrollArea QWidget {{ + background-color: {colors['background']}; + }} + """) + + # 更新图片列表样式(如果已存在) + if hasattr(self, 'image_list_widget') and self.image_list_widget is not None: + self.image_list_widget.setStyleSheet(f""" + QListWidget {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 4px; + font-size: 11px; + color: {colors['text']}; + }} + QListWidget::item {{ + padding: 5px; + border-bottom: 1px solid {colors['border']}; + color: {colors['text']}; + }} + QListWidget::item:selected {{ + background-color: {colors['accent']}; + color: {colors['surface']}; + }} + """) + + # 更新功能区下拉框样式 + if hasattr(self, 'ribbon'): + self.update_ribbon_styles(is_dark) + + def update_ribbon_styles(self, is_dark): + """更新功能区样式""" + colors = theme_manager.get_current_theme_colors() + + # 更新字体下拉框样式 + if hasattr(self.ribbon, 'font_combo'): + self.ribbon.font_combo.setStyleSheet(f""" + QComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + # 更新字体大小下拉框样式 + if hasattr(self.ribbon, 'size_combo'): + self.ribbon.size_combo.setStyleSheet(f""" + QComboBox {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 2px; + color: {colors['text']}; + padding: 2px 5px; + }} + + QComboBox:hover {{ + background-color: {colors['surface_hover']}; + border: 1px solid {colors['accent']}; + }} + + QComboBox::drop-down {{ + border: none; + width: 15px; + }} + + QComboBox::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + def on_theme_changed(self, is_dark): + """主题切换槽函数""" + self.apply_theme() + def set_window_icon(self): """设置窗口图标""" # 使用我们创建的Word风格图标 @@ -248,30 +500,11 @@ class WordStyleMainWindow(QMainWindow): """创建菜单栏""" menubar = self.menuBar() menubar.setNativeMenuBar(False) - menubar.setStyleSheet(""" - QMenuBar { - background-color: #f3f2f1; - border-bottom: 1px solid #d0d0d0; - font-size: 12px; - color: #333333; - } - QMenuBar::item:selected { - background-color: #e1e1e1; - } - """) + self.menubar = menubar # 保存为实例变量以便后续样式更新 # 文件菜单 file_menu = menubar.addMenu('文件(F)') - file_menu.setStyleSheet(""" - QMenu { - background-color: #ffffff; - border: 1px solid #d0d0d0; - font-size: 12px; - } - QMenu::item:selected { - background-color: #e1e1e1; - } - """) + self.file_menu = file_menu # 保存为实例变量 # 新建 new_action = QAction('新建(N)', self) @@ -305,6 +538,7 @@ class WordStyleMainWindow(QMainWindow): # 开始菜单 start_menu = menubar.addMenu('开始(S)') + self.start_menu = start_menu # 保存为实例变量 # 撤销 undo_action = QAction('撤销(U)', self) @@ -340,6 +574,7 @@ class WordStyleMainWindow(QMainWindow): # 视图菜单 view_menu = menubar.addMenu('视图(V)') + self.view_menu = view_menu # 保存为实例变量 # 阅读视图 read_view_action = QAction('阅读视图', self) @@ -355,6 +590,25 @@ class WordStyleMainWindow(QMainWindow): view_menu.addSeparator() + # 模式选择子菜单 + theme_menu = view_menu.addMenu('模式') + + # 白色模式 + self.light_mode_action = QAction('白色模式', self) + self.light_mode_action.setCheckable(True) + self.light_mode_action.setChecked(not theme_manager.is_dark_theme()) # 根据当前主题设置 + self.light_mode_action.triggered.connect(self.set_light_mode) + theme_menu.addAction(self.light_mode_action) + + # 黑色模式 + self.dark_mode_action = QAction('黑色模式', self) + self.dark_mode_action.setCheckable(True) + self.dark_mode_action.setChecked(theme_manager.is_dark_theme()) # 根据当前主题设置 + self.dark_mode_action.triggered.connect(self.set_dark_mode) + theme_menu.addAction(self.dark_mode_action) + + view_menu.addSeparator() + # 视图模式选择 view_mode_menu = view_menu.addMenu('视图模式') @@ -436,11 +690,11 @@ class WordStyleMainWindow(QMainWindow): # 创建滚动区域 from PyQt5.QtWidgets import QScrollArea - scroll_area = QScrollArea() - scroll_area.setWidgetResizable(True) - scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) - scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) - scroll_area.setStyleSheet(""" + self.scroll_area = QScrollArea() # 保存为实例变量 + self.scroll_area.setWidgetResizable(True) + self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) + self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + self.scroll_area.setStyleSheet(""" QScrollArea { background-color: #e1e1e1; border: none; @@ -508,8 +762,8 @@ class WordStyleMainWindow(QMainWindow): document_layout.addWidget(self.image_list_widget) document_container.setLayout(document_layout) - scroll_area.setWidget(document_container) - main_layout.addWidget(scroll_area) + self.scroll_area.setWidget(document_container) + main_layout.addWidget(self.scroll_area) def init_network_services(self): """初始化网络服务""" @@ -2068,6 +2322,20 @@ class WordStyleMainWindow(QMainWindow): except Exception as e: self.status_bar.showMessage(f"显示图片失败: {str(e)}", 3000) + def set_light_mode(self): + """设置为白色模式""" + theme_manager.set_dark_theme(False) + self.light_mode_action.setChecked(True) + self.dark_mode_action.setChecked(False) + self.status_bar.showMessage("已切换到白色模式", 2000) + + def set_dark_mode(self): + """设置为黑色模式""" + theme_manager.set_dark_theme(True) + self.light_mode_action.setChecked(False) + self.dark_mode_action.setChecked(True) + self.status_bar.showMessage("已切换到黑色模式", 2000) + def show_image_viewer(self, filename, image_data): """显示图片查看器""" try: -- 2.34.1 From a51e8f2089056a454a587ee85796435d8bbda115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Fri, 31 Oct 2025 15:29:14 +0800 Subject: [PATCH 06/11] =?UTF-8?q?fix(=E4=B8=BB=E9=A2=98):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=B6=88=E6=81=AF=E6=A1=86=E7=9A=84=E9=BB=91=E8=89=B2?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E9=97=AE=E9=A2=98=E5=B9=B6=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/theme_manager.py | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/ui/theme_manager.py b/src/ui/theme_manager.py index 2b99e10..255307b 100644 --- a/src/ui/theme_manager.py +++ b/src/ui/theme_manager.py @@ -356,6 +356,31 @@ class ThemeManager(QObject): background-color: transparent; } + /* 消息框 - 修复黑色背景问题 */ + QMessageBox { + background-color: #2d2d2d; + color: #e0e0e0; + } + + QMessageBox QPushButton { + background-color: #3c3c3c; + color: #e0e0e0; + border: 1px solid #5a5a5a; + border-radius: 3px; + padding: 5px 15px; + min-width: 80px; + } + + QMessageBox QPushButton:hover { + background-color: #4a4a4a; + border: 1px solid #6a6a6a; + } + + QMessageBox QPushButton:pressed { + background-color: #2a2a2a; + border: 1px solid #1a1a1a; + } + /* 滚动条 */ QScrollBar:vertical { background-color: #2d2d2d; @@ -598,6 +623,31 @@ class ThemeManager(QObject): background-color: transparent; } + /* 消息框 - 修复黑色背景问题 */ + QMessageBox { + background-color: #ffffff; + color: #333333; + } + + QMessageBox QPushButton { + background-color: #ffffff; + color: #333333; + border: 1px solid #d0d0d0; + border-radius: 3px; + padding: 5px 15px; + min-width: 80px; + } + + QMessageBox QPushButton:hover { + background-color: #f0f0f0; + border: 1px solid #0078d7; + } + + QMessageBox QPushButton:pressed { + background-color: #e0e0e0; + border: 1px solid #005a9e; + } + /* 滚动条 */ QScrollBar:vertical { background-color: #ffffff; -- 2.34.1 From f2b0ed83bf2dc9b96abf5e535951e91e3ba3a3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Fri, 31 Oct 2025 16:40:17 +0800 Subject: [PATCH 07/11] =?UTF-8?q?style(=E4=B8=BB=E9=A2=98):=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=8F=9C=E5=8D=95=E6=A0=8F=E6=A0=B7=E5=BC=8F=E4=B8=BA?= =?UTF-8?q?=E5=BE=AE=E8=BD=AF=E8=93=9D=EF=BC=8C=E4=BC=98=E5=8C=96=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E9=A2=9C=E8=89=B2=E5=92=8C=E8=83=8C=E6=99=AF=20feat(?= =?UTF-8?q?=E7=BB=84=E4=BB=B6):=20=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A0=87=E9=A2=98=E6=A0=8F=E5=92=8C=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E6=9D=A1=E7=BB=84=E4=BB=B6=EF=BC=8C=E5=A2=9E=E5=BC=BAUI?= =?UTF-8?q?=E4=BA=A4=E4=BA=92=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/components.py | 492 ++++++++++++++++++++++++++++++++++++++++ src/ui/theme_manager.py | 16 +- src/word_main_window.py | 70 +++--- 3 files changed, 543 insertions(+), 35 deletions(-) create mode 100644 src/ui/components.py diff --git a/src/ui/components.py b/src/ui/components.py new file mode 100644 index 0000000..3746898 --- /dev/null +++ b/src/ui/components.py @@ -0,0 +1,492 @@ +# ui/components.py +from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QTextEdit, QProgressBar +from PyQt5.QtCore import Qt + +class CustomTitleBar(QWidget): + def __init__(self, parent=None): + """ + 自定义标题栏 + - 创建标题栏UI元素 + - 添加窗口控制按钮 + """ + super().__init__(parent) + self.parent = parent + self.setup_ui() + + def setup_ui(self): + """ + 设置标题栏UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建水平布局 + layout = QHBoxLayout() + layout.setContentsMargins(10, 5, 10, 5) + layout.setSpacing(10) + + # 创建标题标签 + self.title_label = QLabel("MagicWord") + self.title_label.setStyleSheet("color: #333333; font-size: 12px; font-weight: normal;") + + # 创建控制按钮 + self.minimize_button = QPushButton("—") + self.maximize_button = QPushButton("□") + self.close_button = QPushButton("×") + + # 设置按钮样式 + button_style = """ + QPushButton { + background-color: transparent; + border: none; + color: #333333; + font-size: 12px; + font-weight: normal; + width: 30px; + height: 30px; + } + QPushButton:hover { + background-color: #d0d0d0; + } + """ + + self.minimize_button.setStyleSheet(button_style) + self.maximize_button.setStyleSheet(button_style) + self.close_button.setStyleSheet(button_style + "QPushButton:hover { background-color: #ff5555; color: white; }") + + # 添加组件到布局 + layout.addWidget(self.title_label) + layout.addStretch() + layout.addWidget(self.minimize_button) + layout.addWidget(self.maximize_button) + layout.addWidget(self.close_button) + + self.setLayout(layout) + + # 连接按钮事件 + self.minimize_button.clicked.connect(self.minimize_window) + self.maximize_button.clicked.connect(self.maximize_window) + self.close_button.clicked.connect(self.close_window) + + # 设置标题栏样式 + self.setStyleSheet(""" + CustomTitleBar { + background-color: #f0f0f0; + border-top-left-radius: 0px; + border-top-right-radius: 0px; + border-bottom: 1px solid #d0d0d0; + } + """) + + def minimize_window(self): + """ + 最小化窗口 + - 触发窗口最小化事件 + """ + if self.parent: + self.parent.showMinimized() + + def maximize_window(self): + """ + 最大化窗口 + - 切换窗口最大化状态 + """ + if self.parent: + if self.parent.isMaximized(): + self.parent.showNormal() + self.maximize_button.setText("□") + else: + self.parent.showMaximized() + self.maximize_button.setText("❐") + + def close_window(self): + """ + 关闭窗口 + - 触发窗口关闭事件 + """ + if self.parent: + self.parent.close() + +class ProgressBarWidget(QWidget): + def __init__(self, parent=None): + """ + 进度条组件 + - 显示打字练习进度 + - 显示统计信息 + """ + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + """ + 设置进度条UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建垂直布局 + layout = QVBoxLayout() + layout.setContentsMargins(10, 10, 10, 10) + layout.setSpacing(5) + + # 创建水平布局用于统计信息 + stats_layout = QHBoxLayout() + stats_layout.setSpacing(15) + + # 创建统计信息标签 + self.wpm_label = QLabel("WPM: 0") + self.accuracy_label = QLabel("准确率: 0%") + self.time_label = QLabel("用时: 0s") + + # 设置标签样式 + label_style = "font-size: 12px; font-weight: normal; color: #333333;" + self.wpm_label.setStyleSheet(label_style) + self.accuracy_label.setStyleSheet(label_style) + self.time_label.setStyleSheet(label_style) + + # 添加标签到统计布局 + stats_layout.addWidget(self.wpm_label) + stats_layout.addWidget(self.accuracy_label) + stats_layout.addWidget(self.time_label) + stats_layout.addStretch() + + # 创建进度条 + self.progress_bar = QProgressBar() + self.progress_bar.setRange(0, 100) + self.progress_bar.setValue(0) + self.progress_bar.setTextVisible(True) + self.progress_bar.setFormat("进度: %p%") + + # 设置进度条样式 + self.progress_bar.setStyleSheet(""" + QProgressBar { + border: 1px solid #c0c0c0; + border-radius: 0px; + text-align: center; + background-color: #f0f0f0; + } + QProgressBar::chunk { + background-color: #0078d7; + border-radius: 0px; + } + """) + + # 添加组件到主布局 + layout.addLayout(stats_layout) + layout.addWidget(self.progress_bar) + + self.setLayout(layout) + + def update_progress(self, progress: float): + """ + 更新进度条 + - 设置进度值 + - 更新显示 + """ + self.progress_bar.setValue(int(progress)) + + def update_stats(self, wpm: int, accuracy: float, time_elapsed: int): + """ + 更新统计信息 + - wpm: 每分钟字数 + - accuracy: 准确率(%) + - time_elapsed: 用时(秒) + """ + self.wpm_label.setText(f"WPM: {wpm}") + self.accuracy_label.setText(f"准确率: {accuracy:.1f}%") + self.time_label.setText(f"用时: {time_elapsed}s") + +class StatsDisplayWidget(QWidget): + def __init__(self, parent=None): + """ + 统计信息显示组件 + - 显示准确率、WPM等统计信息 + """ + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + """ + 设置统计信息显示UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建水平布局 + layout = QHBoxLayout() + layout.setContentsMargins(10, 5, 10, 5) + layout.setSpacing(15) + + # 创建统计信息标签 + self.wpm_label = QLabel("WPM: 0") + self.accuracy_label = QLabel("准确率: 0%") + + # 设置标签样式 + label_style = "font-size: 12px; font-weight: normal; color: #333333;" + self.wpm_label.setStyleSheet(label_style) + self.accuracy_label.setStyleSheet(label_style) + + # 添加组件到布局 + layout.addWidget(self.wpm_label) + layout.addWidget(self.accuracy_label) + layout.addStretch() + + self.setLayout(layout) + + # 设置样式 + self.setStyleSheet(""" + StatsDisplayWidget { + background-color: #f0f0f0; + border-bottom: 1px solid #d0d0d0; + } + """) + + def update_stats(self, wpm: int, accuracy: float): + """ + 更新统计信息 + - wpm: 每分钟字数 + - accuracy: 准确率(%) + """ + self.wpm_label.setText(f"WPM: {wpm}") + self.accuracy_label.setText(f"准确率: {accuracy:.1f}%") + +class QuoteDisplayWidget(QWidget): + def __init__(self, parent=None): + """ + 每日一言显示组件 + - 显示每日一言功能 + """ + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + """ + 设置每日一言显示UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建水平布局 + layout = QHBoxLayout() + layout.setContentsMargins(10, 5, 10, 5) + layout.setSpacing(15) + + # 创建每日一言标签 + self.quote_label = QLabel("每日一言: 暂无") + self.quote_label.setStyleSheet("QLabel { color: #666666; font-style: italic; }") + + # 设置标签样式 + label_style = "font-size: 12px; font-weight: normal; color: #333333;" + self.quote_label.setStyleSheet(label_style) + + # 创建每日一言刷新按钮 + self.refresh_quote_button = QPushButton("刷新") + self.refresh_quote_button.setStyleSheet(""" + QPushButton { + background-color: #0078d7; + color: white; + border: none; + padding: 5px 10px; + border-radius: 3px; + font-size: 12px; + } + QPushButton:hover { + background-color: #005a9e; + } + """) + + # 添加组件到布局 + layout.addWidget(self.quote_label) + layout.addStretch() + layout.addWidget(self.refresh_quote_button) + + self.setLayout(layout) + + # 设置样式 + self.setStyleSheet(""" + QuoteDisplayWidget { + background-color: #f0f0f0; + border-bottom: 1px solid #d0d0d0; + } + """) + + def update_quote(self, quote: str): + """ + 更新每日一言 + - quote: 每日一言内容 + """ + self.quote_label.setText(f"每日一言: {quote}") + +class WeatherDisplayWidget(QWidget): + def __init__(self, parent=None): + """ + 天气显示组件 + - 显示天气信息 + """ + super().__init__(parent) + self.setup_ui() + + def setup_ui(self): + """ + 设置天气显示UI + - 初始化所有UI组件 + - 设置组件属性和样式 + """ + # 创建水平布局 + layout = QHBoxLayout() + layout.setContentsMargins(10, 5, 10, 5) + layout.setSpacing(15) + + # 创建天气信息标签 + self.weather_label = QLabel("天气: 暂无") + + # 设置标签样式 + label_style = "font-size: 12px; font-weight: normal; color: #333333;" + self.weather_label.setStyleSheet(label_style) + + # 创建天气刷新按钮 + self.refresh_weather_button = QPushButton("刷新") + self.refresh_weather_button.setStyleSheet(""" + QPushButton { + background-color: #0078d7; + color: white; + border: none; + padding: 5px 10px; + border-radius: 3px; + font-size: 12px; + } + QPushButton:hover { + background-color: #005a9e; + } + """) + + # 添加组件到布局 + layout.addWidget(self.weather_label) + layout.addStretch() + layout.addWidget(self.refresh_weather_button) + + self.setLayout(layout) + + # 设置样式 + self.setStyleSheet(""" + WeatherDisplayWidget { + background-color: #f0f0f0; + border-bottom: 1px solid #d0d0d0; + } + """) + + def update_weather(self, weather_info: dict): + """ + 更新天气信息 + - weather_info: 天气信息字典 + """ + if weather_info: + city = weather_info.get("city", "未知") + temperature = weather_info.get("temperature", "N/A") + description = weather_info.get("description", "N/A") + self.weather_label.setText(f"天气: {city} {temperature}°C {description}") + else: + self.weather_label.setText("天气: 获取失败") + +class TextDisplayWidget(QWidget): + def __init__(self, parent=None): + """ + 文本显示组件 + - 显示待练习文本 + - 高亮当前字符 + - 显示用户输入反馈 + """ + super().__init__(parent) + self.text_content = "" + self.current_index = 0 + self.setup_ui() + + def setup_ui(self): + """ + 设置文本显示UI + - 初始化文本显示区域 + - 设置样式和布局 + """ + # 创建垂直布局 + layout = QVBoxLayout() + layout.setContentsMargins(20, 20, 20, 20) + + # 创建文本显示区域 + self.text_display = QTextEdit() + self.text_display.setReadOnly(False) # 设置为可编辑 + self.text_display.setLineWrapMode(QTextEdit.WidgetWidth) + + # 设置文本显示样式 + self.text_display.setStyleSheet(""" + QTextEdit { + font-family: 'Calibri', 'Segoe UI', 'Microsoft YaHei', sans-serif; + font-size: 12pt; + border: 1px solid #d0d0d0; + border-radius: 0px; + padding: 15px; + background-color: white; + color: black; + } + """) + + # 添加组件到布局 + layout.addWidget(self.text_display) + self.setLayout(layout) + + def set_text(self, text: str): + """ + 设置显示文本 + - text: 要显示的文本内容 + """ + self.text_content = text + self.current_index = 0 + # 初始不显示内容,通过打字逐步显示 + self.text_display.setHtml("") + + def highlight_character(self, position: int): + """ + 高亮指定位置的字符 + - position: 字符位置索引 + """ + if 0 <= position < len(self.text_content): + self.current_index = position + # 不再直接高亮字符,而是通过用户输入来显示内容 + pass + + def _update_display(self, user_input: str = ""): + """ + 更新文本显示 + - user_input: 用户输入文本(可选) + """ + # 导入需要的模块 + from PyQt5.QtGui import QTextCursor + + if not self.text_content: + self.text_display.clear() + return + + # 简单显示文本,不使用任何高亮 + if user_input: + # 只显示用户已输入的部分文本 + displayed_text = self.text_content[:len(user_input)] + else: + # 没有用户输入,不显示任何内容 + displayed_text = "" + + # 更新文本显示 + self.text_display.setPlainText(displayed_text) + + # 安全地滚动到光标位置 + if user_input and displayed_text: + try: + cursor = self.text_display.textCursor() + # 将光标定位到文本末尾 + cursor.setPosition(len(displayed_text)) + self.text_display.setTextCursor(cursor) + self.text_display.ensureCursorVisible() + except Exception: + # 如果光标定位失败,忽略错误 + pass + + def show_user_input(self, input_text: str): + """ + 显示用户输入的文本 + - input_text: 用户输入的文本 + """ + self._update_display(input_text) \ No newline at end of file diff --git a/src/ui/theme_manager.py b/src/ui/theme_manager.py index 255307b..6b42bb1 100644 --- a/src/ui/theme_manager.py +++ b/src/ui/theme_manager.py @@ -169,10 +169,10 @@ class ThemeManager(QObject): /* 菜单栏 */ QMenuBar { - background-color: #2d2d2d; - border: 1px solid #3c3c3c; + background-color: #0078d7; + border: 1px solid #005a9e; font-size: 12px; - color: #e0e0e0; + color: #ffffff; } QMenuBar::item { @@ -182,7 +182,7 @@ class ThemeManager(QObject): } QMenuBar::item:selected { - background-color: #3c3c3c; + background-color: #106ebe; } /* 菜单 */ @@ -421,10 +421,10 @@ class ThemeManager(QObject): /* 菜单栏 */ QMenuBar { - background-color: #ffffff; - border: 1px solid #d0d0d0; + background-color: #0078d7; + border: 1px solid #005a9e; font-size: 12px; - color: #333333; + color: #ffffff; } QMenuBar::item { @@ -434,7 +434,7 @@ class ThemeManager(QObject): } QMenuBar::item:selected { - background-color: #f0f0f0; + background-color: #106ebe; } /* 菜单 */ diff --git a/src/word_main_window.py b/src/word_main_window.py index fbf8eb3..38112ac 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -131,6 +131,10 @@ class WordStyleMainWindow(QMainWindow): # 连接主题切换信号 theme_manager.theme_changed.connect(self.on_theme_changed) + # 设置默认为白色模式(禁用自动检测) + theme_manager.enable_auto_detection(False) + theme_manager.set_dark_theme(False) + # 应用当前主题 self.apply_theme() @@ -150,30 +154,35 @@ class WordStyleMainWindow(QMainWindow): """更新组件样式""" colors = theme_manager.get_current_theme_colors() - # 更新菜单栏样式 + # 更新菜单栏样式 - 使用微软蓝 if hasattr(self, 'menubar'): - self.menubar.setStyleSheet(f""" - QMenuBar {{ - background-color: {colors['surface']}; - border: 1px solid {colors['border']}; + self.menubar.setStyleSheet(""" + QMenuBar { + background-color: #0078d7; + border: 1px solid #005a9e; font-size: 12px; - color: {colors['text']}; - }} + color: #ffffff; + } - QMenuBar::item {{ + QMenuBar::item { background-color: transparent; padding: 4px 10px; - color: {colors['text']}; - }} + color: #ffffff; + } - QMenuBar::item:selected {{ - background-color: {colors['surface_hover']}; - }} + QMenuBar::item:selected { + background-color: #106ebe; + } - QMenuBar::item:pressed {{ - background-color: {colors['accent']}; - color: {colors['surface']}; - }} + QMenuBar::item:pressed { + background-color: #005a9e; + color: #ffffff; + } + + #startMenu { + background-color: white; + color: #000000; + } """) # 更新文件菜单样式 @@ -538,6 +547,7 @@ class WordStyleMainWindow(QMainWindow): # 开始菜单 start_menu = menubar.addMenu('开始(S)') + start_menu.setObjectName("startMenu") self.start_menu = start_menu # 保存为实例变量 # 撤销 @@ -657,24 +667,30 @@ class WordStyleMainWindow(QMainWindow): show_weather_action = QAction('显示详细天气', self) show_weather_action.triggered.connect(self.show_detailed_weather) weather_menu.addAction(show_weather_action) - #插入 + # 插入菜单 insert_menu = menubar.addMenu('插入(I)') - #绘图 + + # 绘图菜单 paint_menu = menubar.addMenu('绘图(D)') - #设计 + + # 设计菜单 design_menu = menubar.addMenu('设计(G)') - #布局 + + # 布局菜单 layout_menu = menubar.addMenu('布局(L)') - #引用 + + # 引用菜单 reference_menu = menubar.addMenu('引用(R)') - #邮件 + + # 邮件菜单 mail_menu = menubar.addMenu('邮件(M)') - #审阅 + + # 审阅菜单 review_menu = menubar.addMenu('审阅(W)') - #视图 - view_menu = menubar.addMenu('视图(V)') - #开发工具 + + # 开发工具菜单 developer_menu = menubar.addMenu('开发工具(Q)') + # 帮助菜单 help_menu = menubar.addMenu('帮助(H)') -- 2.34.1 From 9b06f616fcf57180651fc11f6184f55acd0ed924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Fri, 31 Oct 2025 18:28:22 +0800 Subject: [PATCH 08/11] =?UTF-8?q?fix=EF=BC=9A=E6=96=B0=E5=A2=9E=E5=AD=A6?= =?UTF-8?q?=E4=B9=A0=E6=A8=A1=E5=BC=8F=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/learning_mode_window.py | 434 ++++++++++++++++++++++++++++++++++++ src/ui/UI.png | Bin 0 -> 41047 bytes src/ui/word_style_ui.py | 67 +++++- src/word_main_window.py | 282 +++++++++++------------ 4 files changed, 640 insertions(+), 143 deletions(-) create mode 100644 src/learning_mode_window.py create mode 100644 src/ui/UI.png diff --git a/src/learning_mode_window.py b/src/learning_mode_window.py new file mode 100644 index 0000000..1ec350b --- /dev/null +++ b/src/learning_mode_window.py @@ -0,0 +1,434 @@ +# learning_mode_window.py +import sys +import os +from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, + QTextEdit, QLabel, QFrame, QMenuBar, + QAction, QFileDialog, QMessageBox, QApplication, + QSplitter, QScrollArea, QStatusBar, QProgressBar) +from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QRect +from PyQt5.QtGui import QFont, QPalette, QColor, QIcon, QPixmap, QTextCharFormat, QTextCursor + +from src.ui.components import CustomTitleBar, TextDisplayWidget +from src.typing_logic import TypingLogic +from src.file_parser import FileParser +from src.ui.theme_manager import theme_manager + +class LearningModeWindow(QMainWindow): + def __init__(self, parent=None, imported_content="", current_position=0): + """ + 学习模式窗口 + - 顶部显示UI.png图片 + - 下方显示输入字符页面 + - 输入字符显示导入的文件内容 + + 参数: + parent: 父窗口 + imported_content: 从主窗口传递的导入内容 + current_position: 当前学习进度位置 + """ + super().__init__(parent) + self.parent_window = parent + self.imported_content = imported_content + self.current_position = current_position + self.typing_logic = None + self.is_loading_file = False + + # 初始化UI + self.initUI() + + # 初始化打字逻辑 + self.init_typing_logic() + + # 如果有导入内容,初始化显示 + if self.imported_content: + self.initialize_with_imported_content() + + def initialize_with_imported_content(self): + """ + 使用从主窗口传递的导入内容初始化学习模式窗口 + """ + if not self.imported_content: + return + + # 重置打字逻辑 + if self.typing_logic: + self.typing_logic.reset(self.imported_content) + + # 显示已学习的内容 + display_text = self.imported_content[:self.current_position] + self.text_display_widget.text_display.setPlainText(display_text) + + # 更新状态 + progress = (self.current_position / len(self.imported_content)) * 100 + self.status_label.setText(f"继续学习 - 进度: {self.current_position}/{len(self.imported_content)} 字符") + self.progress_label.setText(f"进度: {progress:.1f}%") + + # 设置光标位置到文本末尾 + cursor = self.text_display_widget.text_display.textCursor() + cursor.movePosition(cursor.End) + self.text_display_widget.text_display.setTextCursor(cursor) + + def initUI(self): + """ + 初始化学习模式窗口UI + - 设置窗口标题和大小 + - 创建顶部图片区域 + - 创建下方输入区域 + """ + # 设置窗口属性 + self.setWindowTitle("学习模式 - MagicWord") + self.setGeometry(200, 200, 900, 700) + self.setWindowFlags(Qt.Window) # 独立窗口 + + # 创建中央widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # 创建主布局 + main_layout = QVBoxLayout() + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + central_widget.setLayout(main_layout) + + # 创建顶部图片区域 + self.create_top_image_area(main_layout) + + # 创建分隔线 + separator = QFrame() + separator.setFrameShape(QFrame.HLine) + separator.setFrameShadow(QFrame.Sunken) + separator.setStyleSheet("background-color: #d0d0d0;") + main_layout.addWidget(separator) + + # 创建输入区域 + self.create_input_area(main_layout) + + # 创建菜单栏 + self.create_menu_bar() + + # 创建状态栏 + self.create_status_bar() + + # 如果有导入内容,更新状态栏显示 + if self.imported_content: + progress = (self.current_position / len(self.imported_content)) * 100 + self.status_label.setText(f"继续学习 - 进度: {self.current_position}/{len(self.imported_content)} 字符") + self.progress_label.setText(f"进度: {progress:.1f}%") + + def create_top_image_area(self, main_layout): + """ + 创建顶部图片区域 + - 加载并显示UI.png图片,完全铺满窗口上方 + - 窗口大小自动适配图片大小 + """ + # 创建图片标签 + self.image_label = QLabel() + self.image_label.setAlignment(Qt.AlignCenter) + self.image_label.setStyleSheet(""" + QLabel { + background-color: #f8f9fa; + border: none; + margin: 0px; + padding: 0px; + } + """) + + # 加载UI.png图片 + ui_image_path = os.path.join(os.path.dirname(__file__), 'ui', 'UI.png') + if os.path.exists(ui_image_path): + pixmap = QPixmap(ui_image_path) + + # 保存原始图片尺寸 + self.original_pixmap = pixmap + + # 设置图片完全铺满标签 + self.image_label.setPixmap(pixmap) + self.image_label.setScaledContents(True) # 关键:让图片缩放填充整个标签 + + # 设置图片标签的尺寸策略,使其可以扩展 + from PyQt5.QtWidgets import QSizePolicy + self.image_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + + # 设置图片区域的最小高度为图片高度的1/3,确保图片可见 + min_height = max(200, pixmap.height() // 3) + self.image_label.setMinimumHeight(min_height) + + # 重新设置窗口大小以适配图片 + self.resize(pixmap.width(), self.height()) + else: + self.image_label.setText("UI图片未找到") + self.image_label.setStyleSheet(""" + QLabel { + background-color: #f8f9fa; + border: none; + color: #666666; + font-size: 14px; + padding: 20px; + } + """) + self.image_label.setMinimumHeight(200) + + # 直接添加图片标签到主布局,不使用滚动区域 + main_layout.addWidget(self.image_label) + + def resizeEvent(self, event): + """ + 窗口大小改变事件 + - 动态调整图片显示区域 + """ + super().resizeEvent(event) + + # 获取窗口宽度 + window_width = self.width() + + # 如果图片标签存在,调整其大小以适配窗口 + if hasattr(self, 'image_label') and self.image_label: + # 设置图片标签的固定宽度为窗口宽度 + self.image_label.setFixedWidth(window_width) + + # 根据窗口宽度计算合适的高度(保持图片比例) + if hasattr(self, 'original_pixmap') and self.original_pixmap: + original_width = self.original_pixmap.width() + original_height = self.original_pixmap.height() + + # 计算保持比例的高度 + new_height = int(window_width * original_height / original_width) + self.image_label.setFixedHeight(new_height) + else: + # 如果没有原始图片,使用默认高度 + self.image_label.setFixedHeight(300) + + def create_input_area(self, main_layout): + """ + 创建输入区域 + - 创建文本显示组件 + - 设置与主系统相同的样式 + """ + # 创建文本显示组件(复用主系统的组件) + self.text_display_widget = TextDisplayWidget(self) + + # 设置样式,使其与主系统保持一致 + self.text_display_widget.setStyleSheet(""" + TextDisplayWidget { + background-color: white; + border: 1px solid #d0d0d0; + border-radius: 0px; + } + """) + + # 连接文本变化信号 + self.text_display_widget.text_display.textChanged.connect(self.on_text_changed) + + main_layout.addWidget(self.text_display_widget, 1) # 占据剩余空间 + + def create_menu_bar(self): + """ + 创建菜单栏 + - 文件菜单:导入、退出 + - 帮助菜单:关于 + """ + menu_bar = self.menuBar() + + # 文件菜单 + file_menu = menu_bar.addMenu('文件') + + # 导入动作 + import_action = QAction('导入文件', self) + import_action.setShortcut('Ctrl+O') + import_action.triggered.connect(self.import_file) + file_menu.addAction(import_action) + + file_menu.addSeparator() + + # 退出动作 + exit_action = QAction('退出学习模式', self) + exit_action.setShortcut('Ctrl+Q') + exit_action.triggered.connect(self.close) + file_menu.addAction(exit_action) + + # 帮助菜单 + help_menu = menu_bar.addMenu('帮助') + + about_action = QAction('关于', self) + about_action.triggered.connect(self.show_about) + help_menu.addAction(about_action) + + def create_status_bar(self): + """ + 创建状态栏 + - 显示当前状态和学习进度 + """ + self.status_bar = self.statusBar() + + # 创建状态标签 + self.status_label = QLabel("就绪 - 请先导入文件开始学习") + self.progress_label = QLabel("进度: 0%") + + # 添加到状态栏 + self.status_bar.addWidget(self.status_label) + self.status_bar.addPermanentWidget(self.progress_label) + + def init_typing_logic(self): + """ + 初始化打字逻辑 + - 创建打字逻辑实例 + - 设置默认内容 + """ + # 创建打字逻辑实例 + self.typing_logic = TypingLogic("欢迎使用学习模式!\n\n请先导入文件开始打字学习。") + + # 设置文本显示组件的打字逻辑 + if hasattr(self.text_display_widget, 'set_typing_logic'): + self.text_display_widget.set_typing_logic(self.typing_logic) + + def import_file(self): + """ + 导入文件 + - 打开文件对话框选择文件 + - 解析文件内容 + - 重置打字逻辑 + """ + file_path, _ = QFileDialog.getOpenFileName( + self, "导入学习文件", "", + "文档文件 (*.docx *.txt *.pdf);;所有文件 (*.*)" + ) + + if file_path: + try: + self.is_loading_file = True + + # 使用文件解析器 + parser = FileParser() + content = parser.parse_file(file_path) + + if content: + # 存储导入的内容 + self.imported_content = content + self.current_position = 0 + + # 重置打字逻辑 + if self.typing_logic: + self.typing_logic.reset(content) + + # 清空文本显示 + self.text_display_widget.text_display.clear() + + # 更新状态 + self.status_label.setText(f"已导入: {os.path.basename(file_path)}") + self.progress_label.setText(f"进度: 0% (0/{len(content)} 字符)") + + # 显示成功消息 + QMessageBox.information(self, "导入成功", + f"文件导入成功!\n文件: {os.path.basename(file_path)}\n字符数: {len(content)}\n\n开始打字以显示学习内容。") + + else: + QMessageBox.warning(self, "导入失败", "无法解析文件内容,请检查文件格式。") + + except Exception as e: + QMessageBox.critical(self, "导入错误", f"导入文件时出错:\n{str(e)}") + + finally: + self.is_loading_file = False + + def on_text_changed(self): + """ + 文本变化处理 + - 根据导入的内容逐步显示 + - 更新学习进度 + """ + # 如果正在加载文件,跳过处理 + if self.is_loading_file: + return + + # 如果没有导入内容,清空文本 + if not self.imported_content: + current_text = self.text_display_widget.text_display.toPlainText() + if current_text: + self.text_display_widget.text_display.clear() + self.status_label.setText("请先导入文件开始学习") + return + + # 获取当前文本 + current_text = self.text_display_widget.text_display.toPlainText() + + # 始终确保显示的是导入的文件内容,而不是用户输入的文字 + expected_text = self.imported_content[:len(current_text)] + + # 如果当前文本与期望文本不一致,强制恢复到期望文本 + if current_text != expected_text: + cursor = self.text_display_widget.text_display.textCursor() + self.text_display_widget.text_display.setPlainText(expected_text) + self.text_display_widget.text_display.setTextCursor(cursor) + + # 显示错误信息 + if len(current_text) > 0: + expected_char = self.imported_content[len(current_text)-1] if len(current_text) <= len(self.imported_content) else '' + self.status_label.setText(f"输入错误!期望字符: '{expected_char}'") + return + + # 检查输入是否正确 + if self.typing_logic and len(current_text) > 0: + result = self.typing_logic.check_input(current_text) + + if not result['correct']: + # 输入错误,恢复到正确的状态 + expected_text = self.imported_content[:len(current_text)] + if current_text != expected_text: + cursor = self.text_display_widget.text_display.textCursor() + self.text_display_widget.text_display.setPlainText(expected_text) + self.text_display_widget.text_display.setTextCursor(cursor) + + # 显示错误信息 + self.status_label.setText(f"输入错误!期望字符: '{result.get('expected', '')}'") + else: + # 输入正确,更新进度 + self.current_position = len(current_text) + progress = (self.current_position / len(self.imported_content)) * 100 + + self.progress_label.setText( + f"进度: {progress:.1f}% ({self.current_position}/{len(self.imported_content)} 字符)" + ) + + # 检查是否完成 + if result.get('completed', False): + self.status_label.setText("恭喜!学习完成!") + QMessageBox.information(self, "学习完成", "恭喜您完成了所有学习内容!") + else: + self.status_label.setText("继续输入以显示更多内容...") + + def show_about(self): + """ + 显示关于对话框 + """ + QMessageBox.about(self, "关于学习模式", + "MagicWord 学习模式\n\n" + "功能特点:\n" + "• 顶部显示UI界面图片\n" + "• 下方为打字输入区域\n" + "• 导入文件后逐步显示内容\n" + "• 实时显示学习进度\n\n" + "使用方法:\n" + "1. 点击'文件'->'导入文件'选择学习材料\n" + "2. 在下方文本区域开始打字\n" + "3. 系统会根据您的输入逐步显示内容") + + def closeEvent(self, event): + """ + 窗口关闭事件 + - 通知父窗口学习模式已关闭 + """ + if self.parent_window and hasattr(self.parent_window, 'on_learning_mode_closed'): + self.parent_window.on_learning_mode_closed() + + event.accept() + + def keyPressEvent(self, event): + """ + 按键事件处理 + - 处理特殊按键 + """ + # 处理Escape键关闭窗口 + if event.key() == Qt.Key_Escape: + self.close() + else: + super().keyPressEvent(event) \ No newline at end of file diff --git a/src/ui/UI.png b/src/ui/UI.png new file mode 100644 index 0000000000000000000000000000000000000000..de2ba66d7538388ed41bce36141401fa3a898a57 GIT binary patch literal 41047 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 0: - # 显示学习模式下已输入的内容 - display_text = self.imported_content[:self.learning_progress] - self.text_edit.setPlainText(display_text) - else: - # 如果没有学习进度,显示默认提示 - self.text_edit.setPlainText("请先在学习模式下输入内容") + if mode == "learning": + # 学习模式:打开新的学习模式窗口 + try: + from learning_mode_window import LearningModeWindow - # 设置光标位置到文档末尾 - cursor = self.text_edit.textCursor() - cursor.movePosition(cursor.End) - self.text_edit.setTextCursor(cursor) + # 准备传递给学习窗口的参数 + imported_content = "" + current_position = 0 - # 重置打字逻辑,准备接受新的输入 - if self.typing_logic: + # 如果有已导入的内容,传递给学习窗口 + if hasattr(self, 'imported_content') and self.imported_content: + imported_content = self.imported_content if hasattr(self, 'learning_progress') and self.learning_progress > 0: - # 使用已输入的内容作为打字逻辑的基础 - self.typing_logic.reset(self.imported_content) - # 设置当前位置到已输入的末尾 - self.typing_logic.current_index = self.learning_progress - self.typing_logic.typed_chars = self.learning_progress - else: - self.typing_logic.reset("") + current_position = self.learning_progress - # 重置显示字符计数 - self.displayed_chars = 0 + # 创建学习模式窗口,直接传递导入内容 + self.learning_window = LearningModeWindow(self, imported_content, current_position) - # 重置图片插入记录 - if hasattr(self, 'inserted_images'): - self.inserted_images.clear() + # 显示学习模式窗口 + self.learning_window.show() - elif mode == "learning": - # 学习模式:从上次中断的地方继续显示学习文档C的内容 - if not self.imported_content: - self.status_bar.showMessage("学习模式需要导入文件 - 请先打开一个文件", 3000) - # 清空文本编辑器,等待导入文件 - self.text_edit.clear() - if self.typing_logic: - self.typing_logic.reset("在此输入您的内容...") - # 重置显示字符计数 - self.displayed_chars = 0 - # 重置图片插入记录 - if hasattr(self, 'inserted_images'): - self.inserted_images.clear() - else: - # 检查是否有保存的学习进度 - if hasattr(self, 'learning_progress') and self.learning_progress > 0: - self.status_bar.showMessage(f"切换到学习模式 - 从上次中断处继续 ({self.learning_progress}/{len(self.imported_content)})", 3000) - # 恢复学习进度 - self.displayed_chars = self.learning_progress - - # 重置打字逻辑,准备接受导入内容 - if self.typing_logic: - self.typing_logic.reset(self.imported_content) - - # 获取应该显示的学习文档C的内容部分 - display_text = self.imported_content[:self.displayed_chars] - - # 设置文本内容 - self.text_edit.clear() - self.text_edit.setPlainText(display_text) - - # 设置光标位置到文本末尾 - cursor = self.text_edit.textCursor() - cursor.movePosition(cursor.End) - self.text_edit.setTextCursor(cursor) - - # 重新插入图片 - if hasattr(self, 'inserted_images'): - self.inserted_images.clear() - self.insert_images_in_text() - else: - self.status_bar.showMessage("切换到学习模式 - 准备显示学习文档C内容", 3000) - # 重置打字逻辑,准备接受导入内容 - if self.typing_logic: - self.typing_logic.reset(self.imported_content) - - # 重置显示字符计数 - self.displayed_chars = 0 - - # 清空文本编辑器,等待用户开始打字 - self.text_edit.clear() - - # 重置图片插入记录 - if hasattr(self, 'inserted_images'): - self.inserted_images.clear() - finally: - # 重新连接文本变化信号 - self.text_edit.textChanged.connect(self.on_text_changed) + # 更新菜单状态 + self.learning_mode_action.setChecked(True) + self.typing_mode_action.setChecked(False) + + # 切换到打字模式(主窗口保持打字模式) + self.view_mode = "typing" + + self.status_bar.showMessage("学习模式窗口已打开", 3000) + + except ImportError as e: + QMessageBox.critical(self, "错误", f"无法加载学习模式窗口:\n{str(e)}") + except Exception as e: + QMessageBox.critical(self, "错误", f"打开学习模式窗口时出错:\n{str(e)}") + + elif mode == "typing": + # 打字模式:保持当前窗口状态 + self.view_mode = "typing" + self.typing_mode_action.setChecked(True) + self.learning_mode_action.setChecked(False) + self.status_bar.showMessage("当前为打字模式", 2000) + + def on_learning_mode_closed(self): + """学习模式窗口关闭时的回调""" + # 重置菜单状态 + self.learning_mode_action.setChecked(False) + self.typing_mode_action.setChecked(True) + self.view_mode = "typing" + self.status_bar.showMessage("学习模式窗口已关闭", 2000) def set_page_color(self, color): """设置页面颜色""" @@ -2353,49 +2280,122 @@ class WordStyleMainWindow(QMainWindow): self.status_bar.showMessage("已切换到黑色模式", 2000) def show_image_viewer(self, filename, image_data): - """显示图片查看器""" + """显示图片查看器 - 图片真正铺满整个窗口上方""" try: - # 创建图片查看窗口 + # 创建自定义图片查看窗口 viewer = QDialog(self) viewer.setWindowTitle(f"图片查看 - {filename}") viewer.setModal(False) - viewer.resize(800, 600) - # 创建布局 - layout = QVBoxLayout() + # 移除窗口边框和标题栏装饰,设置为工具窗口样式 + viewer.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) + + # 设置窗口背景为黑色,完全无边距 + viewer.setStyleSheet(""" + QDialog { + background-color: #000000; + border: none; + margin: 0px; + padding: 0px; + } + """) - # 创建滚动区域 - scroll_area = QScrollArea() - scroll_area.setWidgetResizable(True) + # 创建布局,完全移除边距 + layout = QVBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) # 移除布局边距 + layout.setSpacing(0) # 移除组件间距 + layout.setAlignment(Qt.AlignCenter) # 布局居中对齐 - # 创建图片标签 + # 创建图片标签,设置为完全填充模式 image_label = QLabel() image_label.setAlignment(Qt.AlignCenter) + image_label.setScaledContents(True) # 关键:允许图片缩放以填充标签 + image_label.setMinimumSize(1, 1) # 设置最小尺寸 + image_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # 设置大小策略为扩展 + image_label.setStyleSheet(""" + QLabel { + border: none; + margin: 0px; + padding: 0px; + background-color: #000000; + } + """) # 加载图片 pixmap = QPixmap() - if pixmap.loadFromData(image_data): - image_label.setPixmap(pixmap) - image_label.setScaledContents(False) - - # 设置标签大小为图片实际大小 - image_label.setFixedSize(pixmap.size()) - else: - image_label.setText("无法加载图片") + if not pixmap.loadFromData(image_data): + self.status_bar.showMessage(f"加载图片失败: {filename}", 3000) + return - scroll_area.setWidget(image_label) - layout.addWidget(scroll_area) + layout.addWidget(image_label) + viewer.setLayout(layout) - # 添加关闭按钮 - close_btn = QPushButton("关闭") - close_btn.clicked.connect(viewer.close) - layout.addWidget(close_btn) + # 计算位置和大小 + if self: + parent_geometry = self.geometry() + screen_geometry = QApplication.primaryScreen().geometry() + + # 设置窗口宽度与主窗口相同,高度为屏幕高度的40% + window_width = parent_geometry.width() + window_height = int(screen_geometry.height() * 0.4) + + # 计算位置:显示在主窗口正上方 + x = parent_geometry.x() + y = parent_geometry.y() - window_height + + # 确保不会超出屏幕边界 + if y < screen_geometry.top(): + y = parent_geometry.y() + 50 # 如果上方空间不足,显示在下方 + + # 调整宽度确保不超出屏幕 + if x + window_width > screen_geometry.right(): + window_width = screen_geometry.right() - x + + viewer.setGeometry(x, y, window_width, window_height) - viewer.setLayout(layout) viewer.show() + # 关键:强制图片立即填充整个标签区域 + def force_image_fill(): + try: + if pixmap and not pixmap.isNull(): + # 获取标签的实际大小 + label_size = image_label.size() + if label_size.width() > 10 and label_size.height() > 10: # 确保尺寸有效 + # 完全填充,忽略宽高比,真正铺满 + scaled_pixmap = pixmap.scaled( + label_size, + Qt.IgnoreAspectRatio, # 关键:忽略宽高比,强制填充 + Qt.SmoothTransformation + ) + image_label.setPixmap(scaled_pixmap) + print(f"图片已强制缩放至 {label_size.width()}x{label_size.height()}") + + # 确保标签完全填充布局 + image_label.setMinimumSize(label_size) + except Exception as e: + print(f"图片缩放失败: {e}") + + # 使用多个定时器确保图片正确填充 + from PyQt5.QtCore import QTimer + QTimer.singleShot(50, force_image_fill) # 50毫秒后执行 + QTimer.singleShot(200, force_image_fill) # 200毫秒后执行 + QTimer.singleShot(1000, force_image_fill) # 1000毫秒后再执行一次 + + # 连接窗口大小变化事件 + viewer.resizeEvent = lambda event: force_image_fill() + + # 添加点击关闭功能 + def close_viewer(): + viewer.close() + + image_label.mousePressEvent = lambda event: close_viewer() + viewer.mousePressEvent = lambda event: close_viewer() + except Exception as e: self.status_bar.showMessage(f"创建图片查看器失败: {str(e)}", 3000) + import traceback + traceback.print_exc() def insert_images_in_text(self): """在文本中插入图片 - 修复图片显示逻辑""" -- 2.34.1 From 446d8d2d32806166143d1245f6606260f82be6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Fri, 31 Oct 2025 19:21:13 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E5=B0=8F=E5=BD=A9=E8=9B=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/114514.png | Bin 0 -> 127707 bytes src/word_main_window.py | 174 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 src/ui/114514.png diff --git a/src/ui/114514.png b/src/ui/114514.png new file mode 100644 index 0000000000000000000000000000000000000000..bbcf24377f65a0da4952087f3dbfa8d1ea144022 GIT binary patch literal 127707 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 Date: Fri, 31 Oct 2025 19:32:15 +0800 Subject: [PATCH 10/11] =?UTF-8?q?fix=EF=BC=9A=E5=85=B3=E4=BA=8EMagicWord?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/word_main_window.py | 44 ----------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/word_main_window.py b/src/word_main_window.py index cdf9d13..2a7f7da 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -2272,50 +2272,6 @@ class WordStyleMainWindow(QMainWindow): about_text.setStyleSheet("font-size: 12px; line-height: 1.5;") layout.addWidget(about_text) - # 添加图标展示区域 - icons_layout = QVBoxLayout() - icons_title = QLabel("应用程序图标") - icons_title.setAlignment(Qt.AlignCenter) - icons_title.setStyleSheet("font-size: 14px; font-weight: bold; margin-top: 10px;") - icons_layout.addWidget(icons_title) - - # 添加不同尺寸的图标 - icons_row_layout = QHBoxLayout() - - icon_sizes = [ - ("32x32", "app_icon_32X32.png"), - ("64x64", "app_icon_64X64.png"), - ("128x128", "app_icon_128X128.png"), - ("256x256", "app_icon_256X256.png") - ] - - for size_name, icon_file in icon_sizes: - try: - icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "icons", icon_file) - if os.path.exists(icon_path): - icon_container = QVBoxLayout() - - icon_label = QLabel() - icon_label.setAlignment(Qt.AlignCenter) - pixmap = QPixmap(icon_path) - if not pixmap.isNull(): - # 统一显示为32x32大小以便比较 - scaled_pixmap = pixmap.scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation) - icon_label.setPixmap(scaled_pixmap) - - size_label = QLabel(size_name) - size_label.setAlignment(Qt.AlignCenter) - size_label.setStyleSheet("font-size: 10px; color: #888;") - - icon_container.addWidget(icon_label) - icon_container.addWidget(size_label) - icons_row_layout.addLayout(icon_container) - except Exception as e: - print(f"加载图标 {icon_file} 失败: {e}") - - icons_layout.addLayout(icons_row_layout) - layout.addLayout(icons_layout) - # 添加按钮布局 button_layout = QHBoxLayout() button_layout.addStretch() # 添加弹性空间使按钮居中 -- 2.34.1 From 0b6b2018c6bb50b77be110138e1828e46ee4b87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E5=AD=90=E6=98=82?= <929110464@qq.com> Date: Fri, 31 Oct 2025 20:06:06 +0800 Subject: [PATCH 11/11] =?UTF-8?q?MAC=E7=AB=AF=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_macos_app.py | 309 +++++++++++++++++++++++++++++++++++++++++++ build_simple.py | 83 ++++++++++++ quick_build_macos.sh | 106 +++++++++++++++ 3 files changed, 498 insertions(+) create mode 100644 build_macos_app.py create mode 100644 build_simple.py create mode 100755 quick_build_macos.sh diff --git a/build_macos_app.py b/build_macos_app.py new file mode 100644 index 0000000..c0ff9f8 --- /dev/null +++ b/build_macos_app.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +MagicWord macOS M系列芯片打包脚本 +用于构建macOS Apple Silicon原生应用程序 +""" + +import os +import sys +import subprocess +import platform +import shutil +import plistlib +from datetime import datetime + +def run_command(command, shell=False, cwd=None): + """运行命令并返回结果""" + try: + result = subprocess.run(command, shell=shell, capture_output=True, text=True, encoding='utf-8', cwd=cwd) + return result.returncode, result.stdout, result.stderr + except Exception as e: + return -1, "", str(e) + +def check_system(): + """检查系统是否为macOS Apple Silicon""" + if platform.system() != "Darwin": + print("错误: 此脚本仅支持macOS系统") + return False + + # 检查是否为Apple Silicon + machine = platform.machine() + if machine not in ['arm64', 'aarch64']: + print(f"警告: 当前为 {machine} 架构,建议Apple Silicon (arm64) 以获得最佳性能") + + print(f"系统信息: macOS {platform.mac_ver()[0]}, {machine}") + return True + +def clean_build_dirs(): + """清理构建目录""" + print("清理构建目录...") + dirs_to_clean = ['build', 'dist', '__pycache__', '*.egg-info'] + + for dir_name in dirs_to_clean: + if '*' in dir_name: + import glob + for path in glob.glob(dir_name): + if os.path.isdir(path): + shutil.rmtree(path, ignore_errors=True) + elif os.path.exists(dir_name): + if os.path.isdir(dir_name): + shutil.rmtree(dir_name, ignore_errors=True) + else: + os.remove(dir_name) + + # 清理src目录下的__pycache__ + for root, dirs, files in os.walk('src'): + for dir_name in dirs: + if dir_name == '__pycache__': + cache_path = os.path.join(root, dir_name) + shutil.rmtree(cache_path, ignore_errors=True) + print(f"清理缓存: {cache_path}") + +def install_dependencies(): + """安装依赖""" + print("安装项目依赖...") + + # 首先确保pip是最新的 + run_command([sys.executable, "-m", "pip", "install", "--upgrade", "pip"]) + + # 安装requirements.txt中的依赖 + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]) + if code != 0: + print(f"依赖安装失败: {stderr}") + return False + + # 安装PyInstaller + print("安装PyInstaller...") + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "pyinstaller"]) + if code != 0: + print(f"PyInstaller安装失败: {stderr}") + return False + + print("依赖安装成功") + return True + +def build_macos_app(): + """构建macOS应用包""" + print("构建macOS应用包...") + + # PyInstaller命令 - 针对macOS优化 + pyinstaller_cmd = [ + "pyinstaller", + "--name", "MagicWord", + "--version", "0.3.0", + "--distpath", "dist", + "--workpath", "build", + "--specpath", ".", + # macOS特定的数据文件路径格式 + "--add-data", "resources:resources", + "--add-data", "src:src", + # 隐藏导入模块 + "--hidden-import", "PyQt5", + "--hidden-import", "PyQt5.QtCore", + "--hidden-import", "PyQt5.QtGui", + "--hidden-import", "PyQt5.QtWidgets", + "--hidden-import", "requests", + "--hidden-import", "beautifulsoup4", + "--hidden-import", "python-docx", + "--hidden-import", "PyPDF2", + "--hidden-import", "ebooklib", + "--hidden-import", "chardet", + "--hidden-import", "PIL", + # macOS应用包选项 + "--windowed", # 无控制台窗口 + "--osx-bundle-identifier", "com.magicword.app", + "--target-architecture", "arm64", # Apple Silicon + "--noconfirm", + "src/main.py" + ] + + print("运行PyInstaller...") + code, stdout, stderr = run_command(pyinstaller_cmd) + + if code != 0: + print(f"构建失败: {stderr}") + print("尝试通用架构...") + # 尝试通用架构 + pyinstaller_cmd[-2] = "--target-architecture" + pyinstaller_cmd[-1] = "universal2" + code, stdout, stderr = run_command(pyinstaller_cmd) + if code != 0: + print(f"通用架构构建也失败: {stderr}") + return False + + print("macOS应用包构建成功") + return True + +def create_app_bundle(): + """创建macOS应用束""" + print("创建macOS应用束...") + + app_path = "dist/MagicWord.app" + if not os.path.exists(app_path): + print(f"错误: 找不到应用包 {app_path}") + return False + + # 创建Info.plist文件 + info_plist = { + 'CFBundleName': 'MagicWord', + 'CFBundleDisplayName': 'MagicWord - 隐私学习软件', + 'CFBundleIdentifier': 'com.magicword.app', + 'CFBundleVersion': '0.3.0', + 'CFBundleShortVersionString': '0.3.0', + 'CFBundleExecutable': 'MagicWord', + 'CFBundlePackageType': 'APPL', + 'CFBundleSignature': '????', + 'LSMinimumSystemVersion': '11.0', # macOS Big Sur及更高版本 + 'NSHighResolutionCapable': True, + 'NSHumanReadableCopyright': 'Copyright © 2024 MagicWord Team. All rights reserved.', + 'CFBundleDocumentTypes': [ + { + 'CFBundleTypeName': 'Text Document', + 'CFBundleTypeExtensions': ['txt', 'docx', 'pdf'], + 'CFBundleTypeRole': 'Editor' + } + ] + } + + plist_path = os.path.join(app_path, "Contents", "Info.plist") + with open(plist_path, 'wb') as f: + plistlib.dump(info_plist, f) + + # 复制图标文件 + icon_files = [ + 'resources/icons/app_icon_128X128.png', + 'resources/icons/app_icon_256X256.png', + 'resources/icons/app_icon_32X32.png', + 'resources/icons/app_icon_64X64.png' + ] + + resources_dir = os.path.join(app_path, "Contents", "Resources") + os.makedirs(resources_dir, exist_ok=True) + + for icon_file in icon_files: + if os.path.exists(icon_file): + shutil.copy2(icon_file, resources_dir) + print(f"复制图标: {icon_file}") + + print("macOS应用束创建完成") + return True + +def create_dmg(): + """创建DMG安装包""" + print("创建DMG安装包...") + + app_path = "dist/MagicWord.app" + if not os.path.exists(app_path): + print(f"错误: 找不到应用包 {app_path}") + return False + + # 创建发布目录 + release_dir = "macos_release" + if os.path.exists(release_dir): + shutil.rmtree(release_dir) + os.makedirs(release_dir) + + # 复制应用到发布目录 + release_app_path = os.path.join(release_dir, "MagicWord.app") + shutil.copytree(app_path, release_app_path) + + # 创建应用程序链接 + applications_link = os.path.join(release_dir, "Applications") + os.symlink("/Applications", applications_link) + + # 创建README文件 + readme_content = f"""# MagicWord 0.3.0 for macOS + +## 安装说明 + +1. 将 MagicWord.app 拖拽到 Applications 文件夹 +2. 首次运行时,如果出现安全提示,请前往 系统设置 > 隐私与安全性 允许应用运行 +3. 或者右键点击应用选择"打开" + +## 系统要求 + +- macOS Big Sur (11.0) 或更高版本 +- Apple Silicon (M1/M2/M3) 或 Intel 处理器 + +## 功能特性 + +- 隐私学习:通过打字练习来学习文档内容 +- 支持多种文档格式:TXT, DOCX, PDF +- 智能打字模式 +- 美观的Word风格界面 + +## 版本信息 + +构建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} +平台: {platform.system()} {platform.machine()} +Python版本: {platform.python_version()} + +## 技术支持 + +如有问题,请查看项目文档或联系开发团队。 +""" + + with open(os.path.join(release_dir, "README.txt"), "w") as f: + f.write(readme_content) + + # 创建DMG文件(如果系统支持) + dmg_name = f"MagicWord-0.3.0-macOS-{platform.machine()}.dmg" + dmg_path = os.path.join("dist", dmg_name) + + # 使用hdiutil创建DMG + create_dmg_cmd = [ + "hdiutil", "create", + "-volname", "MagicWord", + "-srcfolder", release_dir, + "-ov", + "-format", "UDZO", + dmg_path + ] + + code, stdout, stderr = run_command(create_dmg_cmd) + if code == 0: + print(f"DMG创建成功: {dmg_path}") + return True + else: + print(f"DMG创建失败: {stderr}") + print("已创建应用包,可手动打包DMG") + return False + +def main(): + """主函数""" + print("=== MagicWord macOS打包脚本 ===") + print(f"构建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + + # 检查系统 + if not check_system(): + return False + + # 清理构建目录 + clean_build_dirs() + + # 安装依赖 + if not install_dependencies(): + print("依赖安装失败") + return False + + # 构建应用 + if not build_macos_app(): + print("应用构建失败") + return False + + # 创建应用束 + if not create_app_bundle(): + print("应用束创建失败") + return False + + # 创建DMG + create_dmg() + + print("\n=== 构建完成 ===") + print("应用位置: dist/MagicWord.app") + print("如需安装,请将应用拖拽到Applications文件夹") + print("首次运行时可能需要允许未知来源的应用") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/build_simple.py b/build_simple.py new file mode 100644 index 0000000..4c7bd88 --- /dev/null +++ b/build_simple.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +""" +MagicWord macOS简化打包脚本 +""" + +import os +import sys +import subprocess +import shutil + +def run_command(cmd): + """运行命令""" + print(f"运行: {' '.join(cmd)}") + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"错误: {result.stderr}") + return False + return True + +def main(): + print("=== MagicWord macOS打包 ===") + + # 清理旧的构建文件 + print("清理构建文件...") + for folder in ['build', 'dist', '__pycache__']: + if os.path.exists(folder): + shutil.rmtree(folder) + + # 安装依赖 + print("安装依赖...") + if not run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]): + return + + if not run_command([sys.executable, "-m", "pip", "install", "pyinstaller"]): + return + + # 构建命令 - 包含所有必要的图片和图标文件 + cmd = [ + sys.executable, "-m", "PyInstaller", + "--name", "MagicWord", + "--distpath", "dist", + "--workpath", "build", + # 资源文件 + "--add-data", "resources:resources", + # UI图片文件 + "--add-data", "src/ui/UI.png:ui", + "--add-data", "src/ui/114514.png:ui", + # 图标文件 + "--add-data", "resources/icons/app_icon_32X32.png:resources/icons", + "--add-data", "resources/icons/app_icon_64X64.png:resources/icons", + "--add-data", "resources/icons/app_icon_128X128.png:resources/icons", + "--add-data", "resources/icons/app_icon_256X256.png:resources/icons", + # 隐藏导入模块 + "--hidden-import", "PyQt5", + "--hidden-import", "PyQt5.QtCore", + "--hidden-import", "PyQt5.QtGui", + "--hidden-import", "PyQt5.QtWidgets", + "--hidden-import", "requests", + "--hidden-import", "beautifulsoup4", + "--hidden-import", "python-docx", + "--hidden-import", "PyPDF2", + "--hidden-import", "ebooklib", + "--hidden-import", "chardet", + "--hidden-import", "PIL", + # macOS应用选项 + "--windowed", + "--osx-bundle-identifier", "com.magicword.app", + "--icon", "resources/icons/app_icon_128X128.png", + "src/main.py" + ] + + print("构建应用...") + if run_command(cmd): + print("✅ 构建成功!") + print(f"应用位置: {os.path.abspath('dist/MagicWord.app')}") + print("\n安装步骤:") + print("1. 将 MagicWord.app 拖拽到 Applications 文件夹") + print("2. 首次运行时,右键点击应用选择'打开'") + else: + print("❌ 构建失败!") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/quick_build_macos.sh b/quick_build_macos.sh new file mode 100755 index 0000000..bf8b1db --- /dev/null +++ b/quick_build_macos.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# MagicWord macOS快速打包脚本 + +echo "=== MagicWord macOS打包脚本 ===" +echo "开始打包进程..." + +# 检查Python版本 +python_version=$(python3 --version 2>/dev/null || python --version) +echo "Python版本: $python_version" + +# 安装依赖 +echo "安装依赖..." +pip3 install -r requirements.txt +pip3 install pyinstaller + +# 清理旧的构建文件 +echo "清理旧的构建文件..." +rm -rf build dist __pycache__ *.spec +find src -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true + +# 构建应用 +echo "构建macOS应用..." +python3 -m pyinstaller \\ + --name "MagicWord" \\ + --distpath "dist" \\ + --workpath "build" \\ + --add-data "resources:resources" \\ + --hidden-import "PyQt5" \\ + --hidden-import "PyQt5.QtCore" \\ + --hidden-import "PyQt5.QtGui" \\ + --hidden-import "PyQt5.QtWidgets" \\ + --hidden-import "requests" \\ + --hidden-import "beautifulsoup4" \\ + --hidden-import "python-docx" \\ + --hidden-import "PyPDF2" \\ + --hidden-import "ebooklib" \\ + --hidden-import "chardet" \\ + --hidden-import "PIL" \\ + --windowed \\ + --osx-bundle-identifier "com.magicword.app" \\ + --target-architecture arm64 \\ + --noconfirm \\ + src/main.py + +# 检查构建结果 +if [ -d "dist/MagicWord.app" ]; then + echo "✅ 构建成功!" + echo "应用位置: dist/MagicWord.app" + echo "" + echo "安装步骤:" + echo "1. 将 MagicWord.app 拖拽到 Applications 文件夹" + echo "2. 首次运行时,右键点击应用选择'打开'" + echo "3. 或者在 系统设置 > 隐私与安全性 中允许应用运行" +else + echo "❌ 构建失败!" + exit 1 +fi + +# 可选:创建DMG +read -p "是否创建DMG安装包?(y/n): " create_dmg +if [[ $create_dmg =~ ^[Yy]$ ]]; then + echo "创建DMG安装包..." + + # 创建发布目录 + release_dir="macos_release" + rm -rf "$release_dir" + mkdir -p "$release_dir" + + # 复制应用 + cp -r "dist/MagicWord.app" "$release_dir/" + + # 创建Applications链接 + ln -s "/Applications" "$release_dir/Applications" + + # 创建README + cat > "$release_dir/README.txt" << 'EOF' +MagicWord for macOS + +安装说明: +1. 将 MagicWord.app 拖拽到 Applications 文件夹 +2. 首次运行时,右键点击应用选择"打开" +3. 或者在 系统设置 > 隐私与安全性 中允许应用运行 + +系统要求: +- macOS Big Sur (11.0) 或更高版本 +- Apple Silicon (M1/M2/M3) 推荐 + +功能特性: +- 隐私学习:通过打字练习来学习文档内容 +- 支持多种文档格式:TXT, DOCX, PDF +- 智能打字模式 +- 美观的Word风格界面 +EOF + + # 创建DMG + dmg_name="MagicWord-0.3.0-macOS-arm64.dmg" + hdiutil create -volname "MagicWord" -srcfolder "$release_dir" -ov -format UDZO "$dmg_name" + + if [ -f "$dmg_name" ]; then + echo "✅ DMG创建成功: $dmg_name" + else + echo "⚠️ DMG创建失败,但应用包已准备就绪" + fi +fi + +echo "=== 打包完成 ===" \ No newline at end of file -- 2.34.1