JavaFX多Controller间StudentRecord对象数据传递问题排查
问题根源
你当前的代码中,Controller提前加载了一个Controller3实例并设置学生信息,但随后跳转的是scene2;等Controller2完成测验后,又重新加载了一个全新的Controller3实例,这两个实例完全独立,所以之前设置的姓名和ID不会出现在最终的结果页面中。
解决方案
下面提供两种可行的修复方案,你可以根据需求选择:
方案一:链式传递数据(推荐)
通过将学生信息从Controller传递到Controller2,再由Controller2传递给最终的Controller3,保证数据在同一个流程中传递。
1. 修改Controller类(跳转时传递学生信息到Controller2)
删除提前加载scene3的代码,改为加载scene2时获取Controller2实例并传递学生信息:
// 替换Controller中onStartTestButton方法里的跳转代码 if (condition){ // 加载scene2并获取Controller2实例 FXMLLoader loader2 = new FXMLLoader(Objects.requireNonNull(getClass().getResource("scene2.fxml"))); root = loader2.load(); Controller2 controller2 = loader2.getController(); // 传递学生姓名和ID到Controller2 controller2.setStudentInfo(fx_studentName.getText(), Integer.parseInt(fx_studentId.getText())); this.stage = (Stage)((Node) event.getSource()).getScene().getWindow(); this.scene = new Scene(root); String css = Objects.requireNonNull(getClass().getResource("style.css")).toExternalForm(); this.scene.getStylesheets().add(css); this.stage.setScene(this.scene); this.stage.show(); }
2. 修改Controller2类(添加存储学生信息的字段和方法)
添加存储学生信息的字段,以及接收数据的方法,最后跳转时同时传递学生信息和答题数据:
// 在Controller2类中添加以下内容 private String studentName; private int studentId; // 接收Controller传递的学生信息 public void setStudentInfo(String name, int id) { this.studentName = name; this.studentId = id; } // 修改onSubmit方法中的跳转逻辑 if (this.myQuestion.getText().equals(this.backend.getQuestions_list().get(lastQuestionIndex - 1).getQuestion())){ FXMLLoader loader = new FXMLLoader(getClass().getResource("scene3.fxml")); this.root = loader.load(); Controller3 controller3 = loader.getController(); // 先传递学生姓名ID,再传递答题数据 controller3.setStudentNameAndID(this.studentName, this.studentId); controller3.labelInitializers(this.correctAnswers, this.wrongAnswers); this.stage = (Stage) this.myQuestion.getScene().getWindow(); this.scene = new Scene(root); this.stage.setScene(this.scene); this.stage.show(); }
3. 保持Controller3类不变
你的Controller3现有逻辑已经可以正确接收并展示数据,无需修改。
方案二:全局单例存储(简化版)
将StudentRecord设计为单例类,全局共享同一个实例,所有控制器直接操作这个实例的数据。
1. 修改StudentRecord类为单例
public class StudentRecord { // 全局唯一实例 private static StudentRecord instance; private String name; private int id; private int correctAnswers; private int wrongAnswers; // 私有构造,禁止外部创建实例 private StudentRecord() {} // 获取全局实例 public static StudentRecord getInstance() { if (instance == null) { instance = new StudentRecord(); } return instance; } // getter和setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getCorrect_answers() { return correctAnswers; } public void setCorrect_answers(int correctAnswers) { this.correctAnswers = correctAnswers; } public int getWrong_answers() { return wrongAnswers; } public void setWrong_answers(int wrongAnswers) { this.wrongAnswers = wrongAnswers; } }
2. 修改Controller类(设置学生信息到单例)
在跳转scene2前,将学生信息存入单例:
// Controller的onStartTestButton方法中条件满足时 if (condition){ // 存储学生信息到单例 StudentRecord record = StudentRecord.getInstance(); record.setName(fx_studentName.getText()); record.setId(Integer.parseInt(fx_studentId.getText())); // 正常跳转scene2,无需传递参数 this.root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("scene2.fxml"))); this.stage = (Stage)((Node) event.getSource()).getScene().getWindow(); this.scene = new Scene(root); String css = Objects.requireNonNull(getClass().getResource("style.css")).toExternalForm(); this.scene.getStylesheets().add(css); this.stage.setScene(this.scene); this.stage.show(); }
3. 修改Controller2类(设置答题数据到单例)
完成测验后,将答题数据存入单例:
// Controller2的onSubmit方法中跳转逻辑 if (this.myQuestion.getText().equals(this.backend.getQuestions_list().get(lastQuestionIndex - 1).getQuestion())){ // 存储答题数据到单例 StudentRecord record = StudentRecord.getInstance(); record.setCorrect_answers(this.correctAnswers); record.setWrong_answers(this.wrongAnswers); // 跳转scene3 FXMLLoader loader = new FXMLLoader(getClass().getResource("scene3.fxml")); this.root = loader.load(); this.stage = (Stage) this.myQuestion.getScene().getWindow(); this.scene = new Scene(root); this.stage.setScene(this.scene); this.stage.show(); }
4. 修改Controller3类(从单例加载数据)
在initialize方法中直接从单例读取并展示所有数据:
public class Controller3 { @FXML private Label fx_studentName; @FXML private Label fx_studentID; @FXML private Label fx_studentScore; @FXML private Label fx_correctAnswers; @FXML private Label fx_wrongAnswers; @FXML private void initialize(){ StudentRecord record = StudentRecord.getInstance(); fx_studentName.setText("Student name : " + record.getName()); fx_studentID.setText("Student ID: " + record.getId()); fx_correctAnswers.setText("Correct answers: " + record.getCorrect_answers()); fx_wrongAnswers.setText("Wrong answers: " + record.getWrong_answers()); // 简化得分计算:正确题数即为得分 fx_studentScore.setText("Total score: " + record.getCorrect_answers()); } }
方案对比
- 方案一:遵循组件间数据传递的规范,耦合度低,适合中大型应用,便于后续扩展和维护。
- 方案二:实现简单,代码量少,适合小型应用或快速原型开发,但全局单例会带来一定的状态管理风险。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

