本文介绍了在普通 Java 应用程序中使用 JavaFX MediaPlayer 播放音频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我需要能够在普通 Java 项目中播放音频文件 (MP3/Wav).我更喜欢使用新的 JavaFX MediaPlayer 而不是 JMF.我写了一些代码来测试这个:public void play(){URL thing = getClass().getResource("mysound.wav");Media audioFile = new Media( thing.toString() );尝试{MediaPlayer player = new MediaPlayer(audioFile);播放器播放();}捕获(例外 e){System.out.println( e.getMessage() );System.exit(0);}}运行时出现异常:Toolkit not initialized我知道这与 JavaFX 线程有关.我的问题是,我该如何解决这个问题?我是否需要创建一个 JavaFX 面板只是为了在我的普通应用程序的后台播放一些音频文件,还是有其他方法?堆栈跟踪:java.lang.IllegalStateException:工具包未初始化在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:121)在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:116)在 javafx.application.Platform.runLater(Platform.java:52)在 javafx.scene.media.MediaPlayer.init(MediaPlayer.java:445)在 javafx.scene.media.MediaPlayer.(MediaPlayer.java:360)在 javaapplication6.JavaApplication6.play(JavaApplication6.java:23)在 javaapplication6.JavaApplication6.main(JavaApplication6.java:14) 解决方案对于在 Swing 中集成了 JavaFX MediaPlayer 的解决方案使用 JavaFXMediaPlayerLaunchedFromSwing.java此代码负责创建一个 Swing 应用程序,该应用程序反过来初始化 JavaFX 工具包并在 JavaFX 应用程序线程上创建 JavaFX 场景.import javafx.application.Platform;导入 javafx.embed.swing.JFXPanel;导入 javafx.scene.Scene;导入 javax.swing.*;/*** 播放给定目录中所有 mp3 音频文件的示例* 使用从 Swing 启动的 JavaFX MediaView*/公共类 JavaFXMediaPlayerLaunchedFromSwing {私有静态无效 initAndShowGUI() {//该方法在 Swing 线程上调用JFrame frame = new JFrame("FX");最终 JFXPanel fxPanel = 新 JFXPanel();frame.add(fxPanel);frame.setBounds(200, 100, 800, 250);frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);frame.setVisible(true);Platform.runLater(() -> initFX(fxPanel));}私有静态无效initFX(JFXPanel fxPanel){//这个方法是在 JavaFX 线程上调用的场景场景 = new MediaSceneGenerator().createScene();fxPanel.setScene(场景);}公共静态无效主(字符串 [] args){SwingUtilities.invokeLater(JavaFXMediaPlayerLaunchedFromSwing::initAndShowGUI);}}MediaSceneGenerator.java创建一个 JavaFX 媒体播放器,它按顺序播放给定文件夹中的所有 .mp3 媒体文件.它为媒体提供了一些控制(播放、暂停、跳过曲目、当前曲目播放进度指示器).import javafx.application.Platform;导入 javafx.beans.value.ChangeListener;导入 javafx.geometry.Pos;导入 javafx.scene.Scene;导入 javafx.scene.control.*;导入 javafx.scene.layout.*;导入 javafx.scene.layout.VBox;导入 javafx.scene.media.*;导入 javafx.util.Duration;导入 java.io.File;导入 java.util.*;公共类 MediaSceneGenerator {private static final String MUSIC_FOLDER = "C:\Users\Public\Music\Sample Music";private static final String MUSIC_FILE_EXTENSION = ".mp3";私人最终标签当前播放 = 新标签();私人最终 ProgressBar 进度 = 新 ProgressBar();private ChangeListener进度变更监听器;公共场景 createScene() {最终的 StackPane 布局 = new StackPane();//确定播放列表的源目录最终文件目录 = 新文件(MUSIC_FOLDER);如果 (!dir.exists() || !dir.isDirectory()) {System.out.println("找不到媒体源目录:" + dir);Platform.exit();返回空;}//创建一些媒体播放器.最终列表<MediaPlayer>玩家 = 新的 ArrayList();for (String file : Objects.requireNonNull(dir.list((dir1, name) -> name.endsWith(MUSIC_FILE_EXTENSION))))玩家.添加(创建播放器(normalizeFileURL(目录,文件)));如果 (players.isEmpty()) {System.out.println("在" + dir中没有找到音频);Platform.exit();返回空;}//创建一个视图来显示媒体播放器.final MediaView mediaView = new MediaView(players.get(0));final Button skip = new Button("Skip");final Button play = new Button("Pause");//依次播放每个音频文件.for (int i = 0; i {最终 MediaPlayer curPlayer = mediaView.getMediaPlayer();nextPlayer.seek(Duration.ZERO);如果(nextPlayer != curPlayer){curPlayer.currentTimeProperty().removeListener(progressChangeListener);}mediaView.setMediaPlayer(nextPlayer);nextPlayer.play();});}//允许用户跳过曲目.skip.setOnAction(actionEvent -> {最终 MediaPlayer curPlayer = mediaView.getMediaPlayer();MediaPlayer nextPlayer = player.get((players.indexOf(curPlayer) + 1) % player.size());nextPlayer.seek(Duration.ZERO);mediaView.setMediaPlayer(nextPlayer);如果(nextPlayer != curPlayer){curPlayer.currentTimeProperty().removeListener(progressChangeListener);}nextPlayer.play();});//允许用户播放或暂停曲目.play.setOnAction(actionEvent -> {if ("Pause".equals(play.getText())) {mediaView.getMediaPlayer().pause();play.setText("播放");} 别的 {mediaView.getMediaPlayer().play();play.setText("暂停");}});//显示当前播放曲目的名称.mediaView.mediaPlayerProperty().addListener((observableValue, oldPlayer, newPlayer) ->设置当前播放(新播放器));//开始播放第一首曲目.mediaView.setMediaPlayer(players.get(0));mediaView.getMediaPlayer().play();setCurrentlyPlaying(mediaView.getMediaPlayer());//愚蠢的隐形按钮用作模板来获取暂停按钮的实际首选大小.Button invisiblePause = new Button("Pause");invisiblePause.setVisible(false);play.prefHeightProperty().bind(invisiblePause.heightProperty());play.prefWidthProperty().bind(invisiblePause.widthProperty());//布置场景.HBox 控件 = new HBox(10, skip, play, progress);control.setAlignment(Pos.CENTER);VBox mediaPanel = new VBox(10, currentPlaying, mediaView, controls);layout.setStyle("-fx-background-color:cornsilk;-fx-font-size: 20;-fx-padding: 20;-fx-alignment: center;");layout.getChildren().addAll(隐形暂停,媒体面板);progress.setMaxWidth(Double.MAX_VALUE);HBox.setHgrow(progress, Priority.ALWAYS);返回新场景(布局);}/*** 将当前播放的标签设置为新媒体播放器的标签并更新进度监视器.*/私有无效 setCurrentlyPlaying(final MediaPlayer newPlayer) {进度.setProgress(0);progressChangeListener = (observableValue, oldValue, newValue) ->progress.setProgress(1.0 * newPlayer.getCurrentTime().toMillis()/newPlayer.getTotalDuration().toMillis());newPlayer.currentTimeProperty().addListener(progressChangeListener);String source = getUserFriendlyMediaName(newPlayer);currentPlaying.setText("正在播放:" + source);}/*** @return 给定源的 MediaPlayer,它将报告它遇到的任何错误*/私人媒体播放器创建播放器(字符串 aMediaSrc){System.out.println("创建播放器:" + aMediaSrc);最终的 MediaPlayer 播放器 = new MediaPlayer(new Media(aMediaSrc));player.setOnError(() -> System.out.println("发生媒体错误:" + player.getError()));回归玩家;}私人字符串 normalizeFileURL(文件目录,字符串文件){return "file:///" + (dir + "\" + file).replace("\", "/").replaceAll(" ", "%20");}私人字符串 getUserFriendlyMediaName(MediaPlayer newPlayer) {字符串源 = newPlayer.getMedia().getSource();source = source.substring(0, source.length() - MUSIC_FILE_EXTENSION.length());source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " ");返回源;}}如果您只想要一个带有 MediaPlayer 而没有 Swing 的本机 JavaFX 应用程序上面使用 Swing 的解决方案回答了提出的问题.但是,我注意到有时人们会选择这个答案并使用它来创建基于 Java 的媒体播放器,即使他们没有将应用程序嵌入其中的现有 Swing 应用程序.如果您没有现有的 Swing 应用程序,那么请从您的应用程序中完全消除 Swing 代码,并改为编写本机 JavaFX 应用程序.为此,请使用下面的 JavaFXMediaPlayer 类,而不是上面示例中的 JavaFXMediaPlayerLaunchedFromSwing 类.JavaFXMediaPlayerimport javafx.application.Application;导入 javafx.stage.Stage;公共类 JavaFXMediaPlayer 扩展应用程序 {@覆盖公共无效开始(阶段阶段)抛出异常{stage.setScene(new MediaSceneGenerator().createScene());舞台表演();}}回答后续问题一旦我将通过 Swing 构建的 .JAR 文件添加到 netbeans 中的库中,它会自动添加 JavaFX 吗?注意:此后续包装回答中的信息现在可能已经过时,并且此时存在其他首选包装选项(例如 https://github.com/openjfx/javafx-maven-plugin).从技术上讲,Swing 不会构建 Jar 文件,但 javafx 打包命令的 jar 会构建.如果您的应用包含 JavaFX,那么最好使用 JavaFX 封装工具.如果没有它们,您可能会遇到一些部署问题,因为 Java 运行时 jar (jfxrt.jar) 不会自动出现在 jdk7u7 的 java 引导类路径上.用户可以手动将它添加到他们的运行时类路径中,但这可能有点麻烦.在未来的 jdk 版本(可能是 jdk7u10 或 jdk8)中,jfxrt.jar 将位于类路径中.即便如此,仍然建议使用 JavaFX 打包工具,因为它是确保您的部署包以最兼容的方式工作的最佳方式.SwingInterop NetBeans 项目是一个示例 NetBeans 项目它利用 JavaFX 部署工具嵌入 JavaFX 组件的 Swing 项目.SwingInterop 的来源是 JDK 7 和 JavaFX 演示和示例 下载.I need to be able to play Audio files (MP3 / Wav) in a normal Java project. I'd prefer using the new JavaFX MediaPlayer rather than JMF. I wrote some code to test this:public void play(){ URL thing = getClass().getResource("mysound.wav"); Media audioFile = new Media( thing.toString() ); try { MediaPlayer player = new MediaPlayer(audioFile); player.play(); } catch (Exception e) { System.out.println( e.getMessage() ); System.exit(0); }}When I run this, I get the exception: Toolkit not initializedI get that this has something to do with the JavaFX thread. My question is, how can I solve this? Do I need to create a JavaFX Panel just to play some audio files in the background of my normal app, or is there any other way?Edit: Stacktrace:java.lang.IllegalStateException: Toolkit not initialized at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:121) at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:116) at javafx.application.Platform.runLater(Platform.java:52) at javafx.scene.media.MediaPlayer.init(MediaPlayer.java:445) at javafx.scene.media.MediaPlayer.<init>(MediaPlayer.java:360) at javaapplication6.JavaApplication6.play(JavaApplication6.java:23) at javaapplication6.JavaApplication6.main(JavaApplication6.java:14) 解决方案 For a solution with integrates a JavaFX MediaPlayer in SwingUse a JFXPanel and be careful to only use JavaFX objects on the JavaFX thread and after the JavaFX system has been properly initialized.JavaFX is normal Java which makes the question a bit confusing, but I guess you mean Swing.Here's a sample audio player which is launched from Swing. The sample assumes that there are a bunch of mp3 files in the default public sample music folder for Windows 7 (C:UsersPublicMusicSample Music) and plays each file in turn.JavaFXMediaPlayerLaunchedFromSwing.javaThis code is responsible for creating a Swing application which, in turn, initializes the JavaFX toolkit and creates a JavaFX scene on the JavaFX application thread. import javafx.application.Platform;import javafx.embed.swing.JFXPanel;import javafx.scene.Scene;import javax.swing.*;/** * Example of playing all mp3 audio files in a given directory * using a JavaFX MediaView launched from Swing */public class JavaFXMediaPlayerLaunchedFromSwing { private static void initAndShowGUI() { // This method is invoked on Swing thread JFrame frame = new JFrame("FX"); final JFXPanel fxPanel = new JFXPanel(); frame.add(fxPanel); frame.setBounds(200, 100, 800, 250); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setVisible(true); Platform.runLater(() -> initFX(fxPanel)); } private static void initFX(JFXPanel fxPanel) { // This method is invoked on JavaFX thread Scene scene = new MediaSceneGenerator().createScene(); fxPanel.setScene(scene); } public static void main(String[] args) { SwingUtilities.invokeLater( JavaFXMediaPlayerLaunchedFromSwing::initAndShowGUI ); }}MediaSceneGenerator.javaCreates a JavaFX media player which sequentially plays all of the .mp3 media files in a given folder. It provides some controls for the media (play, pause, skip track, current track play progress indicator).import javafx.application.Platform;import javafx.beans.value.ChangeListener;import javafx.geometry.Pos;import javafx.scene.Scene;import javafx.scene.control.*;import javafx.scene.layout.*;import javafx.scene.layout.VBox;import javafx.scene.media.*;import javafx.util.Duration;import java.io.File;import java.util.*;public class MediaSceneGenerator { private static final String MUSIC_FOLDER = "C:\Users\Public\Music\Sample Music"; private static final String MUSIC_FILE_EXTENSION = ".mp3"; private final Label currentlyPlaying = new Label(); private final ProgressBar progress = new ProgressBar(); private ChangeListener<Duration> progressChangeListener; public Scene createScene() { final StackPane layout = new StackPane(); // determine the source directory for the playlist final File dir = new File(MUSIC_FOLDER); if (!dir.exists() || !dir.isDirectory()) { System.out.println("Cannot find media source directory: " + dir); Platform.exit(); return null; } // create some media players. final List<MediaPlayer> players = new ArrayList<>(); for (String file : Objects.requireNonNull(dir.list((dir1, name) -> name.endsWith(MUSIC_FILE_EXTENSION)))) players.add( createPlayer( normalizeFileURL(dir, file) ) ); if (players.isEmpty()) { System.out.println("No audio found in " + dir); Platform.exit(); return null; } // create a view to show the mediaplayers. final MediaView mediaView = new MediaView(players.get(0)); final Button skip = new Button("Skip"); final Button play = new Button("Pause"); // play each audio file in turn. for (int i = 0; i < players.size(); i++) { MediaPlayer player = players.get(i); MediaPlayer nextPlayer = players.get((i + 1) % players.size()); player.setOnEndOfMedia(() -> { final MediaPlayer curPlayer = mediaView.getMediaPlayer(); nextPlayer.seek(Duration.ZERO); if (nextPlayer != curPlayer) { curPlayer.currentTimeProperty().removeListener(progressChangeListener); } mediaView.setMediaPlayer(nextPlayer); nextPlayer.play(); }); } // allow the user to skip a track. skip.setOnAction(actionEvent -> { final MediaPlayer curPlayer = mediaView.getMediaPlayer(); MediaPlayer nextPlayer = players.get((players.indexOf(curPlayer) + 1) % players.size()); nextPlayer.seek(Duration.ZERO); mediaView.setMediaPlayer(nextPlayer); if (nextPlayer != curPlayer) { curPlayer.currentTimeProperty().removeListener(progressChangeListener); } nextPlayer.play(); }); // allow the user to play or pause a track. play.setOnAction(actionEvent -> { if ("Pause".equals(play.getText())) { mediaView.getMediaPlayer().pause(); play.setText("Play"); } else { mediaView.getMediaPlayer().play(); play.setText("Pause"); } }); // display the name of the currently playing track. mediaView.mediaPlayerProperty().addListener( (observableValue, oldPlayer, newPlayer) -> setCurrentlyPlaying(newPlayer) ); // start playing the first track. mediaView.setMediaPlayer(players.get(0)); mediaView.getMediaPlayer().play(); setCurrentlyPlaying(mediaView.getMediaPlayer()); // silly invisible button used as a template to get the actual preferred size of the Pause button. Button invisiblePause = new Button("Pause"); invisiblePause.setVisible(false); play.prefHeightProperty().bind(invisiblePause.heightProperty()); play.prefWidthProperty().bind(invisiblePause.widthProperty()); // layout the scene. HBox controls = new HBox(10, skip, play, progress); controls.setAlignment(Pos.CENTER); VBox mediaPanel = new VBox(10, currentlyPlaying, mediaView, controls); layout.setStyle("-fx-background-color: cornsilk; -fx-font-size: 20; -fx-padding: 20; -fx-alignment: center;"); layout.getChildren().addAll( invisiblePause, mediaPanel ); progress.setMaxWidth(Double.MAX_VALUE); HBox.setHgrow(progress, Priority.ALWAYS); return new Scene(layout); } /** * sets the currently playing label to the label of the new media player and updates the progress monitor. */ private void setCurrentlyPlaying(final MediaPlayer newPlayer) { progress.setProgress(0); progressChangeListener = (observableValue, oldValue, newValue) -> progress.setProgress( 1.0 * newPlayer.getCurrentTime().toMillis() / newPlayer.getTotalDuration().toMillis() ); newPlayer.currentTimeProperty().addListener(progressChangeListener); String source = getUserFriendlyMediaName(newPlayer); currentlyPlaying.setText("Now Playing: " + source); } /** * @return a MediaPlayer for the given source which will report any errors it encounters */ private MediaPlayer createPlayer(String aMediaSrc) { System.out.println("Creating player for: " + aMediaSrc); final MediaPlayer player = new MediaPlayer(new Media(aMediaSrc)); player.setOnError(() -> System.out.println("Media error occurred: " + player.getError())); return player; } private String normalizeFileURL(File dir, String file) { return "file:///" + (dir + "\" + file).replace("\", "/").replaceAll(" ", "%20"); } private String getUserFriendlyMediaName(MediaPlayer newPlayer) { String source = newPlayer.getMedia().getSource(); source = source.substring(0, source.length() - MUSIC_FILE_EXTENSION.length()); source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " "); return source; }}If you just want a native JavaFX application with a MediaPlayer and no SwingThe solution above which uses Swing answers the question asked. However, I have noted that sometimes people have picked up this answer and used it to create Java based media players even when they don't have an existing Swing application that they are embedding their application into.If you don't have an existing Swing application, then eliminate the Swing code completely from your application and write a native JavaFX application instead. To do this, use the JavaFXMediaPlayer class below instead of the class JavaFXMediaPlayerLaunchedFromSwing from the sample above.JavaFXMediaPlayerimport javafx.application.Application;import javafx.stage.Stage;public class JavaFXMediaPlayer extends Application { @Override public void start(Stage stage) throws Exception { stage.setScene(new MediaSceneGenerator().createScene()); stage.show(); }}Answers to follow-up questions Will my .JAR file built via swing automatically have JavaFX added to it once I add it to the libraries in netbeans?Note: info in this follow-up answer on packaging is likely dated now and other preferred packaging options exist at this time (e.g https://github.com/openjfx/javafx-maven-plugin).Technically, Swing doesn't build Jar files but the jar of javafx packaging commands do.If your app contains JavaFX, then, it's best to use the JavaFX packaging tools. Without them, you may have some deployment issues issues as the Java runtime jar (jfxrt.jar) is not automatically on the java boot classpath for jdk7u7. Users can manually add it to their runtime classpath, but it could be a bit of a pain. In future jdk versions (perhaps jdk7u10 or jdk8), jfxrt.jar will be on the classpath. Even then, use of the JavaFX packaging tools would still be recommended as it will be the best way to ensure that your deployment package will work in the most compatible way.The SwingInterop NetBeans project is a sample NetBeans project which utilizes JavaFX deployment tools for a Swing project embedding JavaFX components. Source for SwingInterop is part of the JDK 7 and JavaFX Demos and Samples download. 这篇关于在普通 Java 应用程序中使用 JavaFX MediaPlayer 播放音频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-29 12:54
查看更多