branch_develop #2

Merged
hnu202326010330 merged 6 commits from xuejiayu_branch into develop 4 months ago

@ -0,0 +1,674 @@
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QPushButton, QMessageBox, QFrame, QSizePolicy,QDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class LoginPage(QWidget): # 改为继承 QWidget
def __init__(self, parent=None):
super().__init__(parent)
self.parent_window = parent
self.user_system = parent.user_system if parent else None
self.setup_ui()
def setup_ui(self):
# 移除 setWindowTitle 和 setMinimumSize使用父窗口的尺寸
# 设置可爱的渐变背景
self.setStyleSheet("""
QWidget {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(20, 20, 20, 20)
main_layout.setSpacing(0)
# 添加返回按钮区域
back_button_layout = QHBoxLayout()
back_button_layout.setContentsMargins(0, 0, 0, 10)
self.back_btn = QPushButton("←返回")
self.back_btn.setMinimumHeight(50)
self.back_btn.setMaximumWidth(120)
self.back_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
font: bold 11pt '微软雅黑';
border-radius: 15px;
border: 2px solid #8ADBD9;
padding: 5px 15px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border: 2px solid #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
""")
self.back_btn.clicked.connect(self.go_back)
back_button_layout.addWidget(self.back_btn)
back_button_layout.addStretch() # 将按钮推到左边
main_layout.addLayout(back_button_layout)
# 卡片容器 - 自适应尺寸
card = QFrame()
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(card)
# 卡片布局
card_layout = QVBoxLayout(card)
card_layout.setContentsMargins(30, 25, 30, 25)
card_layout.setSpacing(0)
# 顶部弹性空间
card_layout.addStretch(1)
# 标题区域
title_frame = QFrame()
title_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(8)
# 装饰性emoji
emoji_label = QLabel("🔐✨🎮")
emoji_label.setStyleSheet("""
QLabel {
font: bold 18pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
emoji_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("用户登录")
title_label.setStyleSheet("""
QLabel {
font: bold 22pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(title_label)
subtitle_label = QLabel("🌟 欢迎回到数学冒险岛 🌟")
subtitle_label.setStyleSheet("""
QLabel {
font: 12pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
subtitle_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(subtitle_label)
card_layout.addWidget(title_frame)
card_layout.addSpacing(30)
# 输入区域
input_frame = QFrame()
input_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
input_frame.setStyleSheet("background: transparent; border: none;")
input_layout = QVBoxLayout(input_frame)
input_layout.setSpacing(20)
# 用户名区域
username_layout = QVBoxLayout()
username_layout.setSpacing(5)
username_label = QLabel("👤 用户名:")
username_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
username_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
username_layout.addWidget(username_label)
self.username_input = QLineEdit()
self.username_input.setMinimumHeight(40)
self.username_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.username_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.username_input.setPlaceholderText("请输入用户名...")
username_layout.addWidget(self.username_input)
input_layout.addLayout(username_layout)
# 密码区域
password_layout = QVBoxLayout()
password_layout.setSpacing(5)
password_label = QLabel("🔒 密码:")
password_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
password_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
password_layout.addWidget(password_label)
self.password_input = QLineEdit()
self.password_input.setMinimumHeight(40)
self.password_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.password_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.password_input.setEchoMode(QLineEdit.Password)
self.password_input.setPlaceholderText("请输入密码...")
password_layout.addWidget(self.password_input)
input_layout.addLayout(password_layout)
card_layout.addWidget(input_frame)
card_layout.addSpacing(25)
# 按钮区域
button_frame = QFrame()
button_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QVBoxLayout(button_frame)
button_layout.setSpacing(12)
# 登录按钮
self.login_btn = QPushButton("🚀 开始冒险")
self.login_btn.setMinimumHeight(45)
self.login_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.login_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9EBC, stop:1 #FF6B9C);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 20px;
border: 2px solid #FF85A1;
max-width: 300px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF85A1, stop:1 #FF5784);
border: 2px solid #FF6B9C;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF5784, stop:1 #FF3D6D);
}
""")
self.login_btn.clicked.connect(self.do_login)
button_layout.addWidget(self.login_btn, alignment=Qt.AlignCenter)
# 修改密码按钮
self.change_pwd_btn = QPushButton("🔑 修改密码")
self.change_pwd_btn.setMinimumHeight(40)
self.change_pwd_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.change_pwd_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
font: bold 12pt '微软雅黑';
border-radius: 18px;
border: 2px solid #8ADBD9;
max-width: 280px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border: 2px solid #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
""")
self.change_pwd_btn.clicked.connect(self.show_change_pwd)
button_layout.addWidget(self.change_pwd_btn, alignment=Qt.AlignCenter)
card_layout.addWidget(button_frame)
card_layout.addStretch(2)
# 装饰性底部
decoration_label = QLabel("✨🌈🎯 数学冒险岛 🌟🎮🚀")
decoration_label.setStyleSheet("""
QLabel {
font: bold 10pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
decoration_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
card_layout.addWidget(decoration_label)
# 绑定回车键
self.username_input.returnPressed.connect(self.do_login)
self.password_input.returnPressed.connect(self.do_login)
# 设置焦点
self.username_input.setFocus()
def go_back(self):
"""返回上一级页面"""
if self.parent_window:
self.parent_window.show_main_page() # 返回欢迎页面
def do_login(self):
"""执行登录"""
username = self.username_input.text().strip()
password = self.password_input.text()
if not username:
QMessageBox.warning(self, "⚠️ 提示", "请输入用户名")
self.username_input.setFocus()
return
if not password:
QMessageBox.warning(self, "⚠️ 提示", "请输入密码")
self.password_input.setFocus()
return
if self.user_system.login(username, password):
QMessageBox.information(self, "🎉 登录成功", f"欢迎 {username} 回到数学冒险岛!")
# 不再使用 self.accept(),而是通知父窗口切换页面
if self.parent_window:
self.parent_window.show_level_page()
else:
QMessageBox.warning(self, "❌ 登录失败", "用户名或密码错误,请重试")
self.password_input.clear()
self.password_input.setFocus()
def show_change_pwd(self):
"""显示修改密码界面"""
from .login_ui import ChangePasswordUI
change_pwd_ui = ChangePasswordUI(self)
change_pwd_ui.exec_() # 修改密码还是用弹窗,因为涉及敏感操作
def showEvent(self, event):
"""显示页面时清空输入框"""
super().showEvent(event)
self.username_input.clear()
self.password_input.clear()
self.username_input.setFocus()
class ChangePasswordUI(QDialog): # 这个保持为 QDialog因为是敏感操作
def __init__(self, parent=None):
super().__init__(parent)
self.parent_window = parent
self.user_system = parent.user_system if parent else None
self.setup_ui()
def setup_ui(self):
self.setWindowTitle("🔑 修改密码 - 数学冒险岛 🔑")
self.setMinimumSize(450, 550)
# 设置可爱的渐变背景
self.setStyleSheet("""
QDialog {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(20, 20, 20, 20)
main_layout.setSpacing(0)
# 卡片容器 - 自适应尺寸
card = QFrame()
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(card)
# 卡片布局
card_layout = QVBoxLayout(card)
card_layout.setContentsMargins(30, 25, 30, 25)
card_layout.setSpacing(0)
# 顶部弹性空间
card_layout.addStretch(1)
# 标题区域
title_frame = QFrame()
title_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(8)
# 装饰性emoji
emoji_label = QLabel("🔑✨🛡️")
emoji_label.setStyleSheet("""
QLabel {
font: bold 18pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
emoji_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("修改密码")
title_label.setStyleSheet("""
QLabel {
font: bold 22pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(title_label)
subtitle_label = QLabel("🔒 保护你的冒险账户安全 🔒")
subtitle_label.setStyleSheet("""
QLabel {
font: 12pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
subtitle_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_layout.addWidget(subtitle_label)
card_layout.addWidget(title_frame)
card_layout.addSpacing(30)
# 输入区域
input_frame = QFrame()
input_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
input_frame.setStyleSheet("background: transparent; border: none;")
input_layout = QVBoxLayout(input_frame)
input_layout.setSpacing(20)
# 原密码
old_pwd_layout = QVBoxLayout()
old_pwd_layout.setSpacing(5)
old_pwd_label = QLabel("🔓 原密码:")
old_pwd_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
old_pwd_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
old_pwd_layout.addWidget(old_pwd_label)
self.old_pwd_input = QLineEdit()
self.old_pwd_input.setMinimumHeight(38)
self.old_pwd_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.old_pwd_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
""")
self.old_pwd_input.setEchoMode(QLineEdit.Password)
self.old_pwd_input.setPlaceholderText("请输入原密码...")
old_pwd_layout.addWidget(self.old_pwd_input)
input_layout.addLayout(old_pwd_layout)
# 新密码
new_pwd_layout = QVBoxLayout()
new_pwd_layout.setSpacing(5)
new_pwd_label = QLabel("🆕 新密码:")
new_pwd_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
new_pwd_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
new_pwd_layout.addWidget(new_pwd_label)
self.new_pwd_input = QLineEdit()
self.new_pwd_input.setMinimumHeight(38)
self.new_pwd_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.new_pwd_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
""")
self.new_pwd_input.setEchoMode(QLineEdit.Password)
self.new_pwd_input.setPlaceholderText("请输入新密码...")
new_pwd_layout.addWidget(self.new_pwd_input)
input_layout.addLayout(new_pwd_layout)
# 确认新密码
confirm_pwd_layout = QVBoxLayout()
confirm_pwd_layout.setSpacing(5)
confirm_pwd_label = QLabel("✅ 确认新密码:")
confirm_pwd_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
confirm_pwd_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
confirm_pwd_layout.addWidget(confirm_pwd_label)
self.confirm_pwd_input = QLineEdit()
self.confirm_pwd_input.setMinimumHeight(38)
self.confirm_pwd_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.confirm_pwd_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
""")
self.confirm_pwd_input.setEchoMode(QLineEdit.Password)
self.confirm_pwd_input.setPlaceholderText("请再次输入新密码...")
confirm_pwd_layout.addWidget(self.confirm_pwd_input)
input_layout.addLayout(confirm_pwd_layout)
card_layout.addWidget(input_frame)
card_layout.addSpacing(15)
# 密码提示
hint_label = QLabel("📝 密码要求6-10位必须包含大小写字母和数字")
hint_label.setStyleSheet("""
QLabel {
font: 9pt '微软雅黑';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
hint_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
card_layout.addWidget(hint_label)
card_layout.addSpacing(25)
# 确认按钮
button_frame = QFrame()
button_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QVBoxLayout(button_frame)
self.confirm_btn = QPushButton("✨ 确认修改")
self.confirm_btn.setMinimumHeight(45)
self.confirm_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.confirm_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B5EAD7, stop:1 #8CD9B3);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 20px;
border: 2px solid #A0E7E5;
max-width: 300px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8CD9B3, stop:1 #6CD6D3);
border: 2px solid #8CD9B3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #6CD6D3, stop:1 #5AC7C4);
}
""")
self.confirm_btn.clicked.connect(self.change_password)
button_layout.addWidget(self.confirm_btn, alignment=Qt.AlignCenter)
card_layout.addWidget(button_frame)
card_layout.addStretch(2)
# 装饰性底部
decoration_label = QLabel("🔐🌟🛡️ 账户安全最重要 🌈✨🎯")
decoration_label.setStyleSheet("""
QLabel {
font: bold 10pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
decoration_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
card_layout.addWidget(decoration_label)
# 绑定回车键
self.old_pwd_input.returnPressed.connect(self.change_password)
self.new_pwd_input.returnPressed.connect(self.change_password)
self.confirm_pwd_input.returnPressed.connect(self.change_password)
# 设置焦点
self.old_pwd_input.setFocus()
def change_password(self):
old_password = self.old_pwd_input.text()
new_password = self.new_pwd_input.text()
confirm_password = self.confirm_pwd_input.text()
if not old_password or not new_password or not confirm_password:
QMessageBox.warning(self, "⚠️ 提示", "请填写完整信息")
return
if new_password != confirm_password:
QMessageBox.warning(self, "⚠️ 提示", "两次输入的新密码不一致")
self.new_pwd_input.clear()
self.confirm_pwd_input.clear()
self.new_pwd_input.setFocus()
return
# 检查是否已登录
if not self.user_system.current_user:
QMessageBox.warning(self, "⚠️ 提示", "请先登录后再修改密码")
self.close()
return
if self.user_system.change_password(old_password, new_password):
QMessageBox.information(self, "🎉 修改成功", "密码修改成功!")
self.accept()
else:
QMessageBox.warning(self, "❌ 修改失败", "原密码错误或新密码不符合要求")
self.old_pwd_input.clear()
self.new_pwd_input.clear()
self.confirm_pwd_input.clear()
self.old_pwd_input.setFocus()

@ -0,0 +1,764 @@
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QLabel, QPushButton, QLineEdit,
QMessageBox, QFrame, QGridLayout, QSizePolicy, QStackedWidget)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QPalette, QColor
# 导入各个页面需要先修改这些类继承QWidget
from .login_ui import LoginPage
from .register_ui import RegisterPage
from .question_ui import QuestionPage
from .result_ui import ResultPage
class MainWindow(QMainWindow):
def __init__(self,user_system):
super().__init__()
self.user_system = user_system
self.menu_bar = None
self.current_level = None
self.question_count = None
# 创建堆叠窗口
self.stacked_widget = QStackedWidget()
self.init_ui()
def init_ui(self):
"""初始化主窗口界面"""
self.setWindowTitle("🎮 数学冒险岛 🎮")
# self.setMinimumSize(900, 650)
# 设置固定大小(例如 900×650
# self.setFixedSize(900, 1200)
# 获取字体高度来设置相对大小
font_metrics = self.fontMetrics()
char_height = font_metrics.height()
# 基于字符高度设置尺寸
self.setFixedSize(40 * char_height, 55 * char_height)
# 设置可爱的渐变背景色
palette = self.palette()
palette.setColor(QPalette.Window, QColor(255, 240, 245))
self.setPalette(palette)
# 设置中央部件为堆叠窗口
self.setCentralWidget(self.stacked_widget)
# 初始化各个页面
self.init_pages()
# 显示主页面
self.show_main_page()
def init_pages(self):
"""初始化所有页面"""
# 主页面
self.main_page = self.create_main_page()
self.stacked_widget.addWidget(self.main_page)
# 登录页面
self.login_page = LoginPage(self)
self.stacked_widget.addWidget(self.login_page)
# 注册页面
self.register_page = RegisterPage(self)
self.stacked_widget.addWidget(self.register_page)
# 学段选择页面
self.level_page = self.create_level_page()
self.stacked_widget.addWidget(self.level_page)
# 题目数量页面
self.count_page = self.create_count_page()
self.stacked_widget.addWidget(self.count_page)
def show_main_page(self):
"""显示主页面"""
self.stacked_widget.setCurrentWidget(self.main_page)
self.clear_menu_bar()
def show_login_page(self):
"""显示登录页面"""
self.stacked_widget.setCurrentWidget(self.login_page)
self.clear_menu_bar()
def show_register_page(self):
"""显示注册页面"""
self.stacked_widget.setCurrentWidget(self.register_page)
self.clear_menu_bar()
def show_level_page(self):
"""显示学段选择页面"""
if not self.user_system or not self.user_system.current_user:
QMessageBox.warning(self, "提示", "请先登录")
return
self.stacked_widget.setCurrentWidget(self.level_page)
self.create_user_menu()
def show_count_page(self):
"""显示题目数量输入页面"""
if not self.user_system or not self.user_system.current_user:
QMessageBox.warning(self, "提示", "请先登录")
return
self.update_count_page(self.current_level)
self.stacked_widget.setCurrentWidget(self.count_page)
def show_question_page(self, level: str, count: int):
try:
# ✅ 每次创建新页面前,清理旧的 QuestionPage如果有
for i in reversed(range(self.stacked_widget.count())):
widget = self.stacked_widget.widget(i)
if isinstance(widget, QuestionPage):
self.stacked_widget.removeWidget(widget)
widget.deleteLater() # 释放内存
# ✅ 再创建新页面
question_page = QuestionPage(self, level, count)
self.stacked_widget.addWidget(question_page)
self.stacked_widget.setCurrentWidget(question_page)
except Exception as e:
QMessageBox.critical(self, "❌ 程序错误", f"生成题目时发生错误:\n{str(e)}")
print(f"[ERROR] 题目生成失败: {e}")
try:
question_page = QuestionPage(self, level, count)
self.stacked_widget.addWidget(question_page)
self.stacked_widget.setCurrentWidget(question_page)
except Exception as e:
QMessageBox.critical(self, "❌ 程序错误", f"生成题目时发生错误:\n{str(e)}")
print(f"[ERROR] 题目生成失败: {e}")
def show_result_page(self, score: int, level: str, count: int):
"""显示结果页面"""
result_page = ResultPage(self, score, level, count)
self.stacked_widget.addWidget(result_page)
self.stacked_widget.setCurrentWidget(result_page)
def remove_current_page(self):
"""移除当前页面(用于答题和结果页面)"""
current_index = self.stacked_widget.currentIndex()
# 只移除动态添加的页面(索引大于固定页面数量)
if current_index >= 5: # 主页面、登录、注册、学段、题目数量
current_widget = self.stacked_widget.currentWidget()
self.stacked_widget.removeWidget(current_widget)
def create_main_page(self):
"""创建主页面"""
widget = QWidget()
# 主布局 - 使用弹性布局
main_layout = QVBoxLayout(widget)
main_layout.setContentsMargins(30, 20, 30, 20)
main_layout.setSpacing(0)
# 主容器框架 - 自适应尺寸
container = QFrame()
container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
container.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(container)
# 容器布局 - 使用弹性布局
container_layout = QVBoxLayout(container)
container_layout.setContentsMargins(40, 30, 40, 30)
container_layout.setSpacing(0)
# 顶部弹性空间
container_layout.addStretch(1)
# --- 标题区域 ---
title_frame = QFrame()
title_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(10)
# 装饰性emoji
emoji_label = QLabel("✨🎓🧮🌟")
emoji_label.setStyleSheet("""
QLabel {
font: bold 20pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("数学冒险岛")
title_label.setStyleSheet("""
QLabel {
font: bold 28pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(title_label)
# 副标题
subtitle_label = QLabel("🚀 开启你的数学冒险之旅! 🚀")
subtitle_label.setStyleSheet("""
QLabel {
font: 14pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(subtitle_label)
container_layout.addWidget(title_frame)
container_layout.addSpacing(40)
# --- 按钮区域 ---
button_frame = QFrame()
button_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QVBoxLayout(button_frame)
button_layout.setSpacing(20)
# 登录按钮
login_btn = QPushButton("🎮 开始冒险")
login_btn.setMinimumSize(250, 60)
login_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
login_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9EBC, stop:1 #FF6B9C);
color: white;
font: bold 16pt '微软雅黑';
border-radius: 30px;
border: 3px solid #FF85A1;
max-width: 300px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF85A1, stop:1 #FF5784);
border: 3px solid #FF6B9C;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF5784, stop:1 #FF3D6D);
}
""")
login_btn.clicked.connect(self.show_login_page) # 改为页面切换
button_layout.addWidget(login_btn, alignment=Qt.AlignCenter)
# 注册按钮
register_btn = QPushButton("📝 注册账号")
register_btn.setMinimumSize(250, 60)
register_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
register_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
font: bold 16pt '微软雅黑';
border-radius: 30px;
border: 3px solid #8ADBD9;
max-width: 300px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border: 3px solid #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
""")
register_btn.clicked.connect(self.show_register_page) # 改为页面切换
button_layout.addWidget(register_btn, alignment=Qt.AlignCenter)
container_layout.addWidget(button_frame)
container_layout.addStretch(2)
# --- 装饰性元素 ---
decoration_frame = QFrame()
decoration_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
decoration_frame.setStyleSheet("background: transparent; border: none;")
decoration_layout = QHBoxLayout(decoration_frame)
math_symbols = QLabel("🔢 ✖️ ➗ 📐 📊 🧮")
math_symbols.setStyleSheet("""
QLabel {
font: bold 16pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
decoration_layout.addWidget(math_symbols)
container_layout.addWidget(decoration_frame)
container_layout.addSpacing(20)
# --- 底部信息 ---
footer_frame = QFrame()
footer_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
footer_frame.setStyleSheet("background: transparent; border: none;")
footer_layout = QHBoxLayout(footer_frame)
footer_label = QLabel("🌈 版权所有 © 2025 数学冒险岛 🌈")
footer_label.setStyleSheet("""
QLabel {
font: 10pt '微软雅黑';
color: #888888;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
footer_layout.addWidget(footer_label)
container_layout.addWidget(footer_frame)
return widget
def create_level_page(self):
"""创建学段选择页面"""
widget = QWidget()
# 主布局
main_layout = QVBoxLayout(widget)
main_layout.setContentsMargins(30, 20, 30, 20)
main_layout.setSpacing(0)
# 主容器
frame = QFrame()
frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
frame.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(frame)
frame_layout = QVBoxLayout(frame)
frame_layout.setContentsMargins(40, 30, 40, 30)
frame_layout.setSpacing(0)
# 顶部空间
frame_layout.addStretch(1)
# 欢迎信息
welcome_text = f"🎉 欢迎回来! 🎉"
self.welcome_label = QLabel(welcome_text)
self.welcome_label.setStyleSheet("""
QLabel {
font: bold 18pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
self.welcome_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
frame_layout.addWidget(self.welcome_label)
frame_layout.addSpacing(40)
# 学段选择标题
select_label = QLabel("🎯 选择你的冒险地图 🎯")
select_label.setStyleSheet("""
QLabel {
font: bold 20pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
select_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
frame_layout.addWidget(select_label)
frame_layout.addSpacing(40)
# 按钮区域
btn_frame = QFrame()
btn_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
btn_frame.setStyleSheet("background: transparent; border: none;")
btn_layout = QGridLayout(btn_frame)
btn_layout.setSpacing(20)
btn_layout.setVerticalSpacing(25)
levels = [("🏫 小学乐园", "primary"), ("🏰 初中城堡", "middle"), ("🚀 高中太空", "high")]
colors = [
("#FF9EBC", "#FF6B9C"), # 粉色
("#A0E7E5", "#6CD6D3"), # 青色
("#B5EAD7", "#8CD9B3") # 绿色
]
for i, (text, level) in enumerate(levels):
color_pair = colors[i % len(colors)]
btn = QPushButton(text)
btn.setMinimumSize(280, 70)
btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
btn.setStyleSheet(f"""
QPushButton {{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 {color_pair[0]}, stop:1 {color_pair[1]});
color: white;
font: bold 18pt '微软雅黑';
border-radius: 35px;
border: 3px solid {color_pair[0]};
max-width: 320px;
}}
QPushButton:hover {{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 {color_pair[1]}, stop:1 {color_pair[0]});
}}
QPushButton:pressed {{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #555555, stop:1 {color_pair[1]});
}}
""")
btn.clicked.connect(lambda checked, l=level: self.on_level_selected(l))
btn_layout.addWidget(btn, i, 0, alignment=Qt.AlignCenter)
frame_layout.addWidget(btn_frame)
frame_layout.addStretch(1)
# 功能按钮区域
func_frame = QFrame()
func_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
func_frame.setStyleSheet("background: transparent; border: none;")
func_layout = QHBoxLayout(func_frame)
func_layout.setSpacing(20)
# 修改密码按钮
change_pwd_btn = QPushButton("🔑 修改密码")
change_pwd_btn.setMinimumSize(180, 50)
change_pwd_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
change_pwd_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFDAC1, stop:1 #FFB347);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #FFB347;
max-width: 200px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFB347, stop:1 #FF9800);
}
""")
change_pwd_btn.clicked.connect(self.open_change_password)
func_layout.addWidget(change_pwd_btn)
# 返回上级按钮
back_btn = QPushButton("🔙 返回主页")
back_btn.setMinimumSize(180, 50)
back_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
back_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #C7CEEA, stop:1 #9FA8DA);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #9FA8DA;
max-width: 200px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #9FA8DA, stop:1 #7986CB);
}
""")
back_btn.clicked.connect(self.show_main_page) # 改为页面切换
func_layout.addWidget(back_btn)
frame_layout.addWidget(func_frame, alignment=Qt.AlignCenter)
frame_layout.addStretch(1)
return widget
def create_count_page(self):
"""创建题目数量页面"""
widget = QWidget()
# 主布局
main_layout = QVBoxLayout(widget)
main_layout.setContentsMargins(30, 20, 30, 20)
main_layout.setSpacing(0)
# 主容器
frame = QFrame()
frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
frame.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(frame)
frame_layout = QVBoxLayout(frame)
frame_layout.setContentsMargins(40, 30, 40, 30)
frame_layout.setSpacing(0)
# 顶部空间
frame_layout.addStretch(1)
# 显示当前学段
self.level_label = QLabel()
self.level_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.level_label.setStyleSheet("""
QLabel {
font: bold 16pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
frame_layout.addWidget(self.level_label)
frame_layout.addSpacing(30)
# 输入提示
count_label = QLabel("🎯 请输入题目数量10-30")
count_label.setStyleSheet("""
QLabel {
font: bold 18pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
count_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
frame_layout.addWidget(count_label)
# 装饰性emoji
emoji_label = QLabel("🔢 ✨ 📚 💫")
emoji_label.setStyleSheet("""
QLabel {
font: bold 16pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
emoji_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
frame_layout.addWidget(emoji_label)
frame_layout.addSpacing(30)
# 输入框
self.count_input = QLineEdit()
self.count_input.setFont(QFont("微软雅黑", 14))
self.count_input.setMinimumSize(200, 50)
self.count_input.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.count_input.setAlignment(Qt.AlignCenter)
self.count_input.setStyleSheet("""
QLineEdit {
background: white;
border: 3px solid #FF9EBC;
border-radius: 20px;
font: bold 14pt '微软雅黑';
color: #FF6B9C;
padding: 5px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 3px solid #FF6B9C;
background: #FFF9FA;
}
""")
frame_layout.addWidget(self.count_input, alignment=Qt.AlignCenter)
frame_layout.addSpacing(40)
# 按钮区域
btn_frame = QFrame()
btn_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
btn_frame.setStyleSheet("background: transparent; border: none;")
btn_layout = QHBoxLayout(btn_frame)
btn_layout.setSpacing(30)
# 开始答题按钮
start_btn = QPushButton("🚀 开始冒险")
start_btn.setMinimumSize(210, 60)
start_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
start_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9EBC, stop:1 #FF6B9C);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 30px;
border: 3px solid #FF85A1;
max-width: 220px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF85A1, stop:1 #FF5784);
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF5784, stop:1 #FF3D6D);
}
""")
start_btn.clicked.connect(self.start_question)
btn_layout.addWidget(start_btn)
# 返回按钮
back_btn = QPushButton("🔙 返回选择")
back_btn.setMinimumSize(210, 60)
back_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
back_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #C7CEEA, stop:1 #9FA8DA);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 30px;
border: 3px solid #9FA8DA;
max-width: 220px;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #9FA8DA, stop:1 #7986CB);
}
""")
back_btn.clicked.connect(self.show_level_page) # 改为页面切换
btn_layout.addWidget(back_btn)
frame_layout.addWidget(btn_frame, alignment=Qt.AlignCenter)
frame_layout.addStretch(2)
return widget
def update_level_page(self):
"""更新学段选择页面的欢迎信息"""
if self.user_system and self.user_system.current_user:
welcome_text = f"🎉 欢迎回来,{self.user_system.current_user} 🎉"
self.welcome_label.setText(welcome_text)
def update_count_page(self, level: str):
"""更新题目数量页面的学段信息"""
level_text = {"primary": "🏫 小学乐园", "middle": "🏰 初中城堡", "high": "🚀 高中太空"}.get(level, level)
self.level_label.setText(f"🗺️ 当前地图:{level_text}")
self.count_input.clear()
self.count_input.setFocus()
# 修改原有方法
def open_login(self):
"""打开登录界面 - 改为页面切换"""
self.show_login_page()
def open_register(self):
"""打开注册界面 - 改为页面切换"""
self.show_register_page()
def on_level_selected(self, level: str):
"""学段选择后进入题目数量输入"""
if self.user_system:
self.user_system.set_level(level)
self.current_level = level
self.update_count_page(level)
self.show_count_page()
def start_question(self):
"""开始答题"""
try:
count = int(self.count_input.text())
if 10 <= count <= 30:
self.question_count = count
self.show_question_page(self.current_level, count)
else:
QMessageBox.warning(self, "⚠️ 提示", "请输入10-30之间的数字哦")
except ValueError:
QMessageBox.warning(self, "⚠️ 提示", "请输入有效的数字!")
# 其他方法保持不变...
def create_user_menu(self):
"""创建用户菜单栏"""
if self.menu_bar:
self.menu_bar.clear()
else:
self.menu_bar = self.menuBar()
self.menu_bar.setStyleSheet("""
QMenuBar {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
color: #FF6B9C;
font: bold 12pt '微软雅黑';
border-bottom: 2px solid #FF9EBC;
}
QMenuBar::item {
background: transparent;
padding: 5px 10px;
}
QMenuBar::item:selected {
background: #FF9EBC;
border-radius: 10px;
}
""")
# 用户菜单
user_menu = self.menu_bar.addMenu(f"🎮 欢迎(点这里哦),{self.user_system.current_user}")
user_menu.setStyleSheet("""
QMenu {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
}
QMenu::item {
padding: 8px 20px;
font: 11pt '微软雅黑';
}
QMenu::item:selected {
background: #FFE4EC;
border-radius: 10px;
}
""")
user_menu.addAction("🔑 修改密码", self.open_change_password)
user_menu.addSeparator()
user_menu.addAction("🚪 退出登录", self.logout)
def open_change_password(self):
"""打开修改密码界面"""
if self.user_system and self.user_system.current_user:
from .login_ui import ChangePasswordUI
change_password_ui = ChangePasswordUI(self)
change_password_ui.exec_() # 这个还是弹窗,因为涉及敏感操作
else:
QMessageBox.warning(self, "提示", "请先登录")
def logout(self):
"""退出登录"""
if self.user_system:
self.user_system.current_user = None
self.user_system.current_level = None
QMessageBox.information(self, "🎮 再见", "期待下次与你一起冒险!")
self.show_main_page()
def clear_menu_bar(self):
"""清空菜单栏"""
if self.menu_bar:
self.menu_bar.clear()
self.menu_bar = None
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = MainWindow()
window.show()
sys.exit(app.exec_())

@ -0,0 +1,455 @@
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QMessageBox, QFrame, QRadioButton,
QButtonGroup, QScrollArea, QWidget, QProgressBar, QSizePolicy)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from .result_ui import ResultPage
from core.question_bank import QuestionBank
class QuestionPage(QWidget): # 改为继承 QWidget
def __init__(self, parent, level: str, count: int):
super().__init__(parent)
try:
self.parent_window = parent
self.level = level
self.count = count
self.current_idx = 0
self.answers = [None] * count
self.question_bank = QuestionBank()
self.paper = self.question_bank.generate_paper(level, count)
self.setup_ui()
self.show_question()
except Exception as e:
print(f"[ERROR] QuestionPage 初始化失败: {e}")
raise e # 重新抛出,供上层捕获
def setup_ui(self):
"""初始化界面"""
# 移除 setWindowTitle 和 setMinimumSize使用父窗口的尺寸
# 设置可爱的渐变背景
self.setStyleSheet("""
QWidget {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(25, 20, 25, 20)
main_layout.setSpacing(0)
# 顶部信息区域
top_frame = QFrame()
top_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
top_frame.setStyleSheet("""
QFrame {
background: transparent;
border: none;
}
""")
top_layout = QVBoxLayout(top_frame)
top_layout.setSpacing(15)
# 标题
title_label = QLabel("🧮 数学冒险岛 - 答题挑战 🧮")
title_label.setStyleSheet("""
QLabel {
font: bold 24pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
top_layout.addWidget(title_label)
# 进度显示
self.progress_label = QLabel()
self.progress_label.setStyleSheet("""
QLabel {
font: bold 16pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
self.progress_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
top_layout.addWidget(self.progress_label)
# 进度条
self.progress_bar = QProgressBar()
self.progress_bar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.progress_bar.setFixedHeight(25)
self.progress_bar.setStyleSheet("""
QProgressBar {
border: 3px solid #FF9EBC;
border-radius: 12px;
background-color: white;
text-align: center;
font: bold 12pt '微软雅黑';
color: #FF6B9C;
}
QProgressBar::chunk {
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 #FF9EBC, stop:0.5 #FF6B9C, stop:1 #FF3D6D);
border-radius: 8px;
}
""")
top_layout.addWidget(self.progress_bar)
main_layout.addWidget(top_frame)
main_layout.addSpacing(20)
# 题目内容框架(可滚动)
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
scroll_area.setStyleSheet("""
QScrollArea {
border: none;
background: transparent;
}
QScrollBar:vertical {
background: white;
width: 15px;
margin: 0px;
}
QScrollBar::handle:vertical {
background: #FF9EBC;
border-radius: 7px;
min-height: 20px;
}
QScrollBar::handle:vertical:hover {
background: #FF6B9C;
}
""")
main_layout.addWidget(scroll_area)
# 滚动区域的内容部件
scroll_content = QWidget()
scroll_area.setWidget(scroll_content)
content_layout = QVBoxLayout(scroll_content)
content_layout.setContentsMargins(0, 0, 0, 0)
# 题目卡片
question_card = QFrame()
question_card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
question_layout = QVBoxLayout(question_card)
question_layout.setContentsMargins(30, 25, 30, 25)
question_layout.setSpacing(20)
# 题干
self.question_label = QLabel()
self.question_label.setStyleSheet("""
QLabel {
font: bold 18pt '微软雅黑';
color: #5A5A5A;
background: transparent;
line-height: 1.5;
}
""")
self.question_label.setWordWrap(True)
self.question_label.setAlignment(Qt.AlignLeft | Qt.AlignTop)
question_layout.addWidget(self.question_label)
# 选项框架
self.options_frame = QFrame()
self.options_frame.setStyleSheet("""
QFrame {
background: transparent;
border: none;
}
""")
self.options_layout = QVBoxLayout(self.options_frame)
self.options_layout.setSpacing(12)
question_layout.addWidget(self.options_frame)
content_layout.addWidget(question_card)
main_layout.addSpacing(20)
# 底部按钮框架
button_frame = QFrame()
button_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QHBoxLayout(button_frame)
button_layout.setSpacing(20)
# 上一题按钮
self.prev_btn = QPushButton("⬅️ 上一题")
self.prev_btn.setMinimumSize(120, 50)
self.prev_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.prev_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #C7CEEA, stop:1 #9FA8DA);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #9FA8DA;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #9FA8DA, stop:1 #7986CB);
border: 3px solid #7986CB;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #7986CB, stop:1 #5C6BC0);
}
QPushButton:disabled {
background: #E0E0E0;
color: #9E9E9E;
border: 3px solid #CCCCCC;
}
""")
self.prev_btn.clicked.connect(self.prev_question)
button_layout.addWidget(self.prev_btn)
button_layout.addStretch(1)
# 下一题按钮
self.next_btn = QPushButton("下一题 ➡️")
self.next_btn.setMinimumSize(120, 50)
self.next_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.next_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #8ADBD9;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border: 3px solid #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
""")
self.next_btn.clicked.connect(self.next_question)
button_layout.addWidget(self.next_btn)
button_layout.addStretch(1)
# 提交按钮
self.submit_btn = QPushButton("🎯 提交试卷")
self.submit_btn.setMinimumSize(140, 50)
self.submit_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.submit_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9EBC, stop:1 #FF6B9C);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #FF85A1;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF85A1, stop:1 #FF5784);
border: 3px solid #FF6B9C;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF5784, stop:1 #FF3D6D);
}
""")
self.submit_btn.clicked.connect(self.submit_paper)
button_layout.addWidget(self.submit_btn)
main_layout.addWidget(button_frame)
# 选项按钮组
self.option_group = QButtonGroup(self)
self.option_group.buttonClicked.connect(self.on_option_selected)
def show_question(self):
"""显示当前题目"""
if self.current_idx >= len(self.paper):
return
question = self.paper[self.current_idx]
# 更新进度
progress_text = f"📊 第 {self.current_idx + 1} 题 / 共 {self.count}"
self.progress_label.setText(progress_text)
# 更新进度条
progress_percent = int((self.current_idx + 1) / self.count * 100)
self.progress_bar.setValue(progress_percent)
self.progress_bar.setFormat(f"🚀 进度: {progress_percent}%")
# 显示题干
self.question_label.setText(question.content)
# 清空选项框架
for i in reversed(range(self.options_layout.count())):
widget = self.options_layout.itemAt(i).widget()
if widget:
widget.deleteLater()
# 移除所有按钮
self.option_group = QButtonGroup(self)
self.option_group.buttonClicked.connect(self.on_option_selected)
# 创建选项按钮
option_labels = ["A", "B", "C", "D"]
option_emojis = ["🔸", "🔹", "🔸", "🔹"]
for i, option_text in enumerate(question.options):
# 选项卡片
option_card = QFrame()
option_card.setStyleSheet("""
QFrame {
background: white;
border: 2px solid #FFD1DC;
border-radius: 15px;
}
QFrame:hover {
background: #FFF9FA;
border: 2px solid #FF9EBC;
}
""")
option_card.setFixedHeight(60)
option_layout = QHBoxLayout(option_card)
option_layout.setContentsMargins(20, 10, 20, 10)
# 单选按钮
radio_btn = QRadioButton(f"{option_emojis[i]} {option_labels[i]}. {option_text}")
radio_btn.setStyleSheet("""
QRadioButton {
font: 16pt '微软雅黑';
color: #5A5A5A;
background: transparent;
spacing: 15px;
}
QRadioButton::indicator {
width: 24px;
height: 24px;
}
QRadioButton::indicator:unchecked {
border: 3px solid #FF9EBC;
border-radius: 12px;
background-color: white;
}
QRadioButton::indicator:checked {
border: 3px solid #FF6B9C;
border-radius: 12px;
background-color: #FF6B9C;
}
QRadioButton:hover {
color: #FF6B9C;
}
""")
self.option_group.addButton(radio_btn, i)
option_layout.addWidget(radio_btn)
option_layout.addStretch(1)
self.options_layout.addWidget(option_card)
# 恢复已选答案
if self.answers[self.current_idx] is not None:
button = self.option_group.button(self.answers[self.current_idx])
if button:
button.setChecked(True)
# 更新按钮状态
self.update_button_states()
def on_option_selected(self, button):
"""选项被选择时的处理"""
self.save_current_answer()
def update_button_states(self):
"""更新按钮状态"""
# 上一题按钮
self.prev_btn.setEnabled(self.current_idx > 0)
# 下一题按钮
if self.current_idx == self.count - 1:
self.next_btn.setText("最后一题 🏁")
else:
self.next_btn.setText("下一题 ➡️")
def save_current_answer(self):
"""保存当前题目的答案"""
selected_button = self.option_group.checkedButton()
if selected_button:
self.answers[self.current_idx] = self.option_group.id(selected_button)
def prev_question(self):
"""上一题"""
self.save_current_answer()
if self.current_idx > 0:
self.current_idx -= 1
self.show_question()
def next_question(self):
"""下一题"""
self.save_current_answer()
if self.current_idx < self.count - 1:
self.current_idx += 1
self.show_question()
else:
# 如果是最后一题,提示提交
QMessageBox.information(self, "🎉 完成", "太棒了!你已经完成了所有题目,请提交试卷查看成绩!")
def submit_paper(self):
"""提交试卷"""
self.save_current_answer()
# 检查是否所有题目都已作答
unanswered = [i+1 for i, answer in enumerate(self.answers) if answer is None]
if unanswered:
reply = QMessageBox.question(
self,
"🤔 确认提交",
f"还有 {len(unanswered)} 题未作答(题号:{unanswered}),确定要提交吗?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply != QMessageBox.Yes:
return
# 计算得分
correct_answers = []
for i, question in enumerate(self.paper):
selected_index = self.answers[i]
if selected_index is not None:
selected_answer = question.options[selected_index]
is_correct = (selected_answer == question.answer)
correct_answers.append(is_correct)
else:
correct_answers.append(False)
score = self.question_bank.calculate_score(correct_answers)
# 显示结果页面
if self.parent_window:
self.parent_window.show_result_page(score, self.level, self.count)
def showEvent(self, event):
"""显示页面时重置状态"""
super().showEvent(event)
# 重置答题状态
self.current_idx = 0
self.answers = [None] * self.count
self.show_question()

@ -0,0 +1,589 @@
# 标准库
import sys
# 第三方库
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QMessageBox, QFrame, QGridLayout, QSizePolicy
)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont
class RegisterPage(QWidget): # 改为继承 QWidget
def __init__(self, parent=None):
super().__init__(parent)
self.parent_window = parent
self.user_system = parent.user_system if parent else None
self.countdown_active = False
self.countdown_seconds = 60
self.countdown_timer = QTimer()
self.countdown_timer.timeout.connect(self.update_countdown)
self.setup_ui()
def setup_ui(self):
"""初始化注册界面"""
# 移除 setWindowTitle 和 setMinimumSize使用父窗口的尺寸
# 设置可爱的渐变背景
self.setStyleSheet("""
QWidget {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(25, 20, 25, 20)
main_layout.setSpacing(0)
# 卡片容器
card = QFrame()
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(card)
# 卡片布局
card_layout = QVBoxLayout(card)
card_layout.setContentsMargins(35, 30, 35, 30)
card_layout.setSpacing(0)
# 顶部按钮栏
top_button_layout = QHBoxLayout()
top_button_layout.setAlignment(Qt.AlignLeft)
# 返回主页按钮
self.back_button = QPushButton("← 返回主页")
self.back_button.setMinimumSize(100, 35)
self.back_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.back_button.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B5EAD7, stop:1 #8CD9C7);
color: white;
font: bold 11pt '微软雅黑';
border-radius: 15px;
border: 2px solid #A0E7E5;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #7BCFBD);
border: 2px solid #8CD9C7;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #7BCFBD, stop:1 #6AC0AE);
}
""")
self.back_button.clicked.connect(self.go_back_to_main)
top_button_layout.addWidget(self.back_button)
top_button_layout.addStretch(1) # 将按钮推到左侧
card_layout.addLayout(top_button_layout)
card_layout.addSpacing(10)
# 顶部弹性空间
card_layout.addStretch(1)
# 标题区域
title_frame = QFrame()
title_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(10)
# 装饰性emoji
emoji_label = QLabel("🎉✨📝")
emoji_label.setStyleSheet("""
QLabel {
font: bold 20pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("用户注册")
title_label.setStyleSheet("""
QLabel {
font: bold 24pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(title_label)
subtitle_label = QLabel("🚀 加入数学冒险岛大家庭 🚀")
subtitle_label.setStyleSheet("""
QLabel {
font: 12pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(subtitle_label)
card_layout.addWidget(title_frame)
card_layout.addSpacing(30)
# 表单区域 - 使用垂直布局包装网格布局
form_container = QFrame()
form_container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
form_container.setStyleSheet("background: transparent; border: none;")
form_container_layout = QVBoxLayout(form_container)
# 网格布局
form_layout = QGridLayout()
form_layout.setVerticalSpacing(15) # 减少垂直间距
form_layout.setHorizontalSpacing(15)
form_layout.setColumnStretch(1, 1)
# 用户名输入
username_label = QLabel("👤 用户名:")
username_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
form_layout.addWidget(username_label, 0, 0, Qt.AlignLeft)
self.username_input = QLineEdit()
self.username_input.setMinimumHeight(40)
self.username_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.username_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.username_input.setPlaceholderText("请输入用户名...")
form_layout.addWidget(self.username_input, 0, 1)
# 用户名提示
username_hint = QLabel("📝 用户名要求2-10位中文、字母或数字")
username_hint.setStyleSheet("""
QLabel {
font: 9pt '微软雅黑';
color: #FF9EBC;
background: transparent;
}
""")
form_layout.addWidget(username_hint, 1, 1, Qt.AlignLeft)
# 添加间距行
form_layout.addWidget(QLabel(""), 2, 0, 1, 2) # 空行作为间距
# 邮箱输入
email_label = QLabel("📧 邮箱:")
email_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
form_layout.addWidget(email_label, 3, 0, Qt.AlignLeft)
self.email_input = QLineEdit()
self.email_input.setMinimumHeight(40)
self.email_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.email_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.email_input.setPlaceholderText("请输入邮箱...")
form_layout.addWidget(self.email_input, 3, 1)
# 添加间距行
form_layout.addWidget(QLabel(""), 4, 0, 1, 2) # 空行作为间距
# 注册码
code_label = QLabel("🔐 注册码:")
code_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
form_layout.addWidget(code_label, 5, 0, Qt.AlignLeft)
code_input_layout = QHBoxLayout()
code_input_layout.setSpacing(10)
self.code_input = QLineEdit()
self.code_input.setMinimumHeight(55)
self.code_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.code_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.code_input.setPlaceholderText("请输入注册码...")
code_input_layout.addWidget(self.code_input)
self.code_btn = QPushButton("获取注册码")
self.code_btn.setMinimumSize(120, 40)
self.code_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.code_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
font: bold 11pt '微软雅黑';
border-radius: 15px;
border: 2px solid #8ADBD9;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border: 2px solid #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
QPushButton:disabled {
background: #E0E0E0;
color: #9E9E9E;
border: 2px solid #CCCCCC;
}
""")
self.code_btn.clicked.connect(self.send_code)
code_input_layout.addWidget(self.code_btn)
form_layout.addLayout(code_input_layout, 5, 1)
# 添加间距行
form_layout.addWidget(QLabel(""), 6, 0, 1, 2) # 空行作为间距
# 密码
pwd_label = QLabel("🔒 密码:")
pwd_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
form_layout.addWidget(pwd_label, 7, 0, Qt.AlignLeft)
self.pwd_input = QLineEdit()
self.pwd_input.setMinimumHeight(40)
self.pwd_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.pwd_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.pwd_input.setEchoMode(QLineEdit.Password)
self.pwd_input.setPlaceholderText("请输入密码...")
form_layout.addWidget(self.pwd_input, 7, 1)
# 密码提示
pwd_hint = QLabel("📝 密码要求6-10位必须包含大小写字母和数字")
pwd_hint.setStyleSheet("""
QLabel {
font: 9pt '微软雅黑';
color: #FF9EBC;
background: transparent;
}
""")
form_layout.addWidget(pwd_hint, 8, 1, Qt.AlignLeft)
# 添加间距行
form_layout.addWidget(QLabel(""), 9, 0, 1, 2) # 空行作为间距
# 确认密码
confirm_pwd_label = QLabel("✅ 确认密码:")
confirm_pwd_label.setStyleSheet("""
QLabel {
font: bold 12pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
form_layout.addWidget(confirm_pwd_label, 10, 0, Qt.AlignLeft)
self.confirm_pwd_input = QLineEdit()
self.confirm_pwd_input.setMinimumHeight(40)
self.confirm_pwd_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.confirm_pwd_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 15px;
font: 12pt '微软雅黑';
color: #FF6B9C;
padding: 8px 15px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 11pt '微软雅黑';
}
""")
self.confirm_pwd_input.setEchoMode(QLineEdit.Password)
self.confirm_pwd_input.setPlaceholderText("请再次输入密码...")
form_layout.addWidget(self.confirm_pwd_input, 10, 1)
form_container_layout.addLayout(form_layout)
form_container_layout.addStretch(1)
card_layout.addWidget(form_container)
card_layout.addStretch(1)
# 按钮布局
button_layout = QHBoxLayout()
button_layout.setSpacing(20)
button_layout.setAlignment(Qt.AlignCenter)
# 返回主页按钮(底部)
back_button_bottom = QPushButton("🔙 返回主页")
back_button_bottom.setMinimumSize(120, 45)
back_button_bottom.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
back_button_bottom.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #C9C9C9, stop:1 #A8A8A8);
color: white;
font: bold 12pt '微软雅黑';
border-radius: 20px;
border: 2px solid #B8B8B8;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B8B8B8, stop:1 #989898);
border: 2px solid #A8A8A8;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #989898, stop:1 #888888);
}
""")
back_button_bottom.clicked.connect(self.go_back_to_main)
button_layout.addWidget(back_button_bottom)
# 注册按钮
register_btn = QPushButton("🎉 立即注册")
register_btn.setMinimumSize(150, 50)
register_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
register_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9EBC, stop:1 #FF6B9C);
color: white;
font: bold 14pt '微软雅黑';
border-radius: 25px;
border: 3px solid #FF85A1;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF85A1, stop:1 #FF5784);
border: 3px solid #FF6B9C;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF5784, stop:1 #FF3D6D);
}
""")
register_btn.clicked.connect(self.do_register)
button_layout.addWidget(register_btn)
card_layout.addLayout(button_layout)
card_layout.addSpacing(10)
# 装饰性底部
decoration_label = QLabel("✨🌈🎮 开启你的数学冒险之旅 🌟📚🚀")
decoration_label.setStyleSheet("""
QLabel {
font: bold 10pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
card_layout.addWidget(decoration_label)
# 设置焦点
self.username_input.setFocus()
def go_back_to_main(self):
"""返回主页"""
if self.parent_window:
self.parent_window.show_main_page()
def send_code(self):
"""发送注册码"""
if self.countdown_active:
return
email = self.email_input.text().strip()
username = self.username_input.text().strip() or "用户"
if not email:
QMessageBox.warning(self, "⚠️ 提示", "请输入邮箱地址")
self.email_input.setFocus()
return
if not self.user_system.is_valid_email(email):
QMessageBox.warning(self, "⚠️ 提示", "请输入有效的邮箱地址")
self.email_input.setFocus()
return
if self.user_system.send_verification(email, username):
QMessageBox.information(self, "📧 发送成功", "注册码已发送到您的邮箱,请查收!")
self.start_countdown()
else:
QMessageBox.warning(self, "❌ 发送失败", "邮箱已被使用或发送失败,请重试")
def start_countdown(self):
"""注册码按钮倒计时"""
print("开始倒计时") # 调试信息
self.countdown_active = True
self.code_btn.setEnabled(False)
self.countdown_seconds = 60
self.countdown_timer.start(1000)
self.update_countdown()
def update_countdown(self):
"""更新倒计时显示"""
print(f"倒计时更新: {self.countdown_seconds}") # 调试信息
if self.countdown_seconds > 0:
self.code_btn.setText(f"重新发送({self.countdown_seconds}s)")
self.countdown_seconds -= 1
# 强制更新UI
self.code_btn.repaint()
else:
self.countdown_timer.stop()
self.code_btn.setText("获取注册码")
self.code_btn.setEnabled(True)
self.countdown_active = False
print("倒计时结束") # 调试信息
def do_register(self):
"""执行注册"""
username = self.username_input.text().strip()
email = self.email_input.text().strip()
code = self.code_input.text().strip()
pwd = self.pwd_input.text()
confirm_pwd = self.confirm_pwd_input.text()
if not username or not email or not code or not pwd or not confirm_pwd:
QMessageBox.warning(self, "⚠️ 提示", "请填写完整信息")
return
if pwd != confirm_pwd:
QMessageBox.warning(self, "⚠️ 提示", "两次输入的密码不一致")
self.pwd_input.clear()
self.confirm_pwd_input.clear()
self.pwd_input.setFocus()
return
if self.user_system.register(username, email, code, pwd):
QMessageBox.information(self, "🎉 注册成功",
"注册成功!现在可以使用用户名登录,开始你的数学冒险之旅!")
# 不再使用 self.accept(),而是通知父窗口切换页面
if self.parent_window:
self.parent_window.show_main_page() # 注册成功后回到主页面
else:
QMessageBox.warning(self, "❌ 注册失败",
"注册失败:注册码错误、用户名已存在或信息不符合要求")
def showEvent(self, event):
"""显示页面时清空输入框"""
super().showEvent(event)
self.username_input.clear()
self.email_input.clear()
self.code_input.clear()
self.pwd_input.clear()
self.confirm_pwd_input.clear()
self.username_input.setFocus()
# 重置倒计时
if self.countdown_timer.isActive():
self.countdown_timer.stop()
self.code_btn.setText("获取注册码")
self.code_btn.setEnabled(True)
self.countdown_active = False
def closeEvent(self, event):
"""关闭事件处理"""
if self.countdown_timer.isActive():
self.countdown_timer.stop()
event.accept()

@ -0,0 +1,296 @@
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QFrame, QMessageBox)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class ResultPage(QWidget): # 改为继承 QWidget
def __init__(self, parent, score: int, level: str, count: int):
super().__init__(parent)
self.parent_window = parent
self.level = level
self.count = count
self.score = score
self.setup_ui()
def setup_ui(self):
"""初始化界面"""
# 移除 setWindowTitle 和 setMinimumSize使用父窗口的尺寸
# 设置可爱的渐变背景
self.setStyleSheet("""
QWidget {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(30, 30, 30, 30)
main_layout.setSpacing(0)
# 卡片容器
card = QFrame()
card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 25px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(card)
# 卡片布局
card_layout = QVBoxLayout(card)
card_layout.setContentsMargins(40, 40, 40, 40)
card_layout.setSpacing(0)
# 顶部弹性空间
card_layout.addStretch(1)
# 标题区域
title_frame = QFrame()
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(15)
# 装饰性emoji
emoji_label = QLabel("🎊✨🏆")
emoji_label.setStyleSheet("""
QLabel {
font: bold 28pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("冒险完成!")
title_label.setStyleSheet("""
QLabel {
font: bold 32pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(title_label)
# 副标题
level_text = {"primary": "小学乐园", "middle": "初中城堡", "high": "高中太空"}.get(self.level, self.level)
subtitle_label = QLabel(f"🎯 你在 {level_text} 完成了 {self.count} 道题目 🎯")
subtitle_label.setStyleSheet("""
QLabel {
font: 16pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(subtitle_label)
card_layout.addWidget(title_frame)
card_layout.addSpacing(40)
# 得分区域
score_frame = QFrame()
score_frame.setStyleSheet("background: transparent; border: none;")
score_layout = QVBoxLayout(score_frame)
score_layout.setSpacing(10)
# 得分标题
score_title_label = QLabel("你的冒险得分")
score_title_label.setStyleSheet("""
QLabel {
font: bold 18pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
score_layout.addWidget(score_title_label)
# 得分显示 - 根据分数显示不同颜色和评价
if self.score >= 90:
score_color = "#FF6B9C"
score_emoji = "🎉"
evaluation = "太棒了!你是数学小天才!"
elif self.score >= 80:
score_color = "#FF9EBC"
score_emoji = "🌟"
evaluation = "优秀!继续加油!"
elif self.score >= 70:
score_color = "#A0E7E5"
score_emoji = "👍"
evaluation = "良好!表现不错!"
elif self.score >= 60:
score_color = "#B5EAD7"
score_emoji = "💪"
evaluation = "及格!还有进步空间!"
else:
score_color = "#C7CEEA"
score_emoji = "📚"
evaluation = "加油!多练习会更好!"
score_display_frame = QFrame()
score_display_frame.setStyleSheet(f"""
QFrame {{
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid {score_color};
}}
""")
score_display_layout = QVBoxLayout(score_display_frame)
score_display_layout.setContentsMargins(30, 20, 30, 20)
# 得分数字
score_value_label = QLabel(f"{score_emoji} {self.score}{score_emoji}")
score_value_label.setStyleSheet(f"""
QLabel {{
font: bold 48pt '微软雅黑';
color: {score_color};
background: transparent;
qproperty-alignment: AlignCenter;
}}
""")
score_display_layout.addWidget(score_value_label)
# 评价
evaluation_label = QLabel(evaluation)
evaluation_label.setStyleSheet(f"""
QLabel {{
font: bold 16pt '微软雅黑';
color: {score_color};
background: transparent;
qproperty-alignment: AlignCenter;
}}
""")
score_display_layout.addWidget(evaluation_label)
score_layout.addWidget(score_display_frame)
card_layout.addWidget(score_frame)
card_layout.addSpacing(40)
# 按钮框架
button_frame = QFrame()
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QHBoxLayout(button_frame)
button_layout.setSpacing(20)
# 按钮样式
button_style = """
QPushButton {
font: bold 14pt '微软雅黑';
border-radius: 25px;
min-width: 140px;
min-height: 50px;
border: 3px solid;
}
"""
# 再做一套按钮
again_btn = QPushButton("🔄 再来一次")
again_btn.setStyleSheet(button_style + """
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #A0E7E5, stop:1 #6CD6D3);
color: white;
border-color: #8ADBD9;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8ADBD9, stop:1 #5AC7C4);
border-color: #6CD6D3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #5AC7C4, stop:1 #4BB5B2);
}
""")
again_btn.clicked.connect(self.do_again)
button_layout.addWidget(again_btn)
# 返回学段按钮
level_btn = QPushButton("🗺️ 选择地图")
level_btn.setStyleSheet(button_style + """
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFDAC1, stop:1 #FFB347);
color: white;
border-color: #FFB347;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFB347, stop:1 #FF9800);
border-color: #FF9800;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FF9800, stop:1 #F57C00);
}
""")
level_btn.clicked.connect(self.exit_to_level)
button_layout.addWidget(level_btn)
# 退出程序按钮
quit_btn = QPushButton("🚪 结束冒险")
quit_btn.setStyleSheet(button_style + """
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #C7CEEA, stop:1 #9FA8DA);
color: white;
border-color: #9FA8DA;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #9FA8DA, stop:1 #7986CB);
border-color: #7986CB;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #7986CB, stop:1 #5C6BC0);
}
""")
quit_btn.clicked.connect(self.quit_app)
button_layout.addWidget(quit_btn)
card_layout.addWidget(button_frame)
card_layout.addStretch(1)
# 装饰性底部
decoration_label = QLabel("✨🌈🎮 数学冒险岛 - 学数学,真有趣! 🌟📚🚀")
decoration_label.setStyleSheet("""
QLabel {
font: bold 12pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
card_layout.addWidget(decoration_label)
def quit_app(self):
"""退出程序"""
reply = QMessageBox.question(self, "🎮 结束冒险",
"确定要结束数学冒险吗?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
if self.parent_window:
self.parent_window.close()
def do_again(self):
"""重新做题"""
if self.parent_window:
self.parent_window.remove_current_page() # 移除结果页面
self.parent_window.show_count_page() # 回到题目数量页面
def exit_to_level(self):
"""返回学段选择"""
if self.parent_window:
self.parent_window.remove_current_page() # 移除结果页面
self.parent_window.show_level_page() # 回到学段选择页面

@ -0,0 +1,297 @@
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QPushButton, QMessageBox, QFrame, QSizePolicy)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
class ChangeUsernamePage(QWidget): # 改为继承 QWidget
def __init__(self, parent=None):
super().__init__(parent)
self.parent_window = parent
self.user_system = parent.user_system if parent and hasattr(parent, 'user_system') else None
self.setup_ui()
def setup_ui(self):
"""初始化界面"""
# 移除 setWindowTitle 和 setMinimumSize使用父窗口的尺寸
# 设置可爱的渐变背景
self.setStyleSheet("""
QWidget {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFD1DC, stop:1 #B5EAD7);
}
""")
# 主布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(25, 20, 25, 20)
main_layout.setSpacing(0)
# 卡片容器
card = QFrame()
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
card.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 white, stop:1 #FFF9FA);
border-radius: 20px;
border: 3px solid #FF9EBC;
}
""")
main_layout.addWidget(card)
# 卡片布局
card_layout = QVBoxLayout(card)
card_layout.setContentsMargins(35, 30, 35, 30)
card_layout.setSpacing(0)
# 顶部弹性空间
card_layout.addStretch(1)
# 标题区域
title_frame = QFrame()
title_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
title_frame.setStyleSheet("background: transparent; border: none;")
title_layout = QVBoxLayout(title_frame)
title_layout.setSpacing(10)
# 装饰性emoji
emoji_label = QLabel("👤✨🆕")
emoji_label.setStyleSheet("""
QLabel {
font: bold 20pt 'Arial';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(emoji_label)
# 主标题
title_label = QLabel("修改用户名")
title_label.setStyleSheet("""
QLabel {
font: bold 24pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(title_label)
subtitle_label = QLabel("🎯 给你的冒险角色换个新名字吧! 🎯")
subtitle_label.setStyleSheet("""
QLabel {
font: 12pt '微软雅黑';
color: #5A5A5A;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
title_layout.addWidget(subtitle_label)
card_layout.addWidget(title_frame)
card_layout.addSpacing(30)
# 当前用户名显示
current_user_frame = QFrame()
current_user_frame.setStyleSheet("""
QFrame {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #FFF9FA, stop:1 #FFE4EC);
border-radius: 15px;
border: 2px solid #FFD1DC;
}
""")
current_user_layout = QVBoxLayout(current_user_frame)
current_user_layout.setContentsMargins(20, 15, 20, 15)
current_title_label = QLabel("🎮 当前冒险者")
current_title_label.setStyleSheet("""
QLabel {
font: bold 14pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
current_user_layout.addWidget(current_title_label)
# 检查用户系统是否存在
if self.user_system and self.user_system.current_user:
current_username = self.user_system.current_user
else:
current_username = "未登录"
current_user_label = QLabel(f"{current_username}")
current_user_label.setStyleSheet("""
QLabel {
font: bold 18pt '微软雅黑';
color: #FF6B9C;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
current_user_layout.addWidget(current_user_label)
card_layout.addWidget(current_user_frame)
card_layout.addSpacing(25)
# 新用户名输入区域
input_frame = QFrame()
input_frame.setStyleSheet("background: transparent; border: none;")
input_layout = QVBoxLayout(input_frame)
input_layout.setSpacing(8)
# 新用户名标签
new_username_label = QLabel("🆕 新用户名:")
new_username_label.setStyleSheet("""
QLabel {
font: bold 14pt '微软雅黑';
color: #FF6B9C;
background: transparent;
}
""")
input_layout.addWidget(new_username_label)
# 新用户名输入框
self.new_username_input = QLineEdit()
self.new_username_input.setMinimumHeight(45)
self.new_username_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.new_username_input.setStyleSheet("""
QLineEdit {
background: white;
border: 2px solid #FF9EBC;
border-radius: 18px;
font: 14pt '微软雅黑';
color: #FF6B9C;
padding: 8px 20px;
selection-background-color: #FFE4EC;
}
QLineEdit:focus {
border: 2px solid #FF6B9C;
background: #FFF9FA;
}
QLineEdit::placeholder {
color: #CCCCCC;
font: 12pt '微软雅黑';
}
""")
self.new_username_input.setPlaceholderText("请输入新的冒险者名字...")
input_layout.addWidget(self.new_username_input)
# 用户名提示
hint_label = QLabel("📝 用户名要求2-10位中文、字母或数字")
hint_label.setStyleSheet("""
QLabel {
font: 10pt '微软雅黑';
color: #FF9EBC;
background: transparent;
}
""")
input_layout.addWidget(hint_label)
card_layout.addWidget(input_frame)
card_layout.addSpacing(30)
# 确认按钮
button_frame = QFrame()
button_frame.setStyleSheet("background: transparent; border: none;")
button_layout = QVBoxLayout(button_frame)
self.confirm_btn = QPushButton("✨ 确认修改")
self.confirm_btn.setMinimumSize(200, 50)
self.confirm_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.confirm_btn.setStyleSheet("""
QPushButton {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B5EAD7, stop:1 #8CD9B3);
color: white;
font: bold 16pt '微软雅黑';
border-radius: 25px;
border: 3px solid #A0E7E5;
}
QPushButton:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8CD9B3, stop:1 #6CD6D3);
border: 3px solid #8CD9B3;
}
QPushButton:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #6CD6D3, stop:1 #5AC7C4);
}
""")
self.confirm_btn.clicked.connect(self.change_username)
button_layout.addWidget(self.confirm_btn, alignment=Qt.AlignCenter)
card_layout.addWidget(button_frame)
card_layout.addStretch(1)
# 装饰性底部
decoration_label = QLabel("🌟🌈🎮 换个名字,开启新的冒险! 📚✨🚀")
decoration_label.setStyleSheet("""
QLabel {
font: bold 10pt 'Arial';
color: #FF9EBC;
background: transparent;
qproperty-alignment: AlignCenter;
}
""")
card_layout.addWidget(decoration_label)
# 绑定回车键
self.new_username_input.returnPressed.connect(self.change_username)
# 设置焦点
self.new_username_input.setFocus()
def change_username(self):
"""修改用户名"""
if not self.user_system:
QMessageBox.warning(self, "❌ 错误", "用户系统未初始化")
return
if not self.user_system.current_user:
QMessageBox.warning(self, "⚠️ 提示", "请先登录")
if self.parent_window:
self.parent_window.show_main_page() # 回到主页面
return
new_username = self.new_username_input.text().strip()
if not new_username:
QMessageBox.warning(self, "⚠️ 提示", "请输入新用户名")
self.new_username_input.setFocus()
return
if new_username == self.user_system.current_user:
QMessageBox.warning(self, "⚠️ 提示", "新用户名与当前用户名相同,请换个不同的名字吧!")
self.new_username_input.clear()
self.new_username_input.setFocus()
return
if self.user_system.set_username(new_username):
QMessageBox.information(self, "🎉 修改成功",
f"用户名修改成功!\n\n"
f"从现在开始,你就是勇敢的冒险者:\n"
f"{new_username}")
# 不再使用 self.accept(),而是通知父窗口切换页面
if self.parent_window:
self.parent_window.show_level_page() # 回到学段选择页面
else:
QMessageBox.warning(self, "❌ 修改失败",
"用户名修改失败:\n"
"• 用户名不符合要求2-10位中文、字母或数字\n"
"• 或用户名已被其他冒险者使用")
self.new_username_input.clear()
self.new_username_input.setFocus()
def showEvent(self, event):
"""显示页面时重置状态"""
super().showEvent(event)
self.new_username_input.clear()
self.new_username_input.setFocus()
# 更新当前用户名显示
if hasattr(self, 'current_user_label') and self.user_system and self.user_system.current_user:
self.current_user_label.setText(f"{self.user_system.current_user}")
Loading…
Cancel
Save