You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 21:47:10