You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Curriculum_Design/src/ui/components.py

492 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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