From 88500b153b6615d7cfdc2bd86fb91151047215e0 Mon Sep 17 00:00:00 2001 From: Horse861 <929110464@qq.com> Date: Mon, 3 Nov 2025 11:16:52 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(=E5=AD=A6=E4=B9=A0=E6=A8=A1=E5=BC=8F):?= =?UTF-8?q?=20=E5=AE=9E=E7=8E=B0=E5=AD=A6=E4=B9=A0=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=8E=E6=89=93=E5=AD=97=E6=A8=A1=E5=BC=8F=E7=9A=84=E5=86=85?= =?UTF-8?q?=E5=AE=B9=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加学习模式窗口的内容变化信号和关闭信号 在打字模式窗口中处理学习模式的内容同步 优化学习模式窗口的初始化逻辑 --- src/learning_mode_window.py | 21 ++ src/main_window.py | 487 +----------------------------------- src/word_main_window.py | 65 ++++- 3 files changed, 91 insertions(+), 482 deletions(-) diff --git a/src/learning_mode_window.py b/src/learning_mode_window.py index 1ec350b..49305f4 100644 --- a/src/learning_mode_window.py +++ b/src/learning_mode_window.py @@ -14,6 +14,10 @@ from src.file_parser import FileParser from src.ui.theme_manager import theme_manager class LearningModeWindow(QMainWindow): + # 定义内容变化信号 + content_changed = pyqtSignal(str, int) # 参数:内容,位置 + # 定义关闭信号 + closed = pyqtSignal() def __init__(self, parent=None, imported_content="", current_position=0): """ 学习模式窗口 @@ -39,6 +43,9 @@ class LearningModeWindow(QMainWindow): # 初始化打字逻辑 self.init_typing_logic() + # 初始化同步位置跟踪 + self.last_sync_position = current_position + # 如果有导入内容,初始化显示 if self.imported_content: self.initialize_with_imported_content() @@ -335,6 +342,7 @@ class LearningModeWindow(QMainWindow): 文本变化处理 - 根据导入的内容逐步显示 - 更新学习进度 + - 同步内容到打字模式 """ # 如果正在加载文件,跳过处理 if self.is_loading_file: @@ -382,6 +390,7 @@ class LearningModeWindow(QMainWindow): self.status_label.setText(f"输入错误!期望字符: '{result.get('expected', '')}'") else: # 输入正确,更新进度 + old_position = self.current_position self.current_position = len(current_text) progress = (self.current_position / len(self.imported_content)) * 100 @@ -389,6 +398,15 @@ class LearningModeWindow(QMainWindow): f"进度: {progress:.1f}% ({self.current_position}/{len(self.imported_content)} 字符)" ) + # 只在用户新输入的字符上同步到打字模式 + if self.parent_window and hasattr(self.parent_window, 'text_edit'): + # 获取用户这一轮新输入的字符(与上一轮相比的新内容) + if old_position < self.current_position: + new_input = expected_text[old_position:self.current_position] + if new_input: # 只有新输入内容时才同步 + # 只同步新输入的内容,不传递整个文本 + self.content_changed.emit(new_input, len(new_input)) + # 检查是否完成 if result.get('completed', False): self.status_label.setText("恭喜!学习完成!") @@ -417,6 +435,9 @@ class LearningModeWindow(QMainWindow): 窗口关闭事件 - 通知父窗口学习模式已关闭 """ + # 发射关闭信号 + self.closed.emit() + if self.parent_window and hasattr(self.parent_window, 'on_learning_mode_closed'): self.parent_window.on_learning_mode_closed() diff --git a/src/main_window.py b/src/main_window.py index 6c8afa6..0dc3bd0 100644 --- a/src/main_window.py +++ b/src/main_window.py @@ -1,482 +1,9 @@ -import sys -import os -from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit, QAction, - QFileDialog, QVBoxLayout, QWidget, QLabel, QStatusBar, QMessageBox) -from PyQt5.QtGui import QFont, QTextCharFormat, QColor, QTextCursor -from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal - -# 添加项目根目录到Python路径 -sys.path.append(os.path.join(os.path.dirname(__file__), '..')) - -# 导入自定义UI组件 -from src.ui.components import CustomTitleBar, ProgressBarWidget, TextDisplayWidget, StatsDisplayWidget, QuoteDisplayWidget, WeatherDisplayWidget -from src.file_parser import FileParser -from src.typing_logic import TypingLogic -from src.services.network_service import NetworkService - -class WeatherFetchThread(QThread): - """天气信息获取线程""" - weather_fetched = pyqtSignal(object) # 天气信息获取成功信号 - error_occurred = pyqtSignal(str) # 错误发生信号 - - def __init__(self): - super().__init__() - self.network_service = NetworkService() - - def run(self): - try: - weather_info = self.network_service.get_weather_info() - if weather_info: - # 格式化天气信息 - formatted_info = ( - f"天气: {weather_info['city']} - " - f"{weather_info['description']} - " - f"温度: {weather_info['temperature']}°C - " - f"湿度: {weather_info['humidity']}% - " - f"风速: {weather_info['wind_speed']} m/s" - ) - self.weather_fetched.emit(formatted_info) - else: - self.error_occurred.emit("无法获取天气信息") - except Exception as e: - self.error_occurred.emit(f"获取天气信息时出错: {str(e)}") - -class MainWindow(QMainWindow): - def __init__(self): +def on_learning_mode_closed(self): """ - 初始化主窗口 - - 设置窗口标题为"隐私学习软件 - 仿Word" - - 设置窗口大小为800x600 - - 初始化学习内容存储变量 - - 初始化当前输入位置 - - 调用initUI()方法 + 学习模式窗口关闭回调 + - 清除学习窗口引用 + - 更新菜单状态 """ - super().__init__() - self.learning_content = "" - self.current_position = 0 - self.typing_logic = None - self.text_edit = None - self.status_bar = None - self.title_bar = None - self.progress_bar_widget = None - self.text_display_widget = None - self.initUI() - - def initUI(self): - """ - 创建和布局所有UI组件 - - 创建自定义标题栏 - - 创建文本显示组件 - - 调用createMenuBar()创建菜单 - - 创建状态栏并显示"就绪" - """ - # 设置窗口属性 - self.setWindowTitle("隐私学习软件 - 仿Word") - self.setGeometry(100, 100, 800, 600) - self.setWindowFlags(Qt.FramelessWindowHint) # 移除默认标题栏 - - # 创建中央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.title_bar = CustomTitleBar(self) - main_layout.addWidget(self.title_bar) - - # 创建统计信息显示组件(默认隐藏) - self.stats_display = StatsDisplayWidget(self) - self.stats_display.setVisible(False) # 默认隐藏 - main_layout.addWidget(self.stats_display) - - # 创建每日一言显示组件(默认隐藏) - self.quote_display = QuoteDisplayWidget(self) - self.quote_display.setVisible(False) # 默认隐藏 - main_layout.addWidget(self.quote_display) - - # 创建天气显示组件(默认隐藏) - self.weather_display = WeatherDisplayWidget(self) - self.weather_display.setVisible(False) # 默认隐藏 - main_layout.addWidget(self.weather_display) - - # 创建文本显示组件 - self.text_display_widget = TextDisplayWidget(self) - main_layout.addWidget(self.text_display_widget) - - # 连接文本显示组件的文本变化信号 - self.text_display_widget.text_display.textChanged.connect(self.onTextChanged) - - # 创建菜单栏 - self.createMenuBar() - - # 创建状态栏 - self.status_bar = self.statusBar() - self.status_bar.showMessage("就绪") - - def createTopFunctionArea(self, main_layout): - """ - 创建顶部功能区域 - - 显示准确率、WPM等统计信息 - - 显示每日一言功能 - """ - from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QPushButton - from PyQt5.QtCore import Qt - - # 创建顶部功能区域widget - top_widget = QWidget() - top_widget.setStyleSheet(""" - QWidget { - background-color: #f0f0f0; - border-bottom: 1px solid #d0d0d0; - } - """) - - # 创建水平布局 - top_layout = QHBoxLayout() - top_layout.setContentsMargins(10, 5, 10, 5) - top_layout.setSpacing(15) - - # 创建统计信息标签 - self.wpm_label = QLabel("WPM: 0") - self.accuracy_label = QLabel("准确率: 0%") - 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.wpm_label.setStyleSheet(label_style) - self.accuracy_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; - } - """) - self.refresh_quote_button.clicked.connect(self.refresh_daily_quote) - - # 添加组件到布局 - top_layout.addWidget(self.wpm_label) - top_layout.addWidget(self.accuracy_label) - top_layout.addStretch() - top_layout.addWidget(self.quote_label) - top_layout.addWidget(self.refresh_quote_button) - - top_widget.setLayout(top_layout) - main_layout.addWidget(top_widget) - - def createMenuBar(self): - """ - 创建菜单栏和所有菜单项 - - 文件菜单:打开(Ctrl+O)、保存(Ctrl+S)、退出(Ctrl+Q) - - 视图菜单:显示统计信息、显示每日一言 - - 帮助菜单:关于 - - 为每个菜单项连接对应的槽函数 - """ - menu_bar = self.menuBar() - - # 文件菜单 - file_menu = menu_bar.addMenu('文件') - - # 打开动作 - open_action = QAction('打开', self) - open_action.setShortcut('Ctrl+O') - open_action.triggered.connect(self.openFile) - file_menu.addAction(open_action) - - # 保存动作 - save_action = QAction('保存', self) - save_action.setShortcut('Ctrl+S') - save_action.triggered.connect(self.saveFile) - file_menu.addAction(save_action) - - # 分隔线 - file_menu.addSeparator() - - # 退出动作 - exit_action = QAction('退出', self) - exit_action.setShortcut('Ctrl+Q') - exit_action.triggered.connect(self.close) - file_menu.addAction(exit_action) - - # 视图菜单 - view_menu = menu_bar.addMenu('视图') - - # 显示统计信息动作 - self.stats_action = QAction('显示统计信息', self) - self.stats_action.setCheckable(True) - self.stats_action.setChecked(True) - self.stats_action.triggered.connect(self.toggleStatsDisplay) - view_menu.addAction(self.stats_action) - - # 显示每日一言动作 - self.quote_action = QAction('显示每日一言', self) - self.quote_action.setCheckable(True) - self.quote_action.setChecked(True) - self.quote_action.triggered.connect(self.toggleQuoteDisplay) - view_menu.addAction(self.quote_action) - - # 显示天气信息动作 - self.weather_action = QAction('显示天气', self) - self.weather_action.setCheckable(True) - self.weather_action.setChecked(True) - self.weather_action.triggered.connect(self.toggleWeatherDisplay) - view_menu.addAction(self.weather_action) - - # 帮助菜单 - help_menu = menu_bar.addMenu('帮助') - - # 关于动作 - about_action = QAction('关于', self) - about_action.triggered.connect(self.showAbout) - help_menu.addAction(about_action) - - def toggleStatsDisplay(self, checked): - """ - 切换统计信息显示 - - checked: 是否显示统计信息 - """ - self.stats_display.setVisible(checked) - - def toggleQuoteDisplay(self, checked): - """ - 切换每日一言显示 - - checked: 是否显示每日一言 - """ - self.quote_display.setVisible(checked) - # 如果启用显示且quote为空,则刷新一次 - if checked and not self.quote_display.quote_label.text(): - self.refresh_daily_quote() - - def toggleWeatherDisplay(self, checked): - """切换天气信息显示""" - self.weather_display.setVisible(checked) - # 如果启用显示且天气信息为空,则刷新一次 - if checked and not self.weather_display.weather_label.text(): - self.refresh_weather_info() - - def openFile(self): - """ - 打开文件选择对话框并加载选中的文件 - - 显示文件选择对话框,过滤条件:*.txt, *.docx, *.pdf - - 如果用户选择了文件,调用FileParser.parse_file(file_path) - - 成功时:将内容存储但不直接显示,重置打字状态 - - 失败时:显示错误消息框 - """ - options = QFileDialog.Options() - file_path, _ = QFileDialog.getOpenFileName( - self, - "打开文件", - "", - "文本文件 (*.txt);;Word文档 (*.docx);;PDF文件 (*.pdf);;所有文件 (*)", - options=options - ) - - if file_path: - try: - # 解析文件内容 - content = FileParser.parse_file(file_path) - self.learning_content = content - - # 在文本显示组件中设置内容(初始为空,通过打字逐步显示) - if self.text_display_widget: - self.text_display_widget.set_text(content) # 设置文件内容 - - # 重置打字状态 - self.typing_logic = TypingLogic(content) - self.current_position = 0 - - # 更新状态栏 - self.status_bar.showMessage(f"已打开文件: {file_path},开始打字以显示内容") - except Exception as e: - # 显示错误消息框 - QMessageBox.critical(self, "错误", f"无法打开文件:\n{str(e)}") - - def saveFile(self): - """ - 保存当前内容到文件 - - 显示保存文件对话框 - - 将文本区域内容写入选定文件 - - 返回操作结果 - """ - options = QFileDialog.Options() - file_path, _ = QFileDialog.getSaveFileName( - self, - "保存文件", - "", - "文本文件 (*.txt);;所有文件 (*)", - options=options - ) - - if file_path: - try: - # 获取文本编辑区域的内容 - content = self.text_edit.toPlainText() - - # 写入文件 - with open(file_path, 'w', encoding='utf-8') as f: - f.write(content) - - # 更新状态栏 - self.status_bar.showMessage(f"文件已保存: {file_path}") - - return True - except Exception as e: - # 显示错误消息框 - QMessageBox.critical(self, "错误", f"无法保存文件:\n{str(e)}") - return False - - return False - - def showAbout(self): - """ - 显示关于对话框 - - 显示消息框,包含软件名称、版本、描述 - """ - QMessageBox.about( - self, - "关于", - "隐私学习软件 - 仿Word\n\n" - "版本: 1.0\n\n" - "这是一个用于隐私学习的打字练习软件,\n" - "可以加载文档并进行打字练习,\n" - "帮助提高打字速度和准确性。" - ) - - def refresh_daily_quote(self): - """ - 刷新每日一言 - - 从网络API获取名言 - - 更新显示 - """ - import requests - import json - from PyQt5.QtCore import Qt - from src.constants import QUOTE_API_URL - - try: - # 发送请求获取每日一言 - response = requests.get(QUOTE_API_URL, timeout=5) - if response.status_code == 200: - data = response.json() - quote_content = data.get('content', '暂无内容') - quote_author = data.get('author', '未知作者') - - # 更新显示 - self.quote_label.setText(f"每日一言: {quote_content} — {quote_author}") - - # 同时更新统计信息显示组件中的每日一言 - if hasattr(self, 'stats_display') and self.stats_display: - self.stats_display.update_quote(f"{quote_content} — {quote_author}") - else: - self.quote_label.setText("每日一言: 获取失败") - # 同时更新统计信息显示组件中的每日一言 - if hasattr(self, 'stats_display') and self.stats_display: - self.stats_display.update_quote("获取失败") - except Exception as e: - self.quote_label.setText("每日一言: 获取失败") - # 同时更新统计信息显示组件中的每日一言 - if hasattr(self, 'stats_display') and self.stats_display: - self.stats_display.update_quote("获取失败") - - def onTextChanged(self): - """ - 处理用户输入变化事件(打字练习) - - 获取文本显示组件中的文本 - - 使用TypingLogic.check_input检查输入 - - 根据结果更新文本显示组件 - - 更新统计数据展示 - """ - # 防止递归调用 - if getattr(self, '_processing_text_change', False): - return - - if not self.typing_logic: - return - - # 设置标志防止递归 - self._processing_text_change = True - - try: - # 获取当前输入文本 - current_text = self.text_display_widget.text_display.toPlainText() - - # 检查输入是否正确 - result = self.typing_logic.check_input(current_text) - is_correct = result["correct"] - expected_char = result["expected"] - - # 更新文本显示组件 - if self.text_display_widget: - # 显示用户输入反馈 - self.text_display_widget.show_user_input(current_text) - - # 不再高亮下一个字符,因为内容通过打字逐步显示 - - # 计算统计数据 - stats = self.typing_logic.get_statistics() - accuracy = stats['accuracy_rate'] * 100 # 转换为百分比 - # 可以根据需要添加更多统计数据的计算 - wpm = 0 # 暂时设置为0,后续可以实现WPM计算 - - # 更新状态栏 - self.status_bar.showMessage(f"WPM: {wpm:.1f} | 准确率: {accuracy:.1f}%") - - # 更新统计信息显示组件 - if hasattr(self, 'stats_display') and self.stats_display.isVisible(): - self.stats_display.update_stats(int(wpm), accuracy) - - # 更新每日一言显示组件(如果需要) - if hasattr(self, 'quote_display') and self.quote_display.isVisible() and not self.quote_display.quote_label.text(): - self.refresh_daily_quote() - - # 更新顶部功能区的统计数据(如果仍然存在) - if hasattr(self, 'wpm_label') and self.wpm_label: - self.wpm_label.setText(f"WPM: {wpm:.1f}") - if hasattr(self, 'accuracy_label') and self.accuracy_label: - self.accuracy_label.setText(f"准确率: {accuracy:.1f}%") - finally: - # 清除递归防止标志 - self._processing_text_change = False - - def refresh_daily_quote(self): - """刷新每日一言""" - # 创建并启动获取名言的线程 - self.quote_thread = QuoteFetchThread() - self.quote_thread.quote_fetched.connect(self.on_quote_fetched) - self.quote_thread.error_occurred.connect(self.on_quote_error) - self.quote_thread.start() - - def refresh_weather_info(self): - """刷新天气信息""" - # 创建并启动获取天气信息的线程 - self.weather_thread = WeatherFetchThread() - self.weather_thread.weather_fetched.connect(self.on_weather_fetched) - self.weather_thread.error_occurred.connect(self.on_weather_error) - self.weather_thread.start() - - def on_weather_fetched(self, weather_info): - """处理天气信息获取成功""" - # 更新天气显示组件 - if hasattr(self, 'weather_display') and self.weather_display: - self.weather_display.update_weather(weather_info) - - def on_weather_error(self, error_msg): - """处理天气信息获取错误""" - # 更新天气显示组件 - if hasattr(self, 'weather_display') and self.weather_display: - self.weather_display.update_weather(error_msg) \ No newline at end of file + self.learning_window = None + self.learning_mode_action.setChecked(False) + self.typing_mode_action.setChecked(True) \ No newline at end of file diff --git a/src/word_main_window.py b/src/word_main_window.py index 2a7f7da..9fcdd7c 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -83,6 +83,10 @@ class WordStyleMainWindow(QMainWindow): self.learning_text = "" # 学习模式下的文本内容 self.cursor_position = 0 # 光标位置 + # 学习模式窗口引用和同步标记 + self.learning_window = None # 学习模式窗口引用 + self.sync_from_learning = False # 从学习模式同步内容的标记 + # 统一文档内容管理 self.unified_document_content = "" # 统一文档内容 self.last_edit_mode = "typing" # 上次编辑模式 @@ -836,6 +840,10 @@ class WordStyleMainWindow(QMainWindow): # 如果正在加载文件,跳过处理 if self.is_loading_file: return + + # 检查是否是从学习模式同步内容,避免递归调用 + if hasattr(self, 'sync_from_learning') and self.sync_from_learning: + return # 根据当前视图模式处理 if self.view_mode == "learning": @@ -852,8 +860,9 @@ class WordStyleMainWindow(QMainWindow): self.handle_learning_mode_typing() elif self.view_mode == "typing": - # 打字模式:可以自由打字 - self.handle_typing_mode_typing() + # 打字模式:可以自由打字,不自动处理内容 + # 只在用户主动操作时处理,避免内容被覆盖 + pass # 标记文档为已修改 if not self.is_modified: @@ -1856,10 +1865,24 @@ class WordStyleMainWindow(QMainWindow): imported_content = self.imported_content if hasattr(self, 'learning_progress') and self.learning_progress > 0: current_position = self.learning_progress + else: + # 如果没有导入内容,检查当前打字模式的内容 + current_text = self.text_edit.toPlainText() + if current_text and current_text != "在此输入您的内容...": + # 将打字模式的内容作为学习模式的导入内容 + imported_content = current_text + current_position = 0 + self.imported_content = current_text # 创建学习模式窗口,直接传递导入内容 self.learning_window = LearningModeWindow(self, imported_content, current_position) + # 连接学习模式窗口的内容变化信号 + self.learning_window.content_changed.connect(self.on_learning_content_changed) + + # 连接学习模式窗口的关闭信号 + self.learning_window.closed.connect(self.on_learning_mode_closed) + # 显示学习模式窗口 self.learning_window.show() @@ -1890,8 +1913,46 @@ class WordStyleMainWindow(QMainWindow): self.learning_mode_action.setChecked(False) self.typing_mode_action.setChecked(True) self.view_mode = "typing" + + # 清除学习窗口引用 + self.learning_window = None + self.status_bar.showMessage("学习模式窗口已关闭", 2000) + def on_learning_content_changed(self, new_content, position): + """学习模式内容变化时的回调 - 只在末尾追加新内容""" + # 设置同步标记,防止递归调用 + self.sync_from_learning = True + + try: + # 只在末尾追加新输入的内容,不修改已有内容 + if new_content: + # 直接在末尾追加新内容 + cursor = self.text_edit.textCursor() + cursor.movePosition(QTextCursor.End) + cursor.insertText(new_content) + + # 更新导入内容(但不覆盖用户额外输入的内容) + if self.imported_content: + self.imported_content += new_content + else: + self.imported_content = new_content + + self.learning_progress = len(self.imported_content) if self.imported_content else 0 + + # 重置打字逻辑(不追踪进度) + if self.typing_logic: + self.typing_logic.imported_content = self.imported_content + self.typing_logic.current_index = self.learning_progress + self.typing_logic.typed_chars = self.learning_progress + + # 更新状态栏 + self.status_bar.showMessage(f"从学习模式同步新内容: {new_content}", 3000) + + finally: + # 重置同步标记 + self.sync_from_learning = False + def set_page_color(self, color): """设置页面颜色""" color_map = { -- 2.34.1 From 5d8e05c722aa395ae863a8b19eeb3c250fc153c7 Mon Sep 17 00:00:00 2001 From: Horse861 <929110464@qq.com> Date: Mon, 3 Nov 2025 11:36:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test.docx | Bin 0 -> 21936 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test.docx diff --git a/test.docx b/test.docx new file mode 100644 index 0000000000000000000000000000000000000000..2564c62ed0a7fcaa3172e69d2e3600be8a15bf5e GIT binary patch literal 21936 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 literal 0 HcmV?d00001 -- 2.34.1