JavaFX定时显示文本/图形问题:数字时钟窗口无显示
解决JavaFX数字时钟不显示的问题
嘿,我一眼就看出你代码里的几个关键问题啦,这就是为什么控制台能输出时间,但窗口里看不到内容的原因:
问题分析
- 错误的Main实例引用:你在
Time类里新建了一个Main main = new Main(),这个Main对象和启动应用时创建的那个Main完全不是同一个!你调用它的displayTime方法时,是把Text加到了一个从未被显示的StackPane里,自然看不到内容。 - UI线程违规操作:JavaFX的所有UI组件更新必须在JavaFX应用线程中执行,你在自定义的Time线程里直接操作UI,这不仅可能导致不显示,还可能抛出线程安全异常。
- 重复添加组件:每次调用
displayTime都新建一个Text并加到root里,就算显示出来,也会叠满一堆重复的时间文本,体验很差。
修复方案
我给你调整一下代码,解决这几个问题:
核心修复思路
- 让Time持有实际运行的Main实例,而不是新建一个
- 用
Platform.runLater()确保UI操作在JavaFX应用线程执行 - 复用一个Text对象,每次只更新它的文本内容,而非重复添加组件
修改后的完整代码
Main类
import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Scene; import javafx.scene.layout.StackPane; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.stage.WindowEvent; import javafx.event.EventHandler; public class Main extends Application { StackPane root = new StackPane(); Text t1; // 复用这个Text对象 @Override public void start(Stage primaryStage) throws Exception{ root.setStyle("-fx-background-color: #00FF00"); primaryStage.setTitle("My App"); // 初始化Text,设置样式(可选) t1 = new Text("00:00:00"); t1.setStyle("-fx-font-size: 40px; -fx-fill: #000000;"); root.getChildren().add(t1); primaryStage.setScene(new Scene(root, 1000, 800)); primaryStage.show(); // 创建Time时传入当前Main实例 Time time = new Time(this); time.start(); primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent t) { Platform.exit(); System.exit(0); } }); } public static void main(String[] args) { launch(args); } // 更新Text内容,而不是新建组件 public void displayTime(int hour, int minute, int second){ // 格式化时间,确保两位数显示(比如09:05:03) String timeStr = String.format("%02d:%02d:%02d", hour, minute, second); t1.setText(timeStr); } }
Time类
import java.util.Calendar; import javafx.application.Platform; public class Time extends Thread { private final Main main; // 持有正确的Main实例 private Calendar calendar; // 构造方法接收Main实例 public Time(Main main) { this.main = main; } @Override public void run() { while (!Thread.currentThread().isInterrupted()) { try { getTime(); Thread.sleep(1000); } catch (InterruptedException e) { // 捕获中断异常,优雅结束线程 Thread.currentThread().interrupt(); break; } } } private void getTime() { calendar = Calendar.getInstance(); int hour = calendar.get(Calendar.HOUR); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); System.out.println(hour + ":" + minute + ":" + second); // 用Platform.runLater确保UI操作在JavaFX线程执行 Platform.runLater(() -> { main.displayTime(hour, minute, second); }); } }
额外优化建议
- 用
LocalTime替代Calendar:Java 8+的java.time.LocalTime比Calendar更简洁易用,推荐替换。 - 使用
Timeline替代自定义Thread:JavaFX有专门的Timeline组件来处理定时UI更新,比手动管理Thread更符合JavaFX的设计,示例代码如下:
// 在Main的start方法里用Timeline替代Time线程 import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.util.Duration; import java.time.LocalTime; import java.time.format.DateTimeFormatter; // ... 其他代码 ... Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> { LocalTime now = LocalTime.now(); t1.setText(now.format(DateTimeFormatter.ofPattern("hh:mm:ss"))); })); timeline.setCycleCount(Animation.INDEFINITE); timeline.play();
这样就完全不需要自定义Time线程啦,代码更简洁安全。
内容的提问来源于stack exchange,提问作者Marcin Frąckiewicz
相关产品推荐
相关产品推荐

