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

如何消除JavaFX应用启动时主窗口的闪烁问题?

解决JavaFX启动时Intro视频前的界面闪烁问题

这个问题的核心原因很明确:你现在的代码逻辑是先加载并显示了主界面的所有元素,之后才在控制器初始化阶段创建并启动Intro视频,这中间的时间差就导致了主界面的按钮、文本先露出来半秒,之后视频才覆盖上去,产生闪烁。

下面给你两种直接可行的解决方案,根据你的需求选一个就行:

方案一:先单独播放Intro视频,结束后再加载主界面

这种方式最彻底,完全避免主界面元素提前显示的问题——先把视频作为启动阶段的唯一内容,等视频播放完成(或者淡出后)再切换到主界面。

修改你的主类代码如下:

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage primaryStage) throws Exception {
        try {
            // 初始化Intro视频
            Media introMedia = new Media(getClass().getResource("intro.mp4").toExternalForm());
            MediaPlayer mediaPlayer = new MediaPlayer(introMedia);
            MediaView mediaView = new MediaView(mediaPlayer);
            
            // 让视频铺满整个屏幕
            mediaView.setFitWidth(primaryStage.getScreen().getVisualBounds().getWidth());
            mediaView.setFitHeight(primaryStage.getScreen().getVisualBounds().getHeight());
            mediaView.setSmooth(true);

            // 创建仅包含视频的启动场景
            Scene introScene = new Scene(new StackPane(mediaView));
            primaryStage.setScene(introScene);
            primaryStage.initStyle(StageStyle.UNDECORATED);
            primaryStage.setMaximized(true);
            primaryStage.getIcons().add(new Image("logo-icon.png"));
            primaryStage.show();

            // 视频播放结束后切换到主界面
            mediaPlayer.setOnEndOfMedia(() -> {
                try {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml/card.fxml"));
                    Parent root = loader.load();
                    Scene mainScene = new Scene(root, 1600, 600);
                    mainScene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
                    
                    primaryStage.setScene(mainScene);
                    primaryStage.setResizable(true);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            // 保留你原本的视频淡出效果
            Timeline fadeOutTimeline = new Timeline(
                new KeyFrame(Duration.millis(3000), 
                    new KeyValue(mediaView.opacityProperty(), 0.0)
                )
            );
            fadeOutTimeline.setDelay(Duration.millis(5500));
            fadeOutTimeline.play();

            mediaPlayer.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

同时记得把控制器里的视频相关代码删掉,因为主类已经接管了Intro视频的播放逻辑。

方案二:在同一个界面中先隐藏主元素,视频播放后再显示

如果不想切换场景,也可以在主界面初始化时先把所有内容隐藏,等视频加载播放到合适时机再显示主元素,同时确保视频始终在最上层。

修改你的控制器代码:

@FXML public void initialize(URL location, ResourceBundle resources) {
    // 第一步:先把主内容区域隐藏
    mainAnchor.setVisible(false);

    // 初始化视频
    mp = new MediaPlayer(new Media(this.getClass().getResource(MEDIA_URL).toExternalForm()));
    media.setMediaPlayer(mp);
    media.setSmooth(true);

    // 确保视频准备好后再播放(避免加载延迟)
    mp.setOnReady(mp::play);

    // 视频淡出完成后,隐藏视频并显示主内容
    Timeline tm = new Timeline(
        new KeyFrame(Duration.millis(3000), event -> {
            media.setVisible(false);
            mainAnchor.setVisible(true);
        }, new KeyValue(media.opacityProperty(), 0.0))
    );
    tm.setDelay(Duration.millis(5500));
    tm.play();

    // 你的其他初始化逻辑保持不变
    addQuestionsToArrayCat1();
    addAnswersToArrayCat1();
    addSentencesToArray();
    matchSentences();
}

另外要确保你的FXML中,MediaView的布局层级在mainAnchor之上(比如把它们放在StackPane里,MediaView放在最后一个子节点),这样视频才能完全覆盖主内容,不会漏出。

额外注意点

  • 如果你的Intro视频比较大,加载可能需要时间,可以在视频准备阶段显示一个加载动画(比如ProgressIndicator),避免启动时出现短暂黑屏;
  • 测试时尽量使用本地视频资源,减少网络加载延迟对启动体验的影响。

内容的提问来源于stack exchange,提问作者kentforth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:06:54