diff --git a/src/examwidget.cpp b/src/examwidget.cpp deleted file mode 100644 index b697fd7..0000000 --- a/src/examwidget.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "examwidget.h" -#include -#include -#include -#include - -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(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(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(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); -} diff --git a/src/frontend/examwidget.cpp b/src/frontend/examwidget.cpp new file mode 100644 index 0000000..ab8d906 --- /dev/null +++ b/src/frontend/examwidget.cpp @@ -0,0 +1,376 @@ +#include "examwidget.h" +#include +#include +#include +#include +#include +#include +#include +#include + +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(grade) << "题目数量:" << questionCount; + + questionGenerator.setGrade(grade); + questions = questionGenerator.generateQuestions(questionCount); + totalQuestions = static_cast(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 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(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(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(index) < questionOptions.size()) { + for (int i = 0; i < 4; ++i) { + if (i < static_cast(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(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(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(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(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(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); +} diff --git a/src/examwidget.h b/src/frontend/examwidget.h similarity index 78% rename from src/examwidget.h rename to src/frontend/examwidget.h index f5c90bd..2463d3d 100644 --- a/src/examwidget.h +++ b/src/frontend/examwidget.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include #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 questions; std::vector userAnswers; std::vector correctAnswers; + std::vector> questionOptions; + int currentQuestion; int totalQuestions; }; diff --git a/src/loginwidget.cpp b/src/frontend/loginwidget.cpp similarity index 64% rename from src/loginwidget.cpp rename to src/frontend/loginwidget.cpp index e7a6a87..6a1abb0 100644 --- a/src/loginwidget.cpp +++ b/src/frontend/loginwidget.cpp @@ -1,4 +1,9 @@ #include "loginwidget.h" +#include +#include +#include +#include +#include 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(); +} diff --git a/src/loginwidget.h b/src/frontend/loginwidget.h similarity index 94% rename from src/loginwidget.h rename to src/frontend/loginwidget.h index 9c9d501..87fe657 100644 --- a/src/loginwidget.h +++ b/src/frontend/loginwidget.h @@ -24,6 +24,9 @@ private slots: void onLoginClicked(); void onRegisterClicked(); +public slots: + void clearInputs(); + private: QLineEdit *usernameEdit; // 改为用户名输入 QLineEdit *passwordEdit; diff --git a/src/main.cpp b/src/frontend/main.cpp similarity index 66% rename from src/main.cpp rename to src/frontend/main.cpp index 7b89e2d..e1366fd 100644 --- a/src/main.cpp +++ b/src/frontend/main.cpp @@ -1,17 +1,24 @@ #include +#include #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(); } diff --git a/src/mainmenuwidget.cpp b/src/frontend/mainmenuwidget.cpp similarity index 58% rename from src/mainmenuwidget.cpp rename to src/frontend/mainmenuwidget.cpp index f8cb0b5..3dbf12d 100644 --- a/src/mainmenuwidget.cpp +++ b/src/frontend/mainmenuwidget.cpp @@ -1,5 +1,6 @@ #include "mainmenuwidget.h" #include +#include 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: 用户取消退出登录"; + } +} diff --git a/src/mainmenuwidget.h b/src/frontend/mainmenuwidget.h similarity index 73% rename from src/mainmenuwidget.h rename to src/frontend/mainmenuwidget.h index b1563b1..e4cae4f 100644 --- a/src/mainmenuwidget.h +++ b/src/frontend/mainmenuwidget.h @@ -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 diff --git a/src/frontend/mainwindow.cpp b/src/frontend/mainwindow.cpp new file mode 100644 index 0000000..f3064ad --- /dev/null +++ b/src/frontend/mainwindow.cpp @@ -0,0 +1,203 @@ +#include "mainwindow.h" +#include +#include +#include + +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(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, "退出成功", "您已成功退出登录"); +} diff --git a/src/mainwindow.h b/src/frontend/mainwindow.h similarity index 93% rename from src/mainwindow.h rename to src/frontend/mainwindow.h index 293a82f..4dcb6e3 100644 --- a/src/mainwindow.h +++ b/src/frontend/mainwindow.h @@ -27,6 +27,7 @@ private slots: void showResult(int score, int total); void onUserLoggedIn(User* user); void onRegisterSuccess(); + void onLogoutRequested(); // 新增:处理退出登录 private: QStackedWidget *stackedWidget; diff --git a/src/frontend/mathlearningApp.pro b/src/frontend/mathlearningApp.pro new file mode 100644 index 0000000..dd44b16 --- /dev/null +++ b/src/frontend/mathlearningApp.pro @@ -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 diff --git a/src/registerwidget.cpp b/src/frontend/registerwidget.cpp similarity index 82% rename from src/registerwidget.cpp rename to src/frontend/registerwidget.cpp index 9946c8b..1e20d93 100644 --- a/src/registerwidget.cpp +++ b/src/frontend/registerwidget.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include 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() diff --git a/src/registerwidget.h b/src/frontend/registerwidget.h similarity index 93% rename from src/registerwidget.h rename to src/frontend/registerwidget.h index b49d453..ed5084d 100644 --- a/src/registerwidget.h +++ b/src/frontend/registerwidget.h @@ -13,6 +13,7 @@ #include #include #include +#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(); }; diff --git a/src/resultwidget.cpp b/src/frontend/resultwidget.cpp similarity index 100% rename from src/resultwidget.cpp rename to src/frontend/resultwidget.cpp diff --git a/src/resultwidget.h b/src/frontend/resultwidget.h similarity index 100% rename from src/resultwidget.h rename to src/frontend/resultwidget.h diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp deleted file mode 100644 index a76a040..0000000 --- a/src/mainwindow.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "mainwindow.h" -#include - -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(); -}