如何在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
相关产品推荐
相关产品推荐

