JavaFX如何在Timeline倒计时结束时无需按钮触发切换场景
问题原因分析
- 方法参数不匹配:你定义的
startQuiz方法要求传入ActionEvent类型的参数,但Timeline的setOnFinished回调中调用startQuiz()时没有传任何参数,直接触发方法签名不匹配报错。
- 方法参数不匹配:你定义的
- 场景对象未初始化:
startQuiz方法中你已经通过FXMLLoader加载了新界面的根节点,但调用stage.setScene(scene)时使用的scene是全局未初始化的空变量,会触发空指针异常。
- 场景对象未初始化:
- 事件来源不存在:
Timeline完成的回调中没有可直接使用的界面事件对象,你原来通过event.getSource()拿控件的逻辑无法生效,拿不到Stage对象。
- 事件来源不存在:
- 变量命名冲突:
startQuiz方法内重新定义了局部root变量,覆盖了全局定义的root变量,属于不必要的冗余操作。
- 变量命名冲突:
修正后的代码方案
public class countDownScreenController implements Initializable { // 注入FXML中定义的根节点,注意你的倒计时界面FXML根节点要设置fx:id="root" @FXML private Parent root; private Stage stage; private StringProperty timerText; private int timerTotal; private Timeline timeLine; @Override public void initialize(URL url, ResourceBundle resourceBundle) { runTimer(); } public void runTimer(){ timerTotal = 3; setTimerText(timerTotal); timeLine = new Timeline(); timeLine.setCycleCount(timerTotal); timeLine.getKeyFrames().add(new KeyFrame(Duration.seconds(1), e -> { timerTotal--; setTimerText(timerTotal); })); // 先设置完成回调再播放,避免极端情况倒计时过快回调未生效 timeLine.setOnFinished(e -> { try { startQuiz(); } catch (IOException ex) { ex.printStackTrace(); } }); timeLine.play(); } // 去掉ActionEvent参数,改为无参通用方法 public void startQuiz () throws IOException { Parent quizRoot = FXMLLoader.load(getClass().getResource("/fxml/quizScreenScreen.fxml")); // 直接从已注入的当前界面根节点拿Stage stage = (Stage) root.getScene().getWindow(); // 用新加载的界面根节点创建Scene再设置给Stage Scene scene = new Scene(quizRoot); stage.setScene(scene); stage.show(); } // 原有构造、getter、setter逻辑无需调整 public countDownScreenController() { timerText = new SimpleStringProperty(); } public String getTimerText() { return timerText.get(); } public StringProperty timerTextProperty() { return timerText; } public void setTimerText(String timerText) { this.timerText.set(timerText); } public void setTimerText(int remainingSeconds) { int minutes = remainingSeconds / 60; int seconds = remainingSeconds % 60; setTimerText(String.format("%02d:%02d", minutes, seconds)); } // 若需要保留按钮点击触发切换的功能,新增重载方法即可,无需重复写逻辑 @FXML public void startQuiz(ActionEvent event) throws IOException { startQuiz(); } }
额外注意事项
- 必须在倒计时界面的FXML文件根节点上添加属性
fx:id="root",否则@FXML注入的root会为空,触发空指针异常。 - 确认
/fxml/quizScreenScreen.fxml路径正确,注意文件名是否存在拼写错误(当前命名重复写了一次Screen,可核对实际文件名)。
内容的提问来源于stack exchange,提问作者sillyPin
相关产品推荐
相关产品推荐

