@ -0,0 +1,63 @@
|
||||
#ifndef FILESAVER_H
|
||||
#define FILESAVER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
// 文件保存器类,负责将生成的数学题目保存到文件系统
|
||||
class FileSaver {
|
||||
public:
|
||||
//将题目列表写入指定文件
|
||||
static bool writeQuestionsToFile(const std::string& filename,
|
||||
const std::string& safeUsername,
|
||||
const std::string& englishGrade,
|
||||
const std::vector<std::wstring>& questions);
|
||||
|
||||
//准备用户专属文件夹和文件路径
|
||||
static std::string prepareFileAndDirectory(const std::wstring& username,
|
||||
const std::wstring& grade);
|
||||
|
||||
//保存题目列表到用户专属文件
|
||||
static bool saveToFile(const std::wstring& username,
|
||||
const std::wstring& grade,
|
||||
const std::vector<std::wstring>& questions);
|
||||
|
||||
//生成基于当前时间戳的文件名
|
||||
static std::wstring generateFilename();
|
||||
|
||||
//获取当前格式化的时间字符串
|
||||
static std::wstring getCurrentTime();
|
||||
|
||||
//保存考试记录
|
||||
static bool saveExamRecord(const std::wstring& username,
|
||||
const std::wstring& grade,
|
||||
int score,
|
||||
int totalQuestions,
|
||||
const std::wstring& examDate);
|
||||
|
||||
private:
|
||||
//将包含中文的用户名转换为安全的英文文件名
|
||||
static std::string usernameToSafeName(const std::wstring& username);
|
||||
|
||||
//将中文年级转换为英文标识
|
||||
static std::string gradeToEnglish(const std::wstring& grade);
|
||||
|
||||
//宽字符串到普通字符串的转换
|
||||
static std::string wstringToString(const std::wstring& wstr);
|
||||
|
||||
//创建目录(跨平台实现)
|
||||
static bool createDirectory(const std::wstring& wpath);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,41 @@
|
||||
#include "user.h"
|
||||
#include <string>
|
||||
|
||||
//用户构造函数的实现
|
||||
User::User(const std::wstring& name, const std::wstring& pass, Grade grade)
|
||||
: username(name), password(pass), gradeType(grade) {}
|
||||
|
||||
//用户验证的实现
|
||||
bool User::check(const std::wstring& name, const std::wstring& pass) const {
|
||||
return (username == name && password == pass);
|
||||
}
|
||||
|
||||
//获取用户名的实现
|
||||
std::wstring User::getUsername() const {
|
||||
return username;
|
||||
}
|
||||
|
||||
//获取密码的实现
|
||||
std::wstring User::getPassword() const {
|
||||
return password;
|
||||
}
|
||||
|
||||
//获取年级枚举值的实现
|
||||
Grade User::getGrade() const {
|
||||
return gradeType;
|
||||
}
|
||||
|
||||
//获取年级字符串的实现
|
||||
std::wstring User::getGradeString() const {
|
||||
switch(gradeType) {
|
||||
case Grade::PRIMARY: return L"小学";
|
||||
case Grade::JUNIOR: return L"初中";
|
||||
case Grade::SENIOR: return L"高中";
|
||||
default: return L"未知";
|
||||
}
|
||||
}
|
||||
|
||||
//设置密码的实现
|
||||
void User::setPassword(const std::wstring& newPassword) {
|
||||
password = newPassword;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef USER_H
|
||||
#define USER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
//年级枚举,表示用户所属的学段级别
|
||||
//用于区分不同学段的题目难度和生成规则
|
||||
enum class Grade { PRIMARY, JUNIOR, SENIOR };
|
||||
|
||||
//用户信息类,封装用户认证数据和年级信息
|
||||
//存储用户名、密码和年级类型,提供验证和查询接口。
|
||||
class User {
|
||||
private:
|
||||
std::wstring username;
|
||||
std::wstring password;
|
||||
Grade gradeType;
|
||||
|
||||
public:
|
||||
//构造函数,初始化用户信息
|
||||
User(const std::wstring& name, const std::wstring& pass, Grade grade);
|
||||
|
||||
//验证用户名和密码是否匹配
|
||||
bool check(const std::wstring& name, const std::wstring& pass) const;
|
||||
|
||||
//获取用户名
|
||||
std::wstring getUsername() const;
|
||||
|
||||
//获取密码
|
||||
std::wstring getPassword() const;
|
||||
|
||||
//获取年级枚举值
|
||||
Grade getGrade() const;
|
||||
|
||||
//获取年级的中文描述
|
||||
std::wstring getGradeString() const;
|
||||
|
||||
//设置密码
|
||||
void setPassword(const std::wstring& newPassword);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,75 @@
|
||||
#ifndef USERMANAGE_H
|
||||
#define USERMANAGE_H
|
||||
|
||||
#include "user.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <QProcess> // 添加进程支持
|
||||
|
||||
// 邮箱验证码结构
|
||||
struct EmailVerification {
|
||||
std::wstring code;
|
||||
std::chrono::system_clock::time_point expiryTime;
|
||||
bool used;
|
||||
};
|
||||
|
||||
// 用户管理器类,负责用户数据的初始化和认证管理
|
||||
class UserManager {
|
||||
private:
|
||||
std::vector<User> users;
|
||||
const std::string userFile = "users.dat";
|
||||
|
||||
// 邮箱验证码存储
|
||||
std::map<std::wstring, EmailVerification> emailVerifications;
|
||||
|
||||
//初始化预定义用户数据
|
||||
void initializeUsers();
|
||||
|
||||
//从文件加载用户数据
|
||||
bool loadUsersFromFile();
|
||||
|
||||
//保存用户数据到文件
|
||||
bool saveUsersToFile();
|
||||
|
||||
// 真实邮件发送
|
||||
bool sendRealEmail(const std::wstring& email, const std::wstring& code);
|
||||
|
||||
// PowerShell 邮件发送方法
|
||||
bool sendEmailViaPowerShell(const QString& toEmail, const QString& code);
|
||||
|
||||
public:
|
||||
//构造函数,自动初始化用户数据
|
||||
UserManager();
|
||||
|
||||
//用户认证,验证用户名和密码
|
||||
User* authenticateUser(const std::wstring& username, const std::wstring& password);
|
||||
|
||||
//将中文年级字符串解析为年级枚举值
|
||||
Grade parseUserType(const std::wstring& type);
|
||||
|
||||
//注册新用户
|
||||
bool registerUser(const std::wstring& username, const std::wstring& password, const std::wstring& grade);
|
||||
|
||||
//修改用户密码
|
||||
bool changePassword(const std::wstring& username, const std::wstring& oldPassword, const std::wstring& newPassword);
|
||||
|
||||
//检查用户名是否存在
|
||||
bool isUsernameExists(const std::wstring& username);
|
||||
|
||||
// 邮箱验证相关方法
|
||||
bool sendVerificationCode(const std::wstring& email, std::wstring& generatedCode);
|
||||
bool verifyEmailCode(const std::wstring& email, const std::wstring& code);
|
||||
|
||||
// 生成随机验证码
|
||||
std::wstring generateVerificationCode(int length = 6);
|
||||
|
||||
//获取所有用户(用于测试)
|
||||
std::vector<User>& getUsers() { return users; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,56 @@
|
||||
#ifndef EXAMWIDGET_H
|
||||
#define EXAMWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QRadioButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "questiongenerator.h"
|
||||
#include "user.h"
|
||||
|
||||
class ExamWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ExamWidget(QWidget *parent = nullptr);
|
||||
void startExam(Grade grade, int questionCount);
|
||||
|
||||
signals:
|
||||
void examFinished(int score, int total);
|
||||
|
||||
private slots:
|
||||
void onNextClicked();
|
||||
void onPreviousClicked(); // 上一题
|
||||
void onSubmitClicked();
|
||||
|
||||
private:
|
||||
void showQuestion(int index);
|
||||
void generateOptions();
|
||||
void updateButtonStates(); // 更新按钮状态
|
||||
|
||||
QLabel *questionLabel;
|
||||
QLabel *progressLabel;
|
||||
QButtonGroup *optionGroup;
|
||||
QRadioButton *optionButtons[4];
|
||||
QPushButton *previousButton; // 上一题按钮
|
||||
QPushButton *nextButton;
|
||||
QPushButton *submitButton;
|
||||
|
||||
QuestionGenerator questionGenerator;
|
||||
std::vector<std::wstring> questions;
|
||||
std::vector<int> userAnswers;
|
||||
std::vector<int> correctAnswers;
|
||||
std::vector<std::vector<std::wstring>> questionOptions;
|
||||
|
||||
int currentQuestion;
|
||||
int totalQuestions;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,153 @@
|
||||
#include "loginwidget.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
|
||||
LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
// 设置最小尺寸
|
||||
setMinimumSize(400, 400);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(20);
|
||||
layout->setContentsMargins(50, 50, 50, 50);
|
||||
|
||||
// 标题
|
||||
QLabel *titleLabel = new QLabel("数学学习软件 - 登录");
|
||||
titleLabel->setAlignment(Qt::AlignCenter);
|
||||
titleLabel->setStyleSheet("font-size: 24px; font-weight: bold; margin: 20px; color: #2c3e50;");
|
||||
|
||||
// 用户名输入
|
||||
QLabel *usernameLabel = new QLabel("用户名:");
|
||||
usernameLabel->setStyleSheet("font-size: 14px; font-weight: bold;");
|
||||
usernameEdit = new QLineEdit();
|
||||
usernameEdit->setPlaceholderText("请输入用户名");
|
||||
usernameEdit->setMinimumHeight(35);
|
||||
usernameEdit->setStyleSheet("QLineEdit { padding: 8px; font-size: 14px; border: 1px solid #bdc3c7; border-radius: 4px; }");
|
||||
|
||||
// 密码输入
|
||||
QLabel *passwordLabel = new QLabel("密码:");
|
||||
passwordLabel->setStyleSheet("font-size: 14px; font-weight: bold;");
|
||||
passwordEdit = new QLineEdit();
|
||||
passwordEdit->setEchoMode(QLineEdit::Password);
|
||||
passwordEdit->setPlaceholderText("请输入密码");
|
||||
passwordEdit->setMinimumHeight(35);
|
||||
passwordEdit->setStyleSheet("QLineEdit { padding: 8px; font-size: 14px; border: 1px solid #bdc3c7; border-radius: 4px; }");
|
||||
|
||||
// 按钮区域
|
||||
QWidget *buttonWidget = new QWidget();
|
||||
QVBoxLayout *buttonLayout = new QVBoxLayout(buttonWidget);
|
||||
buttonLayout->setSpacing(15);
|
||||
|
||||
loginButton = new QPushButton("登录");
|
||||
loginButton->setMinimumHeight(40);
|
||||
loginButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #3498db;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"font-size: 16px;"
|
||||
"font-weight: bold;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #2980b9;"
|
||||
"}");
|
||||
|
||||
registerButton = new QPushButton("注册新账号");
|
||||
registerButton->setMinimumHeight(40);
|
||||
registerButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #95a5a6;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"font-size: 16px;"
|
||||
"font-weight: bold;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #7f8c8d;"
|
||||
"}");
|
||||
|
||||
// 添加退出按钮
|
||||
QPushButton *exitButton = new QPushButton("退出系统");
|
||||
exitButton->setMinimumHeight(40);
|
||||
exitButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #e74c3c;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"font-size: 16px;"
|
||||
"font-weight: bold;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #c0392b;"
|
||||
"}");
|
||||
|
||||
// 测试账号提示
|
||||
QLabel *testAccountLabel = new QLabel("测试账号: zhangsan1 / lisi1 / wangwu1 密码: Abc123");
|
||||
testAccountLabel->setStyleSheet("font-size: 12px; color: #7f8c8d; margin-top: 10px;");
|
||||
testAccountLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
buttonLayout->addWidget(loginButton);
|
||||
buttonLayout->addWidget(registerButton);
|
||||
buttonLayout->addWidget(exitButton);
|
||||
buttonLayout->addWidget(testAccountLabel);
|
||||
|
||||
// 添加到布局
|
||||
layout->addWidget(titleLabel);
|
||||
layout->addSpacing(30);
|
||||
layout->addWidget(usernameLabel);
|
||||
layout->addWidget(usernameEdit);
|
||||
layout->addWidget(passwordLabel);
|
||||
layout->addWidget(passwordEdit);
|
||||
layout->addSpacing(30);
|
||||
layout->addWidget(buttonWidget);
|
||||
|
||||
// 连接信号槽
|
||||
connect(loginButton, &QPushButton::clicked, this, &LoginWidget::onLoginClicked);
|
||||
connect(registerButton, &QPushButton::clicked, this, &LoginWidget::onRegisterClicked);
|
||||
connect(exitButton, &QPushButton::clicked, qApp, &QApplication::quit);
|
||||
|
||||
// 回车键登录
|
||||
connect(usernameEdit, &QLineEdit::returnPressed, this, &LoginWidget::onLoginClicked);
|
||||
connect(passwordEdit, &QLineEdit::returnPressed, this, &LoginWidget::onLoginClicked);
|
||||
|
||||
qDebug() << "LoginWidget: 初始化完成";
|
||||
}
|
||||
|
||||
void LoginWidget::onLoginClicked()
|
||||
{
|
||||
QString username = usernameEdit->text().trimmed();
|
||||
QString password = passwordEdit->text();
|
||||
|
||||
qDebug() << "LoginWidget: 尝试登录,用户名:" << username;
|
||||
|
||||
if (username.isEmpty() || password.isEmpty()) {
|
||||
QMessageBox::warning(this, "输入错误", "请输入用户名和密码");
|
||||
return;
|
||||
}
|
||||
|
||||
User* user = userManager.authenticateUser(username.toStdWString(),
|
||||
password.toStdWString());
|
||||
if (user) {
|
||||
qDebug() << "LoginWidget: 登录成功";
|
||||
emit loginSuccess(user);
|
||||
} else {
|
||||
qDebug() << "LoginWidget: 登录失败";
|
||||
QMessageBox::warning(this, "登录失败", "用户名或密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
void LoginWidget::onRegisterClicked()
|
||||
{
|
||||
qDebug() << "LoginWidget: 切换到注册界面";
|
||||
emit showRegister();
|
||||
}
|
||||
|
||||
void LoginWidget::clearInputs()
|
||||
{
|
||||
qDebug() << "LoginWidget: 清空输入框";
|
||||
usernameEdit->clear();
|
||||
passwordEdit->clear();
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
#ifndef LOGINWIDGET_H
|
||||
#define LOGINWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include "usermanage.h"
|
||||
|
||||
class LoginWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LoginWidget(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void loginSuccess(User* user);
|
||||
void showRegister();
|
||||
|
||||
private slots:
|
||||
void onLoginClicked();
|
||||
void onRegisterClicked();
|
||||
|
||||
public slots:
|
||||
void clearInputs();
|
||||
|
||||
private:
|
||||
QLineEdit *usernameEdit; // 改为用户名输入
|
||||
QLineEdit *passwordEdit;
|
||||
QPushButton *loginButton;
|
||||
QPushButton *registerButton;
|
||||
UserManager userManager;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,24 @@
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
qDebug() << "应用程序启动...";
|
||||
|
||||
// 设置应用程序信息
|
||||
app.setApplicationName("数学学习软件");
|
||||
app.setApplicationVersion("1.0");
|
||||
app.setOrganizationName("软件工程学院");
|
||||
|
||||
qDebug() << "创建主窗口...";
|
||||
MainWindow window;
|
||||
|
||||
qDebug() << "显示主窗口...";
|
||||
window.show();
|
||||
|
||||
qDebug() << "进入事件循环...";
|
||||
return app.exec();
|
||||
}
|
||||
@ -0,0 +1,182 @@
|
||||
#include "mainmenuwidget.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
|
||||
MainMenuWidget::MainMenuWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// 标题和欢迎信息
|
||||
QLabel *titleLabel = new QLabel("数学学习软件");
|
||||
titleLabel->setAlignment(Qt::AlignCenter);
|
||||
titleLabel->setStyleSheet("font-size: 24px; font-weight: bold; margin: 30px; color: #2c3e50;");
|
||||
|
||||
welcomeLabel = new QLabel("欢迎使用数学学习软件");
|
||||
welcomeLabel->setAlignment(Qt::AlignCenter);
|
||||
welcomeLabel->setStyleSheet("font-size: 18px; margin: 20px; color: #34495e;");
|
||||
|
||||
userInfoLabel = new QLabel();
|
||||
userInfoLabel->setAlignment(Qt::AlignCenter);
|
||||
userInfoLabel->setStyleSheet("font-size: 14px; margin: 10px; color: #7f8c8d;");
|
||||
|
||||
// 设置区域
|
||||
QGroupBox *settingsGroup = new QGroupBox("考试设置");
|
||||
settingsGroup->setStyleSheet("QGroupBox {"
|
||||
"font-size: 16px;"
|
||||
"font-weight: bold;"
|
||||
"margin-top: 10px;"
|
||||
"}"
|
||||
"QGroupBox::title {"
|
||||
"subcontrol-origin: margin;"
|
||||
"subcontrol-position: top center;"
|
||||
"padding: 0 5px;"
|
||||
"}");
|
||||
|
||||
QVBoxLayout *settingsLayout = new QVBoxLayout(settingsGroup);
|
||||
|
||||
// 年级选择
|
||||
QWidget *gradeWidget = new QWidget();
|
||||
QHBoxLayout *gradeLayout = new QHBoxLayout(gradeWidget);
|
||||
QLabel *gradeLabel = new QLabel("选择年级:");
|
||||
gradeLabel->setStyleSheet("font-size: 14px;");
|
||||
gradeComboBox = new QComboBox();
|
||||
gradeComboBox->addItem("小学");
|
||||
gradeComboBox->addItem("初中");
|
||||
gradeComboBox->addItem("高中");
|
||||
gradeComboBox->setStyleSheet("padding: 8px; font-size: 14px;");
|
||||
gradeLayout->addWidget(gradeLabel);
|
||||
gradeLayout->addWidget(gradeComboBox);
|
||||
gradeLayout->addStretch();
|
||||
|
||||
// 题目数量
|
||||
QWidget *countWidget = new QWidget();
|
||||
QHBoxLayout *countLayout = new QHBoxLayout(countWidget);
|
||||
QLabel *countLabel = new QLabel("题目数量:");
|
||||
countLabel->setStyleSheet("font-size: 14px;");
|
||||
questionCountSpinBox = new QSpinBox();
|
||||
questionCountSpinBox->setRange(5, 30);
|
||||
questionCountSpinBox->setValue(10);
|
||||
questionCountSpinBox->setStyleSheet("padding: 8px; font-size: 14px;");
|
||||
countLayout->addWidget(countLabel);
|
||||
countLayout->addWidget(questionCountSpinBox);
|
||||
countLayout->addStretch();
|
||||
|
||||
// 开始按钮
|
||||
startButton = new QPushButton("开始考试");
|
||||
startButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #e74c3c;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"padding: 12px 30px;"
|
||||
"font-size: 16px;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #c0392b;"
|
||||
"}");
|
||||
startButton->setFixedSize(150, 50);
|
||||
|
||||
// 退出登录按钮
|
||||
logoutButton = new QPushButton("退出登录");
|
||||
logoutButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #95a5a6;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"padding: 12px 30px;"
|
||||
"font-size: 16px;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #7f8c8d;"
|
||||
"}");
|
||||
logoutButton->setFixedSize(150, 50); // 修改为相同大小
|
||||
|
||||
// 按钮容器 - 重新设计布局
|
||||
QWidget *buttonWidget = new QWidget();
|
||||
QVBoxLayout *buttonLayout = new QVBoxLayout(buttonWidget);
|
||||
buttonLayout->setSpacing(15); // 设置按钮间距
|
||||
buttonLayout->setContentsMargins(0, 20, 0, 10);
|
||||
|
||||
// 开始考试按钮行
|
||||
QWidget *startButtonWidget = new QWidget();
|
||||
QHBoxLayout *startButtonLayout = new QHBoxLayout(startButtonWidget);
|
||||
startButtonLayout->addStretch();
|
||||
startButtonLayout->addWidget(startButton);
|
||||
startButtonLayout->addStretch();
|
||||
|
||||
// 退出登录按钮行
|
||||
QWidget *logoutButtonWidget = new QWidget();
|
||||
QHBoxLayout *logoutButtonLayout = new QHBoxLayout(logoutButtonWidget);
|
||||
logoutButtonLayout->addStretch();
|
||||
logoutButtonLayout->addWidget(logoutButton);
|
||||
logoutButtonLayout->addStretch();
|
||||
|
||||
// 添加到按钮布局
|
||||
buttonLayout->addWidget(startButtonWidget);
|
||||
buttonLayout->addWidget(logoutButtonWidget);
|
||||
|
||||
// 添加到设置布局
|
||||
settingsLayout->addWidget(gradeWidget);
|
||||
settingsLayout->addWidget(countWidget);
|
||||
settingsLayout->addSpacing(20);
|
||||
settingsLayout->addWidget(buttonWidget);
|
||||
|
||||
// 添加到主布局
|
||||
mainLayout->addWidget(titleLabel);
|
||||
mainLayout->addWidget(welcomeLabel);
|
||||
mainLayout->addWidget(userInfoLabel);
|
||||
mainLayout->addSpacing(20);
|
||||
mainLayout->addWidget(settingsGroup);
|
||||
mainLayout->addStretch();
|
||||
|
||||
// 连接信号槽
|
||||
connect(startButton, &QPushButton::clicked, this, &MainMenuWidget::onStartExamClicked);
|
||||
connect(logoutButton, &QPushButton::clicked, this, &MainMenuWidget::onLogoutClicked);
|
||||
|
||||
qDebug() << "MainMenuWidget: 初始化完成,退出登录按钮大小已调整";
|
||||
}
|
||||
|
||||
void MainMenuWidget::setUserInfo(const std::wstring& username, const std::wstring& grade)
|
||||
{
|
||||
QString userInfo = QString("当前用户: %1 | 注册年级: %2")
|
||||
.arg(QString::fromStdWString(username))
|
||||
.arg(QString::fromStdWString(grade));
|
||||
userInfoLabel->setText(userInfo);
|
||||
|
||||
// 设置年级选择框默认值
|
||||
QString gradeStr = QString::fromStdWString(grade);
|
||||
int index = gradeComboBox->findText(gradeStr);
|
||||
if (index >= 0) {
|
||||
gradeComboBox->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
QString MainMenuWidget::getSelectedGrade() const {
|
||||
return gradeComboBox->currentText();
|
||||
}
|
||||
|
||||
void MainMenuWidget::onStartExamClicked()
|
||||
{
|
||||
int questionCount = questionCountSpinBox->value();
|
||||
QString selectedGrade = gradeComboBox->currentText();
|
||||
qDebug() << "MainMenuWidget: 开始考试,题目数量:" << questionCount << "选择年级:" << selectedGrade;
|
||||
emit startExam(questionCount);
|
||||
}
|
||||
|
||||
void MainMenuWidget::onLogoutClicked()
|
||||
{
|
||||
qDebug() << "MainMenuWidget: 用户请求退出登录";
|
||||
|
||||
// 弹出确认对话框
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, "确认退出",
|
||||
"确定要退出登录吗?",
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
qDebug() << "MainMenuWidget: 用户确认退出登录";
|
||||
emit logoutRequested();
|
||||
} else {
|
||||
qDebug() << "MainMenuWidget: 用户取消退出登录";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
#ifndef MAINMENUWIDGET_H
|
||||
#define MAINMENUWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGroupBox>
|
||||
|
||||
class MainMenuWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainMenuWidget(QWidget *parent = nullptr);
|
||||
void setUserInfo(const std::wstring& username, const std::wstring& grade);
|
||||
QString getSelectedGrade() const;
|
||||
|
||||
signals:
|
||||
void startExam(int questionCount);
|
||||
void logoutRequested(); // 退出登录
|
||||
|
||||
private slots:
|
||||
void onStartExamClicked();
|
||||
void onLogoutClicked(); // 处理退出登录
|
||||
|
||||
private:
|
||||
QLabel *welcomeLabel;
|
||||
QLabel *userInfoLabel;
|
||||
QComboBox *gradeComboBox;
|
||||
QSpinBox *questionCountSpinBox;
|
||||
QPushButton *startButton;
|
||||
QPushButton *logoutButton; // 退出登录按钮
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,43 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QStackedWidget>
|
||||
#include "loginwidget.h"
|
||||
#include "registerwidget.h"
|
||||
#include "mainmenuwidget.h"
|
||||
#include "examwidget.h"
|
||||
#include "resultwidget.h"
|
||||
#include "usermanage.h"
|
||||
#include "filesaver.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void showLogin();
|
||||
void showRegister();
|
||||
void showMainMenu();
|
||||
void showExam(int questionCount);
|
||||
void showResult(int score, int total);
|
||||
void onUserLoggedIn(User* user);
|
||||
void onRegisterSuccess();
|
||||
void onLogoutRequested(); // 处理退出登录
|
||||
|
||||
private:
|
||||
QStackedWidget *stackedWidget;
|
||||
LoginWidget *loginWidget;
|
||||
RegisterWidget *registerWidget;
|
||||
MainMenuWidget *mainMenuWidget;
|
||||
ExamWidget *examWidget;
|
||||
ResultWidget *resultWidget;
|
||||
UserManager userManager;
|
||||
User *currentUser;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar"/>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@ -0,0 +1,49 @@
|
||||
QT += core gui network
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
filesaver.cpp \
|
||||
questiongenerator.cpp \
|
||||
user.cpp \
|
||||
usermanage.cpp \
|
||||
loginwidget.cpp \
|
||||
main.cpp \
|
||||
mainmenuwidget.cpp \
|
||||
mainwindow.cpp \
|
||||
registerwidget.cpp \
|
||||
resultwidget.cpp \
|
||||
examwidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
filesaver.h \
|
||||
questiongenerator.h \
|
||||
user.h \
|
||||
usermanage.h \
|
||||
loginwidget.h \
|
||||
mainmenuwidget.h \
|
||||
mainwindow.h \
|
||||
registerwidget.h \
|
||||
resultwidget.h \
|
||||
examwidget.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
@ -0,0 +1,59 @@
|
||||
#ifndef REGISTERWIDGET_H
|
||||
#define REGISTERWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
#include <QComboBox>
|
||||
#include <QTimer>
|
||||
#include <QRandomGenerator>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include "usermanage.h"
|
||||
|
||||
class RegisterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RegisterWidget(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void registerSuccess();
|
||||
void showLogin();
|
||||
|
||||
private slots:
|
||||
void onSendCodeClicked();
|
||||
void onRegisterClicked();
|
||||
void onBackClicked();
|
||||
void updateTimer();
|
||||
|
||||
private:
|
||||
QLineEdit *emailEdit;
|
||||
QLineEdit *usernameEdit;
|
||||
QLineEdit *verificationCodeEdit;
|
||||
QLineEdit *passwordEdit;
|
||||
QLineEdit *confirmPasswordEdit;
|
||||
QComboBox *gradeComboBox;
|
||||
QPushButton *sendCodeButton;
|
||||
QPushButton *registerButton;
|
||||
QPushButton *backButton;
|
||||
QLabel *timerLabel;
|
||||
|
||||
QTimer *countdownTimer;
|
||||
int countdownSeconds;
|
||||
QString generatedCode;
|
||||
|
||||
UserManager userManager; // 添加用户管理器
|
||||
|
||||
bool validatePassword(const QString &password);
|
||||
bool validateEmail(const QString &email);
|
||||
void startCountdown();
|
||||
void resetCountdown();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,115 @@
|
||||
#include "resultwidget.h"
|
||||
|
||||
ResultWidget::ResultWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// 标题
|
||||
QLabel *titleLabel = new QLabel("考试结果");
|
||||
titleLabel->setAlignment(Qt::AlignCenter);
|
||||
titleLabel->setStyleSheet("font-size: 24px; font-weight: bold; margin: 30px; color: #2c3e50;");
|
||||
|
||||
// 结果区域
|
||||
QWidget *resultWidget = new QWidget();
|
||||
QVBoxLayout *resultLayout = new QVBoxLayout(resultWidget);
|
||||
resultLayout->setContentsMargins(50, 30, 50, 30);
|
||||
|
||||
resultLabel = new QLabel("考试完成!");
|
||||
resultLabel->setAlignment(Qt::AlignCenter);
|
||||
resultLabel->setStyleSheet("font-size: 20px; margin: 20px; color: #34495e;");
|
||||
|
||||
scoreLabel = new QLabel();
|
||||
scoreLabel->setAlignment(Qt::AlignCenter);
|
||||
scoreLabel->setStyleSheet("font-size: 36px; font-weight: bold; margin: 20px; color: #e74c3c;");
|
||||
|
||||
percentageLabel = new QLabel();
|
||||
percentageLabel->setAlignment(Qt::AlignCenter);
|
||||
percentageLabel->setStyleSheet("font-size: 18px; margin: 10px; color: #7f8c8d;");
|
||||
|
||||
// 按钮区域
|
||||
QWidget *buttonWidget = new QWidget();
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout(buttonWidget);
|
||||
|
||||
backButton = new QPushButton("返回主菜单");
|
||||
backButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #95a5a6;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"padding: 10px 20px;"
|
||||
"font-size: 14px;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #7f8c8d;"
|
||||
"}");
|
||||
backButton->setFixedWidth(120);
|
||||
|
||||
newExamButton = new QPushButton("继续做题");
|
||||
newExamButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #3498db;"
|
||||
"color: white;"
|
||||
"border: none;"
|
||||
"padding: 10px 20px;"
|
||||
"font-size: 14px;"
|
||||
"border-radius: 5px;"
|
||||
"}"
|
||||
"QPushButton:hover {"
|
||||
"background-color: #2980b9;"
|
||||
"}");
|
||||
newExamButton->setFixedWidth(120);
|
||||
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->addWidget(backButton);
|
||||
buttonLayout->addSpacing(20);
|
||||
buttonLayout->addWidget(newExamButton);
|
||||
buttonLayout->addStretch();
|
||||
|
||||
// 添加到结果布局
|
||||
resultLayout->addWidget(resultLabel);
|
||||
resultLayout->addWidget(scoreLabel);
|
||||
resultLayout->addWidget(percentageLabel);
|
||||
resultLayout->addSpacing(30);
|
||||
resultLayout->addWidget(buttonWidget);
|
||||
|
||||
// 添加到主布局
|
||||
mainLayout->addWidget(titleLabel);
|
||||
mainLayout->addWidget(resultWidget);
|
||||
mainLayout->addStretch();
|
||||
|
||||
// 连接信号槽
|
||||
connect(backButton, &QPushButton::clicked, this, &ResultWidget::onBackClicked);
|
||||
connect(newExamButton, &QPushButton::clicked, this, &ResultWidget::onNewExamClicked);
|
||||
}
|
||||
|
||||
void ResultWidget::setResult(int score, int total)
|
||||
{
|
||||
double percentage = (double)score / total * 100;
|
||||
|
||||
scoreLabel->setText(QString("%1 / %2").arg(score).arg(total));
|
||||
percentageLabel->setText(QString("正确率: %1%").arg(percentage, 0, 'f', 1));
|
||||
|
||||
// 根据分数显示不同的评价
|
||||
if (percentage >= 90) {
|
||||
resultLabel->setText("优秀!你的表现非常出色!");
|
||||
resultLabel->setStyleSheet("font-size: 20px; margin: 20px; color: #27ae60;");
|
||||
} else if (percentage >= 70) {
|
||||
resultLabel->setText("良好!继续努力!");
|
||||
resultLabel->setStyleSheet("font-size: 20px; margin: 20px; color: #f39c12;");
|
||||
} else if (percentage >= 60) {
|
||||
resultLabel->setText("及格!还有提升空间!");
|
||||
resultLabel->setStyleSheet("font-size: 20px; margin: 20px; color: #e67e22;");
|
||||
} else {
|
||||
resultLabel->setText("需要加油!再多练习一下吧!");
|
||||
resultLabel->setStyleSheet("font-size: 20px; margin: 20px; color: #e74c3c;");
|
||||
}
|
||||
}
|
||||
|
||||
void ResultWidget::onBackClicked()
|
||||
{
|
||||
emit backToMenu();
|
||||
}
|
||||
|
||||
void ResultWidget::onNewExamClicked()
|
||||
{
|
||||
emit startNewExam();
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
#ifndef RESULTWIDGET_H
|
||||
#define RESULTWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
class ResultWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ResultWidget(QWidget *parent = nullptr);
|
||||
void setResult(int score, int total);
|
||||
|
||||
signals:
|
||||
void backToMenu();
|
||||
void startNewExam();
|
||||
|
||||
private slots:
|
||||
void onBackClicked();
|
||||
void onNewExamClicked();
|
||||
|
||||
private:
|
||||
QLabel *resultLabel;
|
||||
QLabel *scoreLabel;
|
||||
QLabel *percentageLabel;
|
||||
QPushButton *backButton;
|
||||
QPushButton *newExamButton;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue