并发循环未更新Label:JavaFX GUI实时时钟仅启动时刷新后续无更新
问题原因
- 你自定义的后台任务没有设置循环逻辑,
setTime()方法仅会执行1次,线程跑完就自动终止了,自然不会每秒重复更新时间 - JavaFX UI控件的属性修改*必须在FX Application Thread(UI主线程)*中执行,你在自建的后台线程直接调用
jamdisplay.setText(time)属于非法操作,就算加了循环也大概率会出现界面不更新、甚至抛出运行时异常的问题
最优修复方案(推荐新手使用)
JavaFX官方提供了Timeline组件专门用来做周期性的UI更新,不需要你自己管理线程,踩坑概率极低,修复后的代码如下:
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; import javafx.util.Duration; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.ResourceBundle; public class FXMLDocumentController implements Initializable { @FXML private Label jamdisplay; private SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss"); @Override public void initialize(URL url, ResourceBundle rb) { startTime(); } public void startTime() { // 定义每秒执行一次的更新任务 KeyFrame keyFrame = new KeyFrame(Duration.seconds(1), event -> setTime()); Timeline timeline = new Timeline(keyFrame); // 设置为无限循环执行 timeline.setCycleCount(Timeline.INDEFINITE); timeline.play(); } public void setTime() { String time = timeFormat.format(Calendar.getInstance().getTime()); jamdisplay.setText(time); // 可选的调试打印 System.out.println(jamdisplay.getText()); } }
自定义线程实现的修复方式
如果想要理解线程写法的逻辑,需要改两个核心点:一是给任务加死循环保证持续运行,二是把UI修改的逻辑抛到UI线程执行,代码如下:
import javafx.application.Platform; // 需要额外导入这个类 public void startTime() { Runnable task = new Runnable() { public void run() { // 加死循环保证任务持续执行 while (true) { // UI修改操作必须用Platform.runLater抛到UI线程执行 Platform.runLater(() -> setTime()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); break; } } } }; Thread backgroundThread = new Thread(task); backgroundThread.setDaemon(true); backgroundThread.start(); }
内容的提问来源于stack exchange,提问作者Misudn
相关产品推荐
相关产品推荐

