前端代码3.0 #3

Merged
hnu202326010112 merged 1 commits from liumuxue_branch into develop 3 months ago

@ -1,235 +0,0 @@
#include "examwidget.h"
#include <QMessageBox>
#include <random>
#include <QGroupBox>
#include <QTimer>
ExamWidget::ExamWidget(QWidget *parent) : QWidget(parent), currentQuestion(0), totalQuestions(0)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 进度标签
progressLabel = new QLabel();
progressLabel->setAlignment(Qt::AlignCenter);
progressLabel->setStyleSheet("font-size: 16px; font-weight: bold; margin: 20px; color: #2c3e50;");
// 题目区域
QGroupBox *questionGroup = new QGroupBox("题目");
questionGroup->setStyleSheet("QGroupBox {"
"font-size: 16px;"
"font-weight: bold;"
"margin-top: 10px;"
"}"
"QGroupBox::title {"
"subcontrol-origin: margin;"
"subcontrol-position: top center;"
"padding: 0 5px;"
"}");
QVBoxLayout *questionLayout = new QVBoxLayout(questionGroup);
questionLabel = new QLabel();
questionLabel->setWordWrap(true);
questionLabel->setStyleSheet("font-size: 18px; margin: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 5px;");
questionLabel->setAlignment(Qt::AlignCenter);
questionLabel->setMinimumHeight(80);
questionLayout->addWidget(questionLabel);
// 选项区域
QGroupBox *optionsGroup = new QGroupBox("请选择答案");
optionsGroup->setStyleSheet("QGroupBox {"
"font-size: 16px;"
"font-weight: bold;"
"margin-top: 10px;"
"}"
"QGroupBox::title {"
"subcontrol-origin: margin;"
"subcontrol-position: top center;"
"padding: 0 5px;"
"}");
QVBoxLayout *optionsLayout = new QVBoxLayout(optionsGroup);
optionGroup = new QButtonGroup(this);
for (int i = 0; i < 4; ++i) {
optionButtons[i] = new QRadioButton();
optionButtons[i]->setStyleSheet("QRadioButton {"
"font-size: 14px;"
"margin: 8px;"
"padding: 8px;"
"}"
"QRadioButton::indicator {"
"width: 20px;"
"height: 20px;"
"}");
optionGroup->addButton(optionButtons[i], i);
optionsLayout->addWidget(optionButtons[i]);
}
// 按钮区域
QWidget *buttonWidget = new QWidget();
QHBoxLayout *buttonLayout = new QHBoxLayout(buttonWidget);
nextButton = new QPushButton("下一题");
nextButton->setStyleSheet("QPushButton {"
"background-color: #3498db;"
"color: white;"
"border: none;"
"padding: 10px 20px;"
"font-size: 14px;"
"border-radius: 5px;"
"}"
"QPushButton:hover {"
"background-color: #2980b9;"
"}");
nextButton->setFixedWidth(120);
submitButton = new QPushButton("提交试卷");
submitButton->setStyleSheet("QPushButton {"
"background-color: #e74c3c;"
"color: white;"
"border: none;"
"padding: 10px 20px;"
"font-size: 14px;"
"border-radius: 5px;"
"}"
"QPushButton:hover {"
"background-color: #c0392b;"
"}");
submitButton->setFixedWidth(120);
submitButton->setVisible(false);
buttonLayout->addStretch();
buttonLayout->addWidget(nextButton);
buttonLayout->addSpacing(10);
buttonLayout->addWidget(submitButton);
buttonLayout->addStretch();
// 添加到主布局
mainLayout->addWidget(progressLabel);
mainLayout->addWidget(questionGroup);
mainLayout->addWidget(optionsGroup);
mainLayout->addSpacing(20);
mainLayout->addWidget(buttonWidget);
mainLayout->addStretch();
// 连接信号槽
connect(nextButton, &QPushButton::clicked, this, &ExamWidget::onNextClicked);
connect(submitButton, &QPushButton::clicked, this, &ExamWidget::onSubmitClicked);
}
void ExamWidget::startExam(Grade grade, int questionCount)
{
questionGenerator.setGrade(grade);
questions = questionGenerator.generateQuestions(questionCount);
totalQuestions = questionCount;
currentQuestion = 0;
userAnswers.clear();
correctAnswers.clear();
// 为每个题目生成正确答案
for (int i = 0; i < totalQuestions; ++i) {
correctAnswers.push_back(i % 4); // 简单实现,实际应该计算
}
showQuestion(0);
}
void ExamWidget::showQuestion(int index)
{
if (index < totalQuestions) {
currentQuestion = index;
progressLabel->setText(QString("第 %1 题 / 共 %2 题").arg(index + 1).arg(totalQuestions));
// 显示题目
QString questionText = QString::fromStdWString(questions[index]);
questionLabel->setText(questionText);
// 生成选项
generateOptions();
// 清除选择
optionGroup->setExclusive(false);
for (int i = 0; i < 4; ++i) {
optionButtons[i]->setChecked(false);
}
optionGroup->setExclusive(true);
// 恢复之前的选择(如果有)
if (static_cast<size_t>(index) < userAnswers.size()) { // 修复有符号/无符号比较
int previousAnswer = userAnswers[index];
if (previousAnswer >= 0 && previousAnswer < 4) {
optionButtons[previousAnswer]->setChecked(true);
}
}
// 更新按钮状态
nextButton->setVisible(index < totalQuestions - 1);
submitButton->setVisible(index == totalQuestions - 1);
}
}
void ExamWidget::generateOptions()
{
// 生成有意义的选项
int correctIndex = correctAnswers[currentQuestion];
for (int i = 0; i < 4; ++i) {
if (i == correctIndex) {
optionButtons[i]->setText("正确答案");
} else {
// 生成干扰项
QString optionText;
switch(i) {
case 0: optionText = "选项 A"; break;
case 1: optionText = "选项 B"; break;
case 2: optionText = "选项 C"; break;
case 3: optionText = "选项 D"; break;
}
optionButtons[i]->setText(optionText);
}
}
}
void ExamWidget::onNextClicked()
{
int selected = optionGroup->checkedId();
if (selected == -1) {
QMessageBox::warning(this, "提示", "请选择一个答案");
return;
}
// 保存当前答案
if (static_cast<size_t>(currentQuestion) >= userAnswers.size()) { // 修复有符号/无符号比较
userAnswers.resize(currentQuestion + 1);
}
userAnswers[currentQuestion] = selected;
showQuestion(currentQuestion + 1);
}
void ExamWidget::onSubmitClicked()
{
int selected = optionGroup->checkedId();
if (selected == -1) {
QMessageBox::warning(this, "提示", "请选择一个答案");
return;
}
// 保存最后一题的答案
if (static_cast<size_t>(currentQuestion) >= userAnswers.size()) { // 修复有符号/无符号比较
userAnswers.resize(currentQuestion + 1);
}
userAnswers[currentQuestion] = selected;
// 计算分数
int score = 0;
for (size_t i = 0; i < userAnswers.size(); ++i) { // 使用size_t
if (i < correctAnswers.size() && userAnswers[i] == correctAnswers[i]) {
score++;
}
}
emit examFinished(score, totalQuestions);
}

@ -0,0 +1,376 @@
#include "examwidget.h"
#include <QMessageBox>
#include <random>
#include <QGroupBox>
#include <QTimer>
#include <QDebug>
#include <sstream>
#include <iomanip>
#include <cmath>
ExamWidget::ExamWidget(QWidget *parent) : QWidget(parent), currentQuestion(0), totalQuestions(0)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// 进度标签
progressLabel = new QLabel();
progressLabel->setAlignment(Qt::AlignCenter);
progressLabel->setStyleSheet("font-size: 16px; font-weight: bold; margin: 20px; color: #2c3e50;");
// 题目区域
QGroupBox *questionGroup = new QGroupBox("题目");
questionGroup->setStyleSheet("QGroupBox {"
"font-size: 16px;"
"font-weight: bold;"
"margin-top: 10px;"
"}"
"QGroupBox::title {"
"subcontrol-origin: margin;"
"subcontrol-position: top center;"
"padding: 0 5px;"
"}");
QVBoxLayout *questionLayout = new QVBoxLayout(questionGroup);
questionLabel = new QLabel();
questionLabel->setWordWrap(true);
questionLabel->setStyleSheet("font-size: 18px; margin: 20px; padding: 10px; background-color: #f8f9fa; border-radius: 5px;");
questionLabel->setAlignment(Qt::AlignCenter);
questionLabel->setMinimumHeight(80);
questionLayout->addWidget(questionLabel);
// 选项区域
QGroupBox *optionsGroup = new QGroupBox("请选择答案");
optionsGroup->setStyleSheet("QGroupBox {"
"font-size: 16px;"
"font-weight: bold;"
"margin-top: 10px;"
"}"
"QGroupBox::title {"
"subcontrol-origin: margin;"
"subcontrol-position: top center;"
"padding: 0 5px;"
"}");
QVBoxLayout *optionsLayout = new QVBoxLayout(optionsGroup);
optionGroup = new QButtonGroup(this);
for (int i = 0; i < 4; ++i) {
optionButtons[i] = new QRadioButton();
optionButtons[i]->setStyleSheet("QRadioButton {"
"font-size: 14px;"
"margin: 8px;"
"padding: 8px;"
"}"
"QRadioButton::indicator {"
"width: 20px;"
"height: 20px;"
"}");
optionGroup->addButton(optionButtons[i], i);
optionsLayout->addWidget(optionButtons[i]);
}
// 按钮区域
QWidget *buttonWidget = new QWidget();
QHBoxLayout *buttonLayout = new QHBoxLayout(buttonWidget);
// 上一题按钮
previousButton = new QPushButton("上一题");
previousButton->setStyleSheet("QPushButton {"
"background-color: #95a5a6;"
"color: white;"
"border: none;"
"padding: 10px 20px;"
"font-size: 14px;"
"border-radius: 5px;"
"}"
"QPushButton:hover {"
"background-color: #7f8c8d;"
"}"
"QPushButton:disabled {"
"background-color: #bdc3c7;"
"color: #7f8c8d;"
"}");
previousButton->setFixedWidth(120);
previousButton->setEnabled(false); // 第一题时禁用
nextButton = new QPushButton("下一题");
nextButton->setStyleSheet("QPushButton {"
"background-color: #3498db;"
"color: white;"
"border: none;"
"padding: 10px 20px;"
"font-size: 14px;"
"border-radius: 5px;"
"}"
"QPushButton:hover {"
"background-color: #2980b9;"
"}");
nextButton->setFixedWidth(120);
submitButton = new QPushButton("提交试卷");
submitButton->setStyleSheet("QPushButton {"
"background-color: #e74c3c;"
"color: white;"
"border: none;"
"padding: 10px 20px;"
"font-size: 14px;"
"border-radius: 5px;"
"}"
"QPushButton:hover {"
"background-color: #c0392b;"
"}");
submitButton->setFixedWidth(120);
submitButton->setVisible(false);
buttonLayout->addStretch();
buttonLayout->addWidget(previousButton);
buttonLayout->addSpacing(10);
buttonLayout->addWidget(nextButton);
buttonLayout->addSpacing(10);
buttonLayout->addWidget(submitButton);
buttonLayout->addStretch();
// 添加到主布局
mainLayout->addWidget(progressLabel);
mainLayout->addWidget(questionGroup);
mainLayout->addWidget(optionsGroup);
mainLayout->addSpacing(20);
mainLayout->addWidget(buttonWidget);
mainLayout->addStretch();
// 连接信号槽
connect(previousButton, &QPushButton::clicked, this, &ExamWidget::onPreviousClicked);
connect(nextButton, &QPushButton::clicked, this, &ExamWidget::onNextClicked);
connect(submitButton, &QPushButton::clicked, this, &ExamWidget::onSubmitClicked);
}
void ExamWidget::startExam(Grade grade, int questionCount)
{
try {
qDebug() << "ExamWidget: 开始考试,年级:" << static_cast<int>(grade) << "题目数量:" << questionCount;
questionGenerator.setGrade(grade);
questions = questionGenerator.generateQuestions(questionCount);
totalQuestions = static_cast<int>(questions.size());
currentQuestion = 0;
userAnswers.clear();
correctAnswers.clear();
questionOptions.clear();
if (questions.empty()) {
qDebug() << "ExamWidget: 题目生成失败";
QMessageBox::warning(this, "错误", "题目生成失败,请重试");
return;
}
qDebug() << "ExamWidget: 成功生成" << totalQuestions << "个题目";
// 预计算所有题目的正确答案和选项
for (int i = 0; i < totalQuestions; ++i) {
try {
double correctValue = questionGenerator.calculateCorrectAnswer(questions[i]);
// 生成选项并保存
std::vector<std::wstring> options = questionGenerator.generateMeaningfulOptions(correctValue);
questionOptions.push_back(options);
// 找到正确答案的索引
int correctIndex = 0;
bool found = false;
for (size_t j = 0; j < options.size(); ++j) {
try {
double optionValue = std::stod(options[j]);
if (std::abs(optionValue - correctValue) < 0.0001) {
correctIndex = static_cast<int>(j);
found = true;
break;
}
} catch (...) {
// 如果转换失败,使用字符串比较
std::stringstream oss;
oss << std::fixed << std::setprecision(6) << correctValue;
std::string correctStr = oss.str();
std::wstring wcorrectStr(correctStr.begin(), correctStr.end());
if (options[j] == wcorrectStr) {
correctIndex = static_cast<int>(j);
found = true;
break;
}
}
}
if (!found) {
qDebug() << "警告:未找到第" << i << "题的正确答案在选项中";
}
correctAnswers.push_back(correctIndex);
qDebug() << "ExamWidget: 第" << i << "题正确答案:" << correctValue << "索引:" << correctIndex;
} catch (const std::exception& e) {
qDebug() << "ExamWidget: 计算第" << i << "题答案异常:" << e.what();
correctAnswers.push_back(0); // 默认第一个选项为正确答案
questionOptions.push_back({L"1.000000", L"2.000000", L"3.000000", L"4.000000"});
}
}
showQuestion(0);
updateButtonStates(); // 更新按钮状态
qDebug() << "ExamWidget: 考试初始化完成";
} catch (const std::exception& e) {
qDebug() << "ExamWidget: 开始考试异常:" << e.what();
QMessageBox::critical(this, "错误", QString("考试初始化失败: %1").arg(e.what()));
}
}
void ExamWidget::showQuestion(int index)
{
if (index < totalQuestions) {
currentQuestion = index;
progressLabel->setText(QString("第 %1 题 / 共 %2 题").arg(index + 1).arg(totalQuestions));
// 显示题目
QString questionText = QString::fromStdWString(questions[index]);
questionLabel->setText(questionText);
// 设置选项文本 - 使用预先生成的选项
if (static_cast<size_t>(index) < questionOptions.size()) {
for (int i = 0; i < 4; ++i) {
if (i < static_cast<int>(questionOptions[index].size())) {
optionButtons[i]->setText(QString::fromStdWString(questionOptions[index][i]));
} else {
optionButtons[i]->setText(QString("选项 %1").arg(i + 1));
}
}
}
// 清除选择
optionGroup->setExclusive(false);
for (int i = 0; i < 4; ++i) {
optionButtons[i]->setChecked(false);
}
optionGroup->setExclusive(true);
// 恢复之前的选择(如果有)
if (static_cast<size_t>(index) < userAnswers.size()) {
int previousAnswer = userAnswers[index];
if (previousAnswer >= 0 && previousAnswer < 4) {
optionButtons[previousAnswer]->setChecked(true);
}
}
// 更新按钮状态
updateButtonStates();
}
}
void ExamWidget::updateButtonStates()
{
// 更新上一题按钮状态
previousButton->setEnabled(currentQuestion > 0);
// 更新下一题和提交按钮状态
nextButton->setVisible(currentQuestion < totalQuestions - 1);
submitButton->setVisible(currentQuestion == totalQuestions - 1);
}
void ExamWidget::generateOptions()
{
// 这个方法现在不再使用因为选项在startExam中已经预生成
// 保留这个方法是为了保持接口兼容性
}
void ExamWidget::onPreviousClicked()
{
// 保存当前答案
int selected = optionGroup->checkedId();
if (selected != -1) {
if (static_cast<size_t>(currentQuestion) >= userAnswers.size()) {
userAnswers.resize(currentQuestion + 1);
}
userAnswers[currentQuestion] = selected;
}
// 显示上一题
if (currentQuestion > 0) {
showQuestion(currentQuestion - 1);
}
}
void ExamWidget::onNextClicked()
{
int selected = optionGroup->checkedId();
if (selected == -1) {
QMessageBox::warning(this, "提示", "请选择一个答案");
return;
}
// 保存当前答案
if (static_cast<size_t>(currentQuestion) >= userAnswers.size()) {
userAnswers.resize(currentQuestion + 1);
}
userAnswers[currentQuestion] = selected;
showQuestion(currentQuestion + 1);
}
void ExamWidget::onSubmitClicked()
{
int selected = optionGroup->checkedId();
if (selected == -1) {
QMessageBox::warning(this, "提示", "请选择一个答案");
return;
}
// 保存最后一题的答案
if (static_cast<size_t>(currentQuestion) >= userAnswers.size()) {
userAnswers.resize(currentQuestion + 1);
}
userAnswers[currentQuestion] = selected;
// 计算分数 - 使用预先生成的选项进行比较
int score = 0;
for (size_t i = 0; i < userAnswers.size(); ++i) {
if (i < correctAnswers.size() && i < questionOptions.size()) {
if (userAnswers[i] >= 0 && userAnswers[i] < static_cast<int>(questionOptions[i].size())) {
std::wstring selectedOption = questionOptions[i][userAnswers[i]];
try {
double selectedValue = std::stod(selectedOption);
double correctValue = questionGenerator.calculateCorrectAnswer(questions[i]);
qDebug() << "" << i << "题 - 选择值:" << selectedValue
<< "正确答案:" << correctValue
<< "差值:" << std::abs(selectedValue - correctValue);
if (std::abs(selectedValue - correctValue) < 1e-5) {
score++;
qDebug() << "" << i << "题回答正确";
} else {
qDebug() << "" << i << "题回答错误,选择值:" << selectedValue
<< "正确答案:" << correctValue;
}
} catch (const std::exception& e) {
qDebug() << "" << i << "题数值转换异常:" << e.what();
// 回退到索引比较
if (userAnswers[i] == correctAnswers[i]) {
score++;
qDebug() << "" << i << "题通过索引比较回答正确";
} else {
qDebug() << "" << i << "题通过索引比较回答错误";
}
}
} else {
qDebug() << "" << i << "题用户答案索引越界:" << userAnswers[i];
}
} else {
qDebug() << "" << i << "题数据不完整";
}
}
qDebug() << "ExamWidget: 考试完成,分数:" << score << "/" << totalQuestions;
emit examFinished(score, totalQuestions);
}

@ -9,6 +9,8 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <vector>
#include <sstream>
#include <iomanip>
#include "questiongenerator.h"
#include "user.h"
@ -25,16 +27,19 @@ signals:
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;
@ -42,6 +47,8 @@ private:
std::vector<std::wstring> questions;
std::vector<int> userAnswers;
std::vector<int> correctAnswers;
std::vector<std::vector<std::wstring>> questionOptions;
int currentQuestion;
int totalQuestions;
};

@ -1,4 +1,9 @@
#include "loginwidget.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QDebug>
#include <QApplication>
LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent)
{
@ -31,7 +36,11 @@ LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent)
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 {"
@ -60,6 +69,31 @@ LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent)
"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);
@ -68,12 +102,18 @@ LoginWidget::LoginWidget(QWidget *parent) : QWidget(parent)
layout->addWidget(passwordLabel);
layout->addWidget(passwordEdit);
layout->addSpacing(30);
layout->addWidget(loginButton);
layout->addWidget(registerButton);
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()
@ -81,6 +121,8 @@ void LoginWidget::onLoginClicked()
QString username = usernameEdit->text().trimmed();
QString password = passwordEdit->text();
qDebug() << "LoginWidget: 尝试登录,用户名:" << username;
if (username.isEmpty() || password.isEmpty()) {
QMessageBox::warning(this, "输入错误", "请输入用户名和密码");
return;
@ -89,13 +131,23 @@ void LoginWidget::onLoginClicked()
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();
}

@ -24,6 +24,9 @@ private slots:
void onLoginClicked();
void onRegisterClicked();
public slots:
void clearInputs();
private:
QLineEdit *usernameEdit; // 改为用户名输入
QLineEdit *passwordEdit;

@ -1,17 +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();
}

@ -1,5 +1,6 @@
#include "mainmenuwidget.h"
#include <QMessageBox>
#include <QDebug>
MainMenuWidget::MainMenuWidget(QWidget *parent) : QWidget(parent)
{
@ -53,8 +54,8 @@ MainMenuWidget::MainMenuWidget(QWidget *parent) : QWidget(parent)
QLabel *countLabel = new QLabel("题目数量:");
countLabel->setStyleSheet("font-size: 14px;");
questionCountSpinBox = new QSpinBox();
questionCountSpinBox->setRange(10, 30);
questionCountSpinBox->setValue(15);
questionCountSpinBox->setRange(5, 30);
questionCountSpinBox->setValue(10);
questionCountSpinBox->setStyleSheet("padding: 8px; font-size: 14px;");
countLayout->addWidget(countLabel);
countLayout->addWidget(questionCountSpinBox);
@ -75,11 +76,50 @@ MainMenuWidget::MainMenuWidget(QWidget *parent) : QWidget(parent)
"}");
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(startButton, 0, Qt::AlignCenter);
settingsLayout->addWidget(buttonWidget);
// 添加到主布局
mainLayout->addWidget(titleLabel);
@ -91,16 +131,19 @@ MainMenuWidget::MainMenuWidget(QWidget *parent) : QWidget(parent)
// 连接信号槽
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")
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) {
@ -108,8 +151,32 @@ void MainMenuWidget::setUserInfo(const std::wstring& username, const std::wstrin
}
}
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: 用户取消退出登录";
}
}

@ -17,12 +17,15 @@ class MainMenuWidget : public QWidget
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;
@ -30,6 +33,7 @@ private:
QComboBox *gradeComboBox;
QSpinBox *questionCountSpinBox;
QPushButton *startButton;
QPushButton *logoutButton; // 新增:退出登录按钮
};
#endif

@ -0,0 +1,203 @@
#include "mainwindow.h"
#include <QMessageBox>
#include <QTimer>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), currentUser(nullptr)
{
setWindowTitle("中小学数学学习软件");
setMinimumSize(600, 700);
resize(600, 700);
qDebug() << "MainWindow: 初始化开始";
// 创建堆叠窗口
stackedWidget = new QStackedWidget(this);
setCentralWidget(stackedWidget);
// 创建各个界面
loginWidget = new LoginWidget();
registerWidget = new RegisterWidget();
mainMenuWidget = new MainMenuWidget();
examWidget = new ExamWidget();
resultWidget = new ResultWidget();
qDebug() << "MainWindow: 所有界面创建完成";
// 添加到堆叠窗口
stackedWidget->addWidget(loginWidget);
stackedWidget->addWidget(registerWidget);
stackedWidget->addWidget(mainMenuWidget);
stackedWidget->addWidget(examWidget);
stackedWidget->addWidget(resultWidget);
// 连接信号槽
connect(loginWidget, &LoginWidget::loginSuccess, this, &MainWindow::onUserLoggedIn);
connect(loginWidget, &LoginWidget::showRegister, this, &MainWindow::showRegister);
connect(registerWidget, &RegisterWidget::showLogin, this, &MainWindow::showLogin);
connect(registerWidget, &RegisterWidget::registerSuccess, this, &MainWindow::onRegisterSuccess);
connect(mainMenuWidget, &MainMenuWidget::startExam, this, &MainWindow::showExam);
connect(mainMenuWidget, &MainMenuWidget::logoutRequested, this, &MainWindow::onLogoutRequested); // 新增连接
connect(examWidget, &ExamWidget::examFinished, this, &MainWindow::showResult);
connect(resultWidget, &ResultWidget::backToMenu, this, &MainWindow::showMainMenu);
connect(resultWidget, &ResultWidget::startNewExam, this, &MainWindow::showMainMenu);
qDebug() << "MainWindow: 信号连接完成";
// 显示登录界面
showLogin();
}
MainWindow::~MainWindow()
{
qDebug() << "MainWindow: 析构函数调用";
}
void MainWindow::showLogin()
{
qDebug() << "MainWindow: 切换到登录界面";
stackedWidget->setCurrentWidget(loginWidget);
setWindowTitle("中小学数学学习软件 - 登录");
}
void MainWindow::showRegister()
{
qDebug() << "MainWindow: 切换到注册界面";
stackedWidget->setCurrentWidget(registerWidget);
setWindowTitle("中小学数学学习软件 - 注册");
}
void MainWindow::showMainMenu()
{
qDebug() << "MainWindow: 切换到主菜单";
if (currentUser) {
mainMenuWidget->setUserInfo(currentUser->getUsername(),
currentUser->getGradeString());
stackedWidget->setCurrentWidget(mainMenuWidget);
setWindowTitle("中小学数学学习软件 - 主菜单");
} else {
qDebug() << "MainWindow: 当前用户为空,跳转到登录界面";
QMessageBox::warning(this, "会话过期", "用户会话已过期,请重新登录");
showLogin();
}
}
void MainWindow::showExam(int questionCount)
{
qDebug() << "MainWindow: 开始考试,题目数量:" << questionCount;
if (currentUser) {
// 从主菜单获取当前选择的年级,而不是用户注册时的年级
QString selectedGrade = mainMenuWidget->getSelectedGrade();
qDebug() << "MainWindow: 用户注册年级:" << QString::fromStdWString(currentUser->getGradeString())
<< "选择的年级:" << selectedGrade;
// 根据选择的年级设置考试难度
Grade examGrade = Grade::PRIMARY; // 默认小学
if (selectedGrade == "小学") {
examGrade = Grade::PRIMARY;
} else if (selectedGrade == "初中") {
examGrade = Grade::JUNIOR;
} else if (selectedGrade == "高中") {
examGrade = Grade::SENIOR;
}
qDebug() << "MainWindow: 实际考试年级:" << static_cast<int>(examGrade);
examWidget->startExam(examGrade, questionCount);
stackedWidget->setCurrentWidget(examWidget);
setWindowTitle("中小学数学学习软件 - 考试中");
} else {
qDebug() << "MainWindow: 考试时用户未登录";
QMessageBox::warning(this, "错误", "用户未登录,请重新登录");
showLogin();
}
}
void MainWindow::showResult(int score, int total)
{
qDebug() << "MainWindow: 显示考试结果,分数:" << score << "/" << total;
resultWidget->setResult(score, total);
stackedWidget->setCurrentWidget(resultWidget);
setWindowTitle("中小学数学学习软件 - 考试结果");
// 保存考试记录
if (currentUser) {
bool saved = FileSaver::saveExamRecord(currentUser->getUsername(),
currentUser->getGradeString(),
score, total,
FileSaver::getCurrentTime());
if (saved) {
qDebug() << "MainWindow: 考试记录保存成功";
} else {
qDebug() << "MainWindow: 考试记录保存失败";
}
}
}
void MainWindow::onUserLoggedIn(User* user)
{
qDebug() << "MainWindow: 用户登录成功";
if (user) {
currentUser = user;
QString username = QString::fromStdWString(user->getUsername());
QString grade = QString::fromStdWString(user->getGradeString());
qDebug() << "MainWindow: 登录用户:" << username << "年级:" << grade;
QMessageBox::information(this, "登录成功",
QString("欢迎 %1\n年级:%2")
.arg(username)
.arg(grade));
showMainMenu();
} else {
qDebug() << "MainWindow: 用户信息无效";
QMessageBox::warning(this, "登录失败", "用户信息无效");
showLogin();
}
}
void MainWindow::onRegisterSuccess()
{
qDebug() << "MainWindow: 注册成功,准备跳转到登录界面";
// 注册成功后显示登录界面,并显示成功提示
QMessageBox::information(this, "注册成功", "注册成功!请使用新账号登录");
// 清空登录界面的输入框
if (loginWidget) {
loginWidget->clearInputs();
}
qDebug() << "MainWindow: 清空登录界面输入框完成";
// 立即切换到登录界面
showLogin();
qDebug() << "MainWindow: 已切换到登录界面";
}
void MainWindow::onLogoutRequested()
{
qDebug() << "MainWindow: 处理退出登录请求";
// 清除当前用户信息
if (currentUser) {
QString username = QString::fromStdWString(currentUser->getUsername());
qDebug() << "MainWindow: 用户" << username << "退出登录";
currentUser = nullptr;
}
// 清空登录界面的输入框
if (loginWidget) {
loginWidget->clearInputs();
}
// 显示登录界面
showLogin();
QMessageBox::information(this, "退出成功", "您已成功退出登录");
}

@ -27,6 +27,7 @@ private slots:
void showResult(int score, int total);
void onUserLoggedIn(User* user);
void onRegisterSuccess();
void onLogoutRequested(); // 新增:处理退出登录
private:
QStackedWidget *stackedWidget;

@ -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

@ -4,6 +4,8 @@
#include <QGridLayout>
#include <QRandomGenerator>
#include <QTime>
#include <QTimer>
#include <QDebug>
RegisterWidget::RegisterWidget(QWidget *parent) : QWidget(parent), countdownSeconds(0)
{
@ -69,7 +71,7 @@ RegisterWidget::RegisterWidget(QWidget *parent) : QWidget(parent), countdownSeco
QLabel *usernameLabel = new QLabel("用户名:");
usernameLabel->setStyleSheet("font-size: 14px; font-weight: bold;");
usernameEdit = new QLineEdit();
usernameEdit->setPlaceholderText("请输入用户名2-20个字符");
usernameEdit->setPlaceholderText("请输入用户名2-20个字符,建议使用英文");
usernameEdit->setMinimumHeight(35);
usernameEdit->setStyleSheet("QLineEdit { padding: 8px; font-size: 14px; border: 1px solid #bdc3c7; border-radius: 4px; }");
@ -199,26 +201,36 @@ RegisterWidget::RegisterWidget(QWidget *parent) : QWidget(parent), countdownSeco
// 初始状态
resetCountdown();
qDebug() << "RegisterWidget: 初始化完成";
}
void RegisterWidget::onSendCodeClicked()
{
QString email = emailEdit->text().trimmed();
qDebug() << "RegisterWidget: 发送验证码到:" << email;
if (!validateEmail(email)) {
QMessageBox::warning(this, "输入错误", "请输入有效的邮箱地址");
return;
}
// 生成并显示验证码
generatedCode = generateVerificationCode();
// 使用UserManager发送验证码
std::wstring emailW = email.toStdWString();
std::wstring generatedCodeW;
if (userManager.sendVerificationCode(emailW, generatedCodeW)) {
generatedCode = QString::fromStdWString(generatedCodeW);
QMessageBox::information(this, "验证码",
QString("验证码已发送到 %1\n验证码:%2\n(实际项目中会发送到邮箱)")
.arg(email).arg(generatedCode));
QMessageBox::information(this, "验证码已发送",
QString("验证码已发送到 %1\n验证码:%2\n验证码10分钟内有效")
.arg(email).arg(QString::fromStdWString(generatedCodeW)));
// 开始倒计时
startCountdown();
// 开始倒计时
startCountdown();
} else {
QMessageBox::warning(this, "发送失败", "验证码发送失败,请重试");
}
}
void RegisterWidget::onRegisterClicked()
@ -230,6 +242,8 @@ void RegisterWidget::onRegisterClicked()
QString confirmPassword = confirmPasswordEdit->text();
QString grade = gradeComboBox->currentText();
qDebug() << "RegisterWidget: 开始注册,用户名:" << username << "年级:" << grade;
// 验证输入
if (email.isEmpty() || username.isEmpty() || verificationCode.isEmpty() ||
password.isEmpty() || confirmPassword.isEmpty()) {
@ -242,15 +256,12 @@ void RegisterWidget::onRegisterClicked()
return;
}
// 验证验证码
if (verificationCode != generatedCode) {
QMessageBox::warning(this, "验证错误", "验证码错误");
return;
}
// 验证验证码 - 使用UserManager验证
std::wstring emailW = email.toStdWString();
std::wstring codeW = verificationCode.toStdWString();
// 检查验证码是否过期
if (countdownSeconds <= 0) {
QMessageBox::warning(this, "验证错误", "验证码已过期,请重新获取");
if (!userManager.verifyEmailCode(emailW, codeW)) {
QMessageBox::warning(this, "验证错误", "验证码错误或已过期");
return;
}
@ -271,12 +282,29 @@ void RegisterWidget::onRegisterClicked()
return;
}
// 实际注册用户
UserManager userManager;
if (userManager.registerUser(username.toStdWString(),
// 实际注册用户 - 使用安全的用户名避免编码问题
std::wstring safeUsername;
for (QChar ch : username) {
if (ch.isLetterOrNumber() || ch == '_') {
safeUsername += ch.unicode();
}
}
// 如果用户名不合法,生成一个随机用户名
if (safeUsername.empty()) {
safeUsername = L"user" + std::to_wstring(1000 + (std::rand() % 9000));
qDebug() << "RegisterWidget: 生成随机用户名:" << QString::fromStdWString(safeUsername);
}
qDebug() << "RegisterWidget: 尝试注册用户:" << QString::fromStdWString(safeUsername);
if (userManager.registerUser(safeUsername,
password.toStdWString(),
grade.toStdWString())) {
QMessageBox::information(this, "注册成功", "注册成功!");
qDebug() << "RegisterWidget: 注册成功";
QMessageBox::information(this, "注册成功",
QString("注册成功!\n用户名: %1\n请使用新账号登录")
.arg(QString::fromStdWString(safeUsername)));
// 重置表单
emailEdit->clear();
@ -286,14 +314,23 @@ void RegisterWidget::onRegisterClicked()
confirmPasswordEdit->clear();
resetCountdown();
qDebug() << "RegisterWidget: 发射注册成功信号";
// 发射信号
emit registerSuccess();
emit showLogin();
qDebug() << "RegisterWidget: 信号发射完成";
} else {
qDebug() << "RegisterWidget: 注册失败";
QMessageBox::warning(this, "注册失败", "用户名已存在,请选择其他用户名");
}
}
void RegisterWidget::onBackClicked()
{
qDebug() << "RegisterWidget: 返回登录";
resetCountdown();
emit showLogin();
}
@ -320,27 +357,13 @@ bool RegisterWidget::validateEmail(const QString &email)
return emailRegex.match(email).hasMatch();
}
QString RegisterWidget::generateVerificationCode()
{
const QString possibleChars = "0123456789";
QString code;
// 使用传统的随机数生成
qsrand(QTime::currentTime().msec());
for (int i = 0; i < 6; ++i) {
int index = qrand() % possibleChars.length();
code.append(possibleChars.at(index));
}
return code;
}
void RegisterWidget::startCountdown()
{
countdownSeconds = 300; // 5分钟
countdownSeconds = 600; // 10分钟
sendCodeButton->setEnabled(false);
updateTimer();
countdownTimer->start();
qDebug() << "RegisterWidget: 开始倒计时10分钟";
}
void RegisterWidget::resetCountdown()
@ -350,6 +373,7 @@ void RegisterWidget::resetCountdown()
sendCodeButton->setEnabled(true);
timerLabel->clear();
generatedCode.clear();
qDebug() << "RegisterWidget: 重置倒计时";
}
void RegisterWidget::updateTimer()

@ -13,6 +13,7 @@
#include <QRandomGenerator>
#include <QHBoxLayout>
#include <QGridLayout>
#include "usermanage.h"
class RegisterWidget : public QWidget
{
@ -47,9 +48,10 @@ private:
int countdownSeconds;
QString generatedCode;
UserManager userManager; // 添加用户管理器
bool validatePassword(const QString &password);
bool validateEmail(const QString &email);
QString generateVerificationCode();
void startCountdown();
void resetCountdown();
};

@ -1,99 +0,0 @@
#include "mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), currentUser(nullptr)
{
setWindowTitle("中小学数学学习软件");
setMinimumSize(600, 700);
resize(600, 700);
// 创建堆叠窗口
stackedWidget = new QStackedWidget(this);
setCentralWidget(stackedWidget);
// 创建各个界面
loginWidget = new LoginWidget();
registerWidget = new RegisterWidget();
mainMenuWidget = new MainMenuWidget();
examWidget = new ExamWidget();
resultWidget = new ResultWidget();
// 添加到堆叠窗口
stackedWidget->addWidget(loginWidget);
stackedWidget->addWidget(registerWidget);
stackedWidget->addWidget(mainMenuWidget);
stackedWidget->addWidget(examWidget);
stackedWidget->addWidget(resultWidget);
// 连接信号槽
connect(loginWidget, &LoginWidget::loginSuccess, this, &MainWindow::onUserLoggedIn);
connect(loginWidget, &LoginWidget::showRegister, this, &MainWindow::showRegister);
connect(registerWidget, &RegisterWidget::showLogin, this, &MainWindow::showLogin);
connect(registerWidget, &RegisterWidget::registerSuccess, this, &MainWindow::onRegisterSuccess);
connect(mainMenuWidget, &MainMenuWidget::startExam, this, &MainWindow::showExam);
connect(examWidget, &ExamWidget::examFinished, this, &MainWindow::showResult);
connect(resultWidget, &ResultWidget::backToMenu, this, &MainWindow::showMainMenu);
connect(resultWidget, &ResultWidget::startNewExam, this, &MainWindow::showMainMenu);
// 显示登录界面
showLogin();
}
MainWindow::~MainWindow()
{
}
void MainWindow::showLogin()
{
stackedWidget->setCurrentWidget(loginWidget);
}
void MainWindow::showRegister()
{
stackedWidget->setCurrentWidget(registerWidget);
}
void MainWindow::showMainMenu()
{
if (currentUser) {
mainMenuWidget->setUserInfo(currentUser->getUsername(),
currentUser->getGradeString());
stackedWidget->setCurrentWidget(mainMenuWidget);
}
}
void MainWindow::showExam(int questionCount)
{
if (currentUser) {
examWidget->startExam(currentUser->getGrade(), questionCount);
stackedWidget->setCurrentWidget(examWidget);
}
}
void MainWindow::showResult(int score, int total)
{
resultWidget->setResult(score, total);
stackedWidget->setCurrentWidget(resultWidget);
// 保存考试记录
if (currentUser) {
FileSaver::saveExamRecord(currentUser->getUsername(),
currentUser->getGradeString(),
score, total,
FileSaver::getCurrentTime());
}
}
void MainWindow::onUserLoggedIn(User* user)
{
currentUser = user;
showMainMenu();
}
void MainWindow::onRegisterSuccess()
{
// 注册成功后显示登录界面
QMessageBox::information(this, "注册成功", "注册成功,请登录");
showLogin();
}
Loading…
Cancel
Save