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

JavaFX定时显示文本/图形问题:数字时钟窗口无显示

解决JavaFX数字时钟不显示的问题

嘿,我一眼就看出你代码里的几个关键问题啦,这就是为什么控制台能输出时间,但窗口里看不到内容的原因:

问题分析

  • 错误的Main实例引用:你在Time类里新建了一个Main main = new Main(),这个Main对象和启动应用时创建的那个Main完全不是同一个!你调用它的displayTime方法时,是把Text加到了一个从未被显示的StackPane里,自然看不到内容。
  • UI线程违规操作:JavaFX的所有UI组件更新必须在JavaFX应用线程中执行,你在自定义的Time线程里直接操作UI,这不仅可能导致不显示,还可能抛出线程安全异常。
  • 重复添加组件:每次调用displayTime都新建一个Text并加到root里,就算显示出来,也会叠满一堆重复的时间文本,体验很差。

修复方案

我给你调整一下代码,解决这几个问题:

核心修复思路

  1. 让Time持有实际运行的Main实例,而不是新建一个
  2. 用Platform.runLater()确保UI操作在JavaFX应用线程执行
  3. 复用一个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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:07:53