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)')