From 9d7116793ba04072ff484a7ec7e49bbb24de103a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E9=BB=98=E6=B6=B5?= <15530826+wgll926@user.noreply.gitee.com> Date: Thu, 9 Oct 2025 15:34:16 +0800 Subject: [PATCH] =?UTF-8?q?=E7=95=8C=E9=9D=A2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mathsystemtogether/ExamController.java | 185 ++----------- .../ExamTakingController.java | 257 ++++++++++++++++++ .../mathsystemtogether/exam-taking-view.fxml | 96 +++++++ .../example/mathsystemtogether/exam-view.fxml | 173 ++++-------- 4 files changed, 437 insertions(+), 274 deletions(-) create mode 100644 src/main/java/com/example/mathsystemtogether/ExamTakingController.java create mode 100644 src/main/resources/com/example/mathsystemtogether/exam-taking-view.fxml diff --git a/src/main/java/com/example/mathsystemtogether/ExamController.java b/src/main/java/com/example/mathsystemtogether/ExamController.java index 3bd9d97..d591fc2 100644 --- a/src/main/java/com/example/mathsystemtogether/ExamController.java +++ b/src/main/java/com/example/mathsystemtogether/ExamController.java @@ -1,8 +1,11 @@ package com.example.mathsystemtogether; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.VBox; +import javafx.stage.Stage; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -28,29 +31,6 @@ public class ExamController { @FXML private Button logoutButton; @FXML private Label statusLabel; - // 考试界面控件 - @FXML private VBox examPanel; - @FXML private Label questionNumberLabel; - @FXML private Label questionTextLabel; - @FXML private RadioButton optionA; - @FXML private RadioButton optionB; - @FXML private RadioButton optionC; - @FXML private RadioButton optionD; - @FXML private ToggleGroup answerGroup; - @FXML private Button submitButton; - @FXML private Button nextButton; - @FXML private Label progressLabel; - @FXML private Button exitExamButton; - - // 结果界面控件 - @FXML private VBox resultPanel; - @FXML private Label resultTitleLabel; - @FXML private Label scoreLabel; - @FXML private Label correctCountLabel; - @FXML private Label totalCountLabel; - @FXML private TextArea resultDetailsArea; - @FXML private Button restartButton; - @FXML private Button backToLoginButton; // 数据成员 private Account currentAccount; @@ -68,10 +48,7 @@ public class ExamController { public void initialize() { initAccounts(); setupLevelComboBox(); - setupAnswerGroup(); examSetupPanel.setVisible(false); - examPanel.setVisible(false); - resultPanel.setVisible(false); questionCountField.setText("10"); } @@ -96,13 +73,6 @@ public class ExamController { levelComboBox.setValue("小学"); } - private void setupAnswerGroup() { - answerGroup = new ToggleGroup(); - optionA.setToggleGroup(answerGroup); - optionB.setToggleGroup(answerGroup); - optionC.setToggleGroup(answerGroup); - optionD.setToggleGroup(answerGroup); - } @FXML private void handleLogin() { @@ -136,8 +106,6 @@ public class ExamController { currentQuestionIndex = 0; userAnswers.clear(); examSetupPanel.setVisible(false); - examPanel.setVisible(false); - resultPanel.setVisible(false); usernameField.clear(); passwordField.clear(); loginStatusLabel.setText(""); @@ -184,137 +152,32 @@ public class ExamController { } private void startExam() { - currentQuestionIndex = 0; - userAnswers.clear(); - examSetupPanel.setVisible(false); - examPanel.setVisible(true); - resultPanel.setVisible(false); - displayCurrentQuestion(); - } - - private void displayCurrentQuestion() { - if (currentQuestionIndex >= examQuestions.size()) { - showResults(); - return; - } - - Question question = examQuestions.get(currentQuestionIndex); - questionNumberLabel.setText("第 " + (currentQuestionIndex + 1) + " 题 / 共 " + examQuestions.size() + " 题"); - questionTextLabel.setText(question.getQuestionText()); - - optionA.setText("A. " + question.getOptionA()); - optionB.setText("B. " + question.getOptionB()); - optionC.setText("C. " + question.getOptionC()); - optionD.setText("D. " + question.getOptionD()); - - // 清除之前的选择 - answerGroup.selectToggle(null); - - // 更新按钮状态 - if (currentQuestionIndex == examQuestions.size() - 1) { - submitButton.setText("提交并完成考试"); - nextButton.setVisible(false); - } else { - submitButton.setText("提交答案"); - nextButton.setVisible(true); - } - - progressLabel.setText("进度: " + (currentQuestionIndex + 1) + "/" + examQuestions.size()); - } - - @FXML - private void handleSubmitAnswer() { - RadioButton selectedOption = (RadioButton) answerGroup.getSelectedToggle(); - if (selectedOption == null) { - statusLabel.setText("请选择一个答案"); - statusLabel.setStyle("-fx-text-fill: red;"); - return; - } - - String answer = selectedOption.getText().substring(0, 1); // 获取A、B、C、D - userAnswers.put(currentQuestionIndex, answer); - - if (currentQuestionIndex == examQuestions.size() - 1) { - // 最后一题,显示结果 - showResults(); - } else { - // 下一题 - currentQuestionIndex++; - displayCurrentQuestion(); - } - } - - @FXML - private void handleNextQuestion() { - currentQuestionIndex++; - displayCurrentQuestion(); - } - - @FXML - private void handleExitExam() { - if (showExitConfirmation()) { - examPanel.setVisible(false); - examSetupPanel.setVisible(true); - currentQuestionIndex = 0; - userAnswers.clear(); - } - } - - private boolean showExitConfirmation() { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); - alert.setTitle("确认退出"); - alert.setHeaderText("确定要退出考试吗?"); - alert.setContentText("退出后当前进度将丢失。"); - return alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK; - } - - private void showResults() { - examPanel.setVisible(false); - resultPanel.setVisible(true); - - int correctCount = 0; - StringBuilder resultDetails = new StringBuilder(); - - for (int i = 0; i < examQuestions.size(); i++) { - Question question = examQuestions.get(i); - String userAnswer = userAnswers.get(i); - boolean isCorrect = question.isCorrect(userAnswer); + try { + // 打开专门的考试界面 + FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-taking-view.fxml")); + Scene scene = new Scene(loader.load(), 1000, 950); + Stage examStage = new Stage(); + examStage.setTitle("数学考试 - " + currentAccount.username); + examStage.setScene(scene); + examStage.setResizable(false); - if (isCorrect) { - correctCount++; - } + // 设置考试数据 + ExamTakingController examController = loader.getController(); + examController.setExamData(examQuestions, currentAccount.username, levelComboBox.getValue()); - resultDetails.append("第").append(i + 1).append("题: "); - resultDetails.append(question.getQuestionText()).append("\n"); - resultDetails.append("你的答案: ").append(userAnswer != null ? userAnswer : "未作答").append(" "); - resultDetails.append("正确答案: ").append(question.getCorrectAnswer()).append(" "); - resultDetails.append(isCorrect ? "✓" : "✗").append("\n\n"); + // 显示考试窗口 + examStage.show(); + + // 隐藏主窗口 + Stage mainStage = (Stage) startExamButton.getScene().getWindow(); + mainStage.hide(); + + } catch (Exception e) { + statusLabel.setText("启动考试失败:" + e.getMessage()); + statusLabel.setStyle("-fx-text-fill: red;"); } - - int score = (int) Math.round((double) correctCount / examQuestions.size() * 100); - - resultTitleLabel.setText("考试完成!"); - scoreLabel.setText("得分: " + score + "分"); - correctCountLabel.setText("正确: " + correctCount + "题"); - totalCountLabel.setText("总计: " + examQuestions.size() + "题"); - resultDetailsArea.setText(resultDetails.toString()); } - @FXML - private void handleRestart() { - resultPanel.setVisible(false); - examSetupPanel.setVisible(true); - currentQuestionIndex = 0; - userAnswers.clear(); - } - - @FXML - private void handleBackToLogin() { - resultPanel.setVisible(false); - examSetupPanel.setVisible(false); - examPanel.setVisible(false); - handleLogout(); - } // 内部类 static class Account { diff --git a/src/main/java/com/example/mathsystemtogether/ExamTakingController.java b/src/main/java/com/example/mathsystemtogether/ExamTakingController.java new file mode 100644 index 0000000..f4d9202 --- /dev/null +++ b/src/main/java/com/example/mathsystemtogether/ExamTakingController.java @@ -0,0 +1,257 @@ +package com.example.mathsystemtogether; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.animation.Timeline; +import javafx.animation.KeyFrame; +import javafx.util.Duration; + +import java.util.*; + +/** + * 考试进行界面控制器 + */ +public class ExamTakingController { + + // 界面控件 + @FXML private Label examInfoLabel; + @FXML private Label questionNumberLabel; + @FXML private Label timeLabel; + @FXML private Label questionTextLabel; + @FXML private RadioButton optionA; + @FXML private RadioButton optionB; + @FXML private RadioButton optionC; + @FXML private RadioButton optionD; + @FXML private ToggleGroup answerGroup; + @FXML private Button submitButton; + @FXML private Button nextButton; + @FXML private Button exitExamButton; + @FXML private ProgressBar progressBar; + @FXML private Label progressLabel; + + // 数据成员 + private List examQuestions; + private int currentQuestionIndex = 0; + private Map userAnswers = new HashMap<>(); + private ChoiceQuestionGenerator questionGenerator; + private String username; + private String level; + private int totalQuestions; + private Timeline timer; + private int remainingSeconds; + + @FXML + public void initialize() { + setupAnswerGroup(); + setupTimer(); + } + + private void setupAnswerGroup() { + answerGroup = new ToggleGroup(); + optionA.setToggleGroup(answerGroup); + optionB.setToggleGroup(answerGroup); + optionC.setToggleGroup(answerGroup); + optionD.setToggleGroup(answerGroup); + } + + private void setupTimer() { + // 设置30分钟倒计时 + remainingSeconds = 30 * 60; // 30分钟 = 1800秒 + timer = new Timeline(new KeyFrame(Duration.seconds(1), e -> updateTimer())); + timer.setCycleCount(Timeline.INDEFINITE); + timer.play(); + } + + private void updateTimer() { + remainingSeconds--; + if (remainingSeconds <= 0) { + timer.stop(); + handleTimeUp(); + return; + } + + int minutes = remainingSeconds / 60; + int seconds = remainingSeconds % 60; + timeLabel.setText(String.format("⏰ 剩余时间: %02d:%02d", minutes, seconds)); + } + + private void handleTimeUp() { + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("时间到"); + alert.setHeaderText("考试时间已到!"); + alert.setContentText("系统将自动提交您的答案。"); + alert.showAndWait(); + showResults(); + } + + public void setExamData(List questions, String username, String level) { + this.examQuestions = questions; + this.username = username; + this.level = level; + this.totalQuestions = questions.size(); + + examInfoLabel.setText(String.format("👤 %s | 📚 %s | 📝 %d题", username, level, totalQuestions)); + displayCurrentQuestion(); + updateProgress(); + } + + private void displayCurrentQuestion() { + if (currentQuestionIndex >= examQuestions.size()) { + showResults(); + return; + } + + Question question = examQuestions.get(currentQuestionIndex); + questionNumberLabel.setText(String.format("第 %d 题 / 共 %d 题", + currentQuestionIndex + 1, examQuestions.size())); + questionTextLabel.setText(question.getQuestionText()); + + optionA.setText("A. " + question.getOptionA()); + optionB.setText("B. " + question.getOptionB()); + optionC.setText("C. " + question.getOptionC()); + optionD.setText("D. " + question.getOptionD()); + + // 清除之前的选择 + answerGroup.selectToggle(null); + + // 更新按钮状态 + if (currentQuestionIndex == examQuestions.size() - 1) { + submitButton.setText("✅ 提交并完成考试"); + nextButton.setVisible(false); + } else { + submitButton.setText("✅ 提交答案"); + nextButton.setVisible(true); + } + + updateProgress(); + } + + private void updateProgress() { + double progress = (double) currentQuestionIndex / examQuestions.size(); + progressBar.setProgress(progress); + progressLabel.setText(String.format("进度: %d/%d (%.1f%%)", + currentQuestionIndex + 1, examQuestions.size(), progress * 100)); + } + + @FXML + private void handleSubmitAnswer() { + RadioButton selectedOption = (RadioButton) answerGroup.getSelectedToggle(); + if (selectedOption == null) { + showAlert("请选择一个答案", "请先选择答案再提交"); + return; + } + + String answer = selectedOption.getText().substring(0, 1); // 获取A、B、C、D + userAnswers.put(currentQuestionIndex, answer); + + if (currentQuestionIndex == examQuestions.size() - 1) { + // 最后一题,显示结果 + timer.stop(); + showResults(); + } else { + // 下一题 + currentQuestionIndex++; + displayCurrentQuestion(); + } + } + + @FXML + private void handleNextQuestion() { + currentQuestionIndex++; + displayCurrentQuestion(); + } + + @FXML + private void handleExitExam() { + if (showExitConfirmation()) { + timer.stop(); + returnToMainMenu(); + } + } + + private boolean showExitConfirmation() { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("确认退出"); + alert.setHeaderText("确定要退出考试吗?"); + alert.setContentText("退出后当前进度将丢失。"); + return alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK; + } + + private void showAlert(String title, String message) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle(title); + alert.setHeaderText(null); + alert.setContentText(message); + alert.showAndWait(); + } + + private void showResults() { + try { + // 停止计时器 + timer.stop(); + + // 计算成绩 + int correctCount = 0; + StringBuilder resultDetails = new StringBuilder(); + + for (int i = 0; i < examQuestions.size(); i++) { + Question question = examQuestions.get(i); + String userAnswer = userAnswers.get(i); + boolean isCorrect = question.isCorrect(userAnswer); + + if (isCorrect) { + correctCount++; + } + + resultDetails.append("第").append(i + 1).append("题: "); + resultDetails.append(question.getQuestionText()).append("\n"); + resultDetails.append("你的答案: ").append(userAnswer != null ? userAnswer : "未作答").append(" "); + resultDetails.append("正确答案: ").append(question.getCorrectAnswer()).append(" "); + resultDetails.append(isCorrect ? "✓" : "✗").append("\n\n"); + } + + int score = (int) Math.round((double) correctCount / examQuestions.size() * 100); + + // 显示结果对话框 + Alert resultAlert = new Alert(Alert.AlertType.INFORMATION); + resultAlert.setTitle("考试完成"); + resultAlert.setHeaderText("🎉 考试结果"); + resultAlert.setContentText(String.format( + "得分: %d分\n正确: %d题\n总计: %d题\n正确率: %.1f%%", + score, correctCount, examQuestions.size(), (double) correctCount / examQuestions.size() * 100 + )); + resultAlert.showAndWait(); + + // 返回主菜单 + returnToMainMenu(); + + } catch (Exception e) { + showAlert("错误", "显示结果时出错:" + e.getMessage()); + } + } + + private void returnToMainMenu() { + try { + // 关闭当前窗口 + Stage currentStage = (Stage) submitButton.getScene().getWindow(); + currentStage.close(); + + // 打开主菜单 + FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-view.fxml")); + Scene scene = new Scene(loader.load(), 1000, 900); + Stage stage = new Stage(); + stage.setTitle("数学考试系统"); + stage.setScene(scene); + stage.show(); + + } catch (Exception e) { + showAlert("错误", "返回主菜单时出错:" + e.getMessage()); + } + } +} diff --git a/src/main/resources/com/example/mathsystemtogether/exam-taking-view.fxml b/src/main/resources/com/example/mathsystemtogether/exam-taking-view.fxml new file mode 100644 index 0000000..41c7385 --- /dev/null +++ b/src/main/resources/com/example/mathsystemtogether/exam-taking-view.fxml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/src/main/resources/com/example/mathsystemtogether/exam-view.fxml b/src/main/resources/com/example/mathsystemtogether/exam-view.fxml index abec30f..86e5ffb 100644 --- a/src/main/resources/com/example/mathsystemtogether/exam-view.fxml +++ b/src/main/resources/com/example/mathsystemtogether/exam-view.fxml @@ -4,162 +4,109 @@ + + + - + - + - + -
- + - + - -