package com.personalproject.ui.views; import com.personalproject.controller.MathLearningController; import com.personalproject.model.ExamSession; import com.personalproject.model.QuizQuestion; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.stage.Stage; /** * 提供答题界面以及题目与选项的呈现. */ public class ExamView extends BorderPane { private final Stage primaryStage; private final MathLearningController controller; private final ExamSession examSession; private Label questionNumberLabel; private Label questionTextLabel; private ToggleGroup answerToggleGroup; private VBox optionsBox; private Button nextButton; private Button previousButton; private Button finishButton; private HBox buttonBox; /** * ExamView 的构造函数. * * @param primaryStage 应用程序的主舞台 * @param controller 数学学习控制器 * @param examSession 当前的考试会话 */ public ExamView(Stage primaryStage, MathLearningController controller, ExamSession examSession) { this.primaryStage = primaryStage; this.controller = controller; this.examSession = examSession; initializeUi(); } /** * 初始化界面组件. */ private void initializeUi() { // 创建主布局 VBox mainLayout = new VBox(20); mainLayout.setAlignment(Pos.CENTER); mainLayout.setPadding(new Insets(20)); // 题号 questionNumberLabel = new Label(); questionNumberLabel.setFont(Font.font("System", FontWeight.BOLD, 16)); // 题目文本 questionTextLabel = new Label(); questionTextLabel.setWrapText(true); questionTextLabel.setFont(Font.font("System", FontWeight.NORMAL, 14)); questionTextLabel.setMaxWidth(500); // 选项容器 optionsBox = new VBox(10); optionsBox.setPadding(new Insets(10)); answerToggleGroup = new ToggleGroup(); // 按钮区域 buttonBox = new HBox(15); buttonBox.setAlignment(Pos.CENTER); previousButton = new Button("上一题"); nextButton = new Button("下一题"); finishButton = new Button("完成考试"); // 设置按钮尺寸 previousButton.setPrefSize(100, 35); nextButton.setPrefSize(100, 35); finishButton.setPrefSize(120, 35); buttonBox.getChildren().addAll(previousButton, nextButton, finishButton); // 将组件添加到主布局 mainLayout.getChildren().addAll(questionNumberLabel, questionTextLabel, optionsBox, buttonBox); // 将主布局置于边界面板中央 setCenter(mainLayout); // 加载第一题 loadCurrentQuestion(); // 添加事件处理器 addEventHandlers(); } /** * 将当前题目加载到界面. */ private void loadCurrentQuestion() { try { // 在加载下一题之前检查考试是否已完成 if (examSession.isComplete()) { // 如果考试已完成,则启用“完成考试”按钮 updateButtonStates(); return; } QuizQuestion currentQuestion = examSession.getCurrentQuestion(); int currentIndex = examSession.getCurrentQuestionIndex(); if (currentQuestion == null) { showAlert(Alert.AlertType.ERROR, "错误", "当前题目为空,请重新开始考试"); return; } // 更新题号与题目文本 questionNumberLabel.setText("第 " + (currentIndex + 1) + " 题"); questionTextLabel.setText(currentQuestion.getQuestionText()); // 清空上一题的选项 answerToggleGroup.selectToggle(null); answerToggleGroup.getToggles().clear(); optionsBox.getChildren().clear(); // 创建新的选项组件 for (int i = 0; i < currentQuestion.getOptions().size(); i++) { String option = currentQuestion.getOptions().get(i); RadioButton optionButton = new RadioButton((i + 1) + ". " + option); optionButton.setToggleGroup(answerToggleGroup); optionButton.setUserData(i); // 存储选项索引 // 如果该题已有答案则自动选中 if (examSession.hasAnswered(currentIndex) && examSession.getUserAnswer(currentIndex) == i) { optionButton.setSelected(true); } optionsBox.getChildren().add(optionButton); } // 更新按钮状态 updateButtonStates(); } catch (Exception e) { showAlert(Alert.AlertType.ERROR, "错误", "加载题目时发生错误: " + e.getMessage()); } } /** * 根据当前位置更新导航按钮的状态. */ private void updateButtonStates() { try { int currentIndex = examSession.getCurrentQuestionIndex(); int totalQuestions = examSession.getTotalQuestions(); // 处理潜在极端情况 if (totalQuestions <= 0) { // 如果没有题目,则禁用所有导航按钮 previousButton.setDisable(true); nextButton.setDisable(true); finishButton.setDisable(false); // 仍允许完成考试 return; } // “上一题”按钮状态 previousButton.setDisable(currentIndex < 0 || currentIndex == 0); // “下一题”按钮状态 nextButton.setDisable(currentIndex < 0 || currentIndex >= totalQuestions - 1); // “完成考试”按钮状态——在考试完成或到达最后一题时启用 boolean isExamComplete = examSession.isComplete(); boolean isAtLastQuestion = (currentIndex >= totalQuestions - 1); finishButton.setDisable(!(isExamComplete || isAtLastQuestion)); } catch (Exception e) { // 若出现异常,禁用导航按钮以避免进一步问题 previousButton.setDisable(true); nextButton.setDisable(true); finishButton.setDisable(false); // 仍允许完成考试 showAlert(Alert.AlertType.ERROR, "错误", "更新按钮状态时发生错误: " + e.getMessage()); } } /** * 为界面组件添加事件处理器. */ private void addEventHandlers() { nextButton.setOnAction(e -> handleNextQuestion()); previousButton.setOnAction(e -> handlePreviousQuestion()); finishButton.setOnAction(e -> handleFinishExam()); // 添加变更监听器,在选项被选择时保存答案 answerToggleGroup.selectedToggleProperty().addListener((obs, oldSelection, newSelection) -> { if (newSelection != null) { int selectedIndex = (Integer) newSelection.getUserData(); examSession.setAnswer(selectedIndex); } }); } /** * 处理“下一题”按钮的操作. */ private void handleNextQuestion() { try { if (examSession.goToNextQuestion()) { loadCurrentQuestion(); } else { // 若无法跳转到下一题,可能已经到达末尾 // 检查考试是否完成并据此更新按钮状态 updateButtonStates(); } } catch (Exception e) { showAlert(Alert.AlertType.ERROR, "错误", "导航到下一题时发生错误: " + e.getMessage()); } } /** * 处理“上一题”按钮的操作. */ private void handlePreviousQuestion() { try { if (examSession.goToPreviousQuestion()) { loadCurrentQuestion(); } else { // 若无法返回上一题,可能已经位于开头 updateButtonStates(); } } catch (Exception e) { showAlert(Alert.AlertType.ERROR, "错误", "导航到上一题时发生错误: " + e.getMessage()); } } /** * 显示提示对话框. * * @param alertType 提示类型 * @param title 对话框标题 * @param message 显示的消息 */ private void showAlert(Alert.AlertType alertType, String title, String message) { Alert alert = new Alert(alertType); alert.setTitle(title); alert.setHeaderText(null); alert.setContentText(message); alert.showAndWait(); } /** * 处理“完成考试”按钮的操作. */ private void handleFinishExam() { // 保存考试结果 controller.saveExamResults(examSession); // 展示考试结果 ExamResultsView resultsView = new ExamResultsView(primaryStage, controller, examSession); primaryStage.getScene().setRoot(resultsView); } }