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

如何在JFrame的Canvas中绘制JavaFX视频并同时进行绘图操作?

在Swing JFrame中嵌入JavaFX视频并实现绘图功能

要实现把JavaFX视频嵌入Swing的JFrame,同时还能在画布上绘图的需求,核心是利用JFXPanel打通Swing和JavaFX的互操作,再通过分层组件实现视频播放与自定义绘图的共存。下面是完整的实现方案,亲测可用:

第一步:准备工作

确保你的项目已经引入JavaFX相关依赖(JDK11及以上需要手动引入javafx.media、javafx.swing等模块)。

我们的整体思路是:用JFXPanel承载JavaFX的视频播放组件,再在Swing中添加一个透明的绘图面板,让它覆盖在视频上方(或者放在下方,看你的需求),这样就能一边播视频一边绘图了。

第二步:完整可运行代码

import javax.swing.*;
import java.awt.*;
import java.io.File;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;

public class SwingFxVideoDrawer extends JFrame {
    private JFXPanel fxVideoPanel;
    private DrawingOverlay drawingOverlay;
    private MediaPlayer videoPlayer;

    public SwingFxVideoDrawer(File targetVideo) {
        setTitle("视频播放+实时绘图");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);
        setLayout(null); // 用绝对布局方便快速分层,你也可以用BorderLayout这类布局管理器

        // 1. 创建JFXPanel,专门放JavaFX的视频组件
        fxVideoPanel = new JFXPanel();
        fxVideoPanel.setBounds(0, 0, 800, 600);
        add(fxVideoPanel);

        // 2. 创建透明的绘图面板,覆盖在视频上面
        drawingOverlay = new DrawingOverlay();
        drawingOverlay.setBounds(0, 0, 800, 600);
        drawingOverlay.setOpaque(false); // 必须设为透明,不然会挡住下面的视频
        add(drawingOverlay);

        // 3. 必须在JavaFX专属线程里初始化视频组件
        Platform.runLater(() -> setupFxVideo(targetVideo));

        // 确保Swing界面在Event Dispatch Thread启动
        SwingUtilities.invokeLater(() -> setVisible(true));
    }

    // 初始化JavaFX视频播放逻辑
    private void setupFxVideo(File videoFile) {
        Media videoMedia = new Media(videoFile.toURI().toString());
        videoPlayer = new MediaPlayer(videoMedia);
        MediaView videoView = new MediaView(videoPlayer);

        // 让视频自动适配JFXPanel的大小,同时保持比例
        videoView.fitWidthProperty().bind(fxVideoPanel.widthProperty());
        videoView.fitHeightProperty().bind(fxVideoPanel.heightProperty());
        videoView.setPreserveRatio(true);

        StackPane fxRoot = new StackPane(videoView);
        fxVideoPanel.setScene(new Scene(fxRoot));

        // 启动播放
        videoPlayer.play();
    }

    // 自定义绘图面板,重写paintComponent实现绘图逻辑
    private class DrawingOverlay extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // 这里写你的绘图代码,比如画框、文字、图形都可以
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.RED);
            g2d.setStroke(new BasicStroke(3));
            // 画一个红色矩形框
            g2d.drawRect(60, 60, 220, 160);
            // 画一段文字
            g2d.setFont(new Font("微软雅黑", Font.BOLD, 24));
            g2d.drawString("一边看视频一边绘图", 120, 320);
        }
    }

    public static void main(String[] args) {
        // 替换成你的视频文件路径
        File video = new File("your/video/path.mp4");
        new SwingFxVideoDrawer(video);
    }
}

几个关键细节要注意

  • 线程安全:Swing的UI操作必须在Event Dispatch Thread(用SwingUtilities.invokeLater()),JavaFX的操作必须在JavaFX Application Thread(用Platform.runLater()),千万别搞混,不然容易出奇怪的bug。
  • 透明面板:绘图面板一定要设setOpaque(false),不然会完全挡住下面的视频。如果想在视频下面绘图,只需要调换添加组件的顺序(先加绘图面板,再加JFXPanel)。
  • 视频适配:通过绑定MediaView的宽高到JFXPanel的宽高,视频会自动跟着窗口大小变化,还能保持比例,不用手动调整。

适配你现有的ExtVideoPlayer代码

如果你已经有自己的ExtVideoPlayer类,可以修改它来适配Swing嵌入:

// 修改你的ExtVideoPlayer,添加获取MediaView的方法
public class ExtVideoPlayer extends Application {
    private MediaView mediaView;
    private MediaPlayer mediaPlayer;

    @Override
    public void start(Stage stage) {
        // 这里保留你原来的视频初始化逻辑
        // 示例:
        File videoFile = new File("your/video/path.mp4");
        Media media = new Media(videoFile.toURI().toString());
        mediaPlayer = new MediaPlayer(media);
        mediaView = new MediaView(mediaPlayer);
        mediaPlayer.play();

        StackPane root = new StackPane(mediaView);
        stage.setScene(new Scene(root));
        // 不需要显示stage,因为我们要嵌入到Swing里
    }

    // 对外提供MediaView,方便嵌入到JFXPanel
    public MediaView getMediaView() {
        return mediaView;
    }

    public MediaPlayer getMediaPlayer() {
        return mediaPlayer;
    }

    // 给Swing调用的初始化方法,返回播放器实例
    public static ExtVideoPlayer getInitializedPlayer() {
        ExtVideoPlayer player = new ExtVideoPlayer();
        // 单独开线程启动JavaFX Application,避免阻塞Swing线程
        new Thread(() -> Application.launch(player.getClass())).start();
        // 等待MediaView初始化完成
        while (player.getMediaView() == null) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return player;
    }
}

然后在Swing的代码里替换视频初始化部分:

// 把setupFxVideo方法改成这样:
private void setupFxVideo(File videoFile) {
    ExtVideoPlayer fxPlayer = ExtVideoPlayer.getInitializedPlayer();
    MediaView videoView = fxPlayer.getMediaView();
    // 后面的绑定宽高、添加到Scene的逻辑和之前一样
    videoView.fitWidthProperty().bind(fxVideoPanel.widthProperty());
    videoView.fitHeightProperty().bind(fxVideoPanel.heightProperty());
    videoView.setPreserveRatio(true);

    StackPane fxRoot = new StackPane(videoView);
    fxVideoPanel.setScene(new Scene(fxRoot));
}

这样就能把你现有的视频播放器无缝集成到Swing框架里,同时保留绘图功能啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:48:21