diff --git a/src/settings/resources/config/test_config.json b/src/settings/resources/config/test_config.json
new file mode 100644
index 0000000..9f16c30
--- /dev/null
+++ b/src/settings/resources/config/test_config.json
@@ -0,0 +1,45 @@
+{
+ "application": {
+ "name": "MagicWord",
+ "version": "2.0.0",
+ "author": "MagicWord Team",
+ "description": "隐私学习软件"
+ },
+ "window": {
+ "default_size": {
+ "width": 800,
+ "height": 600
+ },
+ "minimum_size": {
+ "width": 600,
+ "height": 400
+ },
+ "title": "MagicWord - 隐私学习软件"
+ },
+ "typing": {
+ "default_time_limit": 300,
+ "show_progress_bar": true,
+ "highlight_current_line": true,
+ "auto_save_progress": true
+ },
+ "files": {
+ "supported_formats": [
+ ".txt",
+ ".docx"
+ ],
+ "auto_backup_enabled": true,
+ "backup_interval_minutes": 30
+ },
+ "network": {
+ "weather_api_key": "YOUR_WEATHER_API_KEY",
+ "quote_api_url": "https://api.quotable.io/random",
+ "timeout_seconds": 10
+ },
+ "appearance": {
+ "theme": "light",
+ "font_family": "Arial",
+ "font_size": 12,
+ "text_color": "#000000",
+ "background_color": "#FFFFFF"
+ }
+}
\ No newline at end of file
diff --git a/src/settings/settings_manager.py b/src/settings/settings_manager.py
index e5fdd76..d26a64a 100644
--- a/src/settings/settings_manager.py
+++ b/src/settings/settings_manager.py
@@ -10,8 +10,63 @@ class SettingsManager:
- 指定配置文件路径
- 加载现有配置或创建默认配置
"""
- # TODO: 实现构造函数逻辑
- pass
+ # 指定配置文件路径
+ self.config_file = config_file
+ self.config_path = os.path.join("resources", "config", config_file)
+
+ # 加载现有配置或创建默认配置
+ self.settings = self.load_settings()
+ if not self.settings:
+ self.settings = self._create_default_settings()
+ self.save_settings(self.settings)
+
+ def _create_default_settings(self) -> Dict[str, Any]:
+ """
+ 创建默认配置
+ - 返回包含默认设置的字典
+ """
+ return {
+ "application": {
+ "name": "MagicWord",
+ "version": "1.0.0",
+ "author": "MagicWord Team",
+ "description": "好东西"
+ },
+ "window": {
+ "default_size": {
+ "width": 800,
+ "height": 600
+ },
+ "minimum_size": {
+ "width": 600,
+ "height": 400
+ },
+ "title": "MagicWord"
+ },
+ "typing": {
+ "default_time_limit": 300,
+ "show_progress_bar": True,
+ "highlight_current_line": True,
+ "auto_save_progress": True
+ },
+ "files": {
+ "supported_formats": [".txt", ".docx"],
+ "auto_backup_enabled": True,
+ "backup_interval_minutes": 30
+ },
+ "network": {
+ "weather_api_key": "YOUR_WEATHER_API_KEY",
+ "quote_api_url": "https://api.quotable.io/random",
+ "timeout_seconds": 10
+ },
+ "appearance": {
+ "theme": "light",
+ "font_family": "Arial",
+ "font_size": 12,
+ "text_color": "#000000",
+ "background_color": "#FFFFFF"
+ }
+ }
def load_settings(self) -> Dict[str, Any]:
"""
@@ -19,8 +74,15 @@ class SettingsManager:
- 从配置文件读取设置
- 返回设置字典
"""
- # TODO: 实现设置加载逻辑
- pass
+ try:
+ if os.path.exists(self.config_path):
+ with open(self.config_path, 'r', encoding='utf-8') as f:
+ return json.load(f)
+ else:
+ return {}
+ except (json.JSONDecodeError, IOError) as e:
+ print(f"加载配置文件时出错: {e}")
+ return {}
def save_settings(self, settings: Dict[str, Any]) -> bool:
"""
@@ -28,8 +90,19 @@ class SettingsManager:
- 将设置保存到配置文件
- 返回保存结果
"""
- # TODO: 实现设置保存逻辑
- pass
+ try:
+ # 确保目录存在
+ config_dir = os.path.dirname(self.config_path)
+ if not os.path.exists(config_dir):
+ os.makedirs(config_dir)
+
+ # 保存设置到文件
+ with open(self.config_path, 'w', encoding='utf-8') as f:
+ json.dump(settings, f, ensure_ascii=False, indent=4)
+ return True
+ except (IOError, TypeError) as e:
+ print(f"保存配置文件时出错: {e}")
+ return False
def get_setting(self, key: str, default: Any = None) -> Any:
"""
@@ -37,8 +110,14 @@ class SettingsManager:
- 根据键名获取设置值
- 如果不存在返回默认值
"""
- # TODO: 实现获取设置项逻辑
- pass
+ keys = key.split('.')
+ value = self.settings
+ try:
+ for k in keys:
+ value = value[k]
+ return value
+ except (KeyError, TypeError):
+ return default
def set_setting(self, key: str, value: Any) -> bool:
"""
@@ -46,5 +125,21 @@ class SettingsManager:
- 设置指定键的值
- 保存到配置文件
"""
- # TODO: 实现设置设置项逻辑
- pass
\ No newline at end of file
+ keys = key.split('.')
+ setting_dict = self.settings
+
+ # 导航到倒数第二个键
+ try:
+ for k in keys[:-1]:
+ if k not in setting_dict:
+ setting_dict[k] = {}
+ setting_dict = setting_dict[k]
+
+ # 设置最后一个键的值
+ setting_dict[keys[-1]] = value
+
+ # 保存到配置文件
+ return self.save_settings(self.settings)
+ except (KeyError, TypeError) as e:
+ print(f"设置配置项时出错: {e}")
+ return False
\ No newline at end of file
diff --git a/src/ui/components.py b/src/ui/components.py
index 2763f93..948839f 100644
--- a/src/ui/components.py
+++ b/src/ui/components.py
@@ -10,12 +10,8 @@ class CustomTitleBar(QWidget):
- 添加窗口控制按钮
"""
super().__init__(parent)
- # TODO: 实现标题栏UI
- # 1. 创建标题标签
- # 2. 创建最小化、最大化、关闭按钮
- # 3. 设置布局和样式
- # 4. 连接按钮事件
- pass
+ self.parent = parent
+ self.setup_ui()
def setup_ui(self):
"""
@@ -23,42 +19,92 @@ class CustomTitleBar(QWidget):
- 初始化所有UI组件
- 设置组件属性和样式
"""
- # TODO: 实现UI设置逻辑
- # 1. 创建水平布局
- # 2. 添加标题标签和控制按钮
- # 3. 设置组件样式
- pass
+ # 创建水平布局
+ 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):
"""
最小化窗口
- 触发窗口最小化事件
"""
- # TODO: 实现窗口最小化逻辑
- # 1. 获取父窗口
- # 2. 调用窗口最小化方法
- pass
+ if self.parent:
+ self.parent.showMinimized()
def maximize_window(self):
"""
最大化窗口
- 切换窗口最大化状态
"""
- # TODO: 实现窗口最大化逻辑
- # 1. 获取父窗口
- # 2. 检查当前窗口状态
- # 3. 切换最大化/还原状态
- pass
+ 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):
"""
关闭窗口
- 触发窗口关闭事件
"""
- # TODO: 实现窗口关闭逻辑
- # 1. 获取父窗口
- # 2. 调用窗口关闭方法
- pass
+ if self.parent:
+ self.parent.close()
class ProgressBarWidget(QWidget):
def __init__(self, parent=None):
@@ -68,11 +114,69 @@ class ProgressBarWidget(QWidget):
- 显示统计信息
"""
super().__init__(parent)
- # TODO: 实现进度条组件初始化
- # 1. 创建进度条UI元素
- # 2. 创建统计信息标签
- # 3. 设置布局
- pass
+ self.setup_ui()
+
+ def setup_ui(self):
+ """
+ 设置进度条UI
+ - 初始化所有UI组件
+ - 设置组件属性和样式
+ """
+ # 创建垂直布局
+ layout = QVBoxLayout()
+ layout.setContentsMargins(10, 10, 10, 10)
+ layout.setSpacing(5)
+
+ # 导入需要的模块
+ from PyQt5.QtWidgets import QProgressBar, QHBoxLayout
+
+ # 创建水平布局用于统计信息
+ 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):
"""
@@ -80,21 +184,18 @@ class ProgressBarWidget(QWidget):
- 设置进度值
- 更新显示
"""
- # TODO: 实现进度更新逻辑
- # 1. 更新进度条数值
- # 2. 刷新UI显示
- pass
+ self.progress_bar.setValue(int(progress))
def update_stats(self, wpm: int, accuracy: float, time_elapsed: int):
"""
更新统计信息
- - 显示WPM、准确率、用时等信息
+ - wpm: 每分钟字数
+ - accuracy: 准确率(%)
+ - time_elapsed: 用时(秒)
"""
- # TODO: 实现统计信息更新逻辑
- # 1. 更新WPM标签
- # 2. 更新准确率标签
- # 3. 更新用时标签
- pass
+ self.wpm_label.setText(f"WPM: {wpm}")
+ self.accuracy_label.setText(f"准确率: {accuracy:.1f}%")
+ self.time_label.setText(f"用时: {time_elapsed}s")
class TextDisplayWidget(QWidget):
def __init__(self, parent=None):
@@ -102,47 +203,123 @@ class TextDisplayWidget(QWidget):
文本显示组件
- 显示待练习文本
- 高亮当前字符
- - 显示用户输入
+ - 显示用户输入反馈
"""
super().__init__(parent)
- # TODO: 实现文本显示组件初始化
- # 1. 创建文本显示区域
- # 2. 设置文本样式
- # 3. 初始化高亮相关属性
- pass
+ self.text_content = ""
+ self.current_index = 0
+ self.setup_ui()
+
+ def setup_ui(self):
+ """
+ 设置文本显示UI
+ - 初始化文本显示区域
+ - 设置样式和布局
+ """
+ # 创建垂直布局
+ layout = QVBoxLayout()
+ layout.setContentsMargins(20, 20, 20, 20)
+
+ # 导入需要的模块
+ from PyQt5.QtWidgets import QTextEdit
+ from PyQt5.QtCore import Qt
+
+ # 创建文本显示区域
+ self.text_display = QTextEdit()
+ self.text_display.setReadOnly(True)
+ 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):
"""
设置显示文本
- - 更新显示内容
- - 重置高亮状态
- """
- # TODO: 实现文本设置逻辑
- # 1. 更新内部文本内容
- # 2. 重置高亮位置
- # 3. 刷新UI显示
- pass
+ - text: 要显示的文本内容
+ """
+ self.text_content = text
+ self.current_index = 0
+ self._update_display()
def highlight_character(self, position: int):
"""
- 高亮指定位置字符
- - 更新高亮位置
- - 刷新显示
+ 高亮指定位置的字符
+ - position: 字符位置索引
"""
- # TODO: 实现字符高亮逻辑
- # 1. 计算高亮范围
- # 2. 应用高亮样式
- # 3. 滚动到高亮位置
- pass
+ if 0 <= position < len(self.text_content):
+ self.current_index = position
+ self._update_display()
+ def _update_display(self, user_input: str = ""):
+ """
+ 更新文本显示
+ - user_input: 用户输入文本(可选)
+ """
+ # 导入需要的模块
+ from PyQt5.QtGui import QTextCursor
+ import sys
+ import os
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+ from constants import COLOR_CORRECT, COLOR_WRONG, COLOR_HIGHLIGHT
+
+ if not self.text_content:
+ self.text_display.clear()
+ return
+
+ # 创建带格式的HTML文本
+ formatted_text = ""
+
+ # 如果有用户输入,对比显示
+ if user_input:
+ for i, char in enumerate(self.text_content):
+ if i < len(user_input):
+ if char == user_input[i]:
+ # 正确字符
+ formatted_text += f'{char}'
+ else:
+ # 错误字符
+ formatted_text += f'{char}'
+ elif i == len(user_input):
+ # 当前字符
+ formatted_text += f'{char}'
+ else:
+ # 未到达的字符
+ formatted_text += char
+ else:
+ # 没有用户输入,只显示原文和当前高亮字符
+ for i, char in enumerate(self.text_content):
+ if i == self.current_index:
+ # 当前字符高亮
+ formatted_text += f'{char}'
+ else:
+ formatted_text += char
+
+ # 更新文本显示
+ self.text_display.setHtml(formatted_text)
+
+ # 滚动到当前高亮字符位置
+ cursor = self.text_display.textCursor()
+ cursor.setPosition(min(self.current_index + 5, len(self.text_content)))
+ self.text_display.setTextCursor(cursor)
+ self.text_display.ensureCursorVisible()
+
def show_user_input(self, input_text: str):
"""
- 显示用户输入
- - 在文本下方显示用户输入
- - 高亮正确/错误字符
+ 显示用户输入反馈
+ - input_text: 用户输入的文本
"""
- # TODO: 实现用户输入显示逻辑
- # 1. 对比用户输入与原文
- # 2. 分别高亮正确和错误字符
- # 3. 更新输入显示区域
- pass
\ No newline at end of file
+ self._update_display(input_text)
\ No newline at end of file