当前位置: 首页 > 知识库问答 >
问题:

在普通Java应用程序中使用JavaFX MediaPlayer播放音频?

冯开诚
2023-03-14

我需要能够在普通的Java项目中播放音频文件(MP3 / Wav)。我更喜欢使用新的JavaFX MediaPlayer而不是JMF。我写了一些代码来测试这一点:

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);
    }        
}

当我运行它时,我得到异常:Toolkit未初始化

我知道这与JavaFX线程有关。我的问题是,我该如何解决这个问题?我是否需要创建一个JavaFX面板来播放正常应用程序后台的一些音频文件,还是有其他方法

编辑:堆栈跟踪:

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)

共有1个答案

彭梓
2023-03-14

对于在Swing中集成了JavaFX MediaPlayer的解决方案

使用JFXPanel并注意只在JavaFX线程上和JavaFX系统正确初始化后使用JavaFX对象。

JavaFX是普通的Java,这使得这个问题有点混乱,但我想你的意思是Swing。

这是从Swing启动的示例音频播放器。该示例假定Windows 7的默认公共示例音乐文件夹(C:\用户\公共\音乐\示例音乐)中有一堆mp3文件,并依次播放每个文件。

JavaFXMediaPlayerLaunchedFromSwing.java

这段代码负责创建一个Swing应用程序,该应用程序反过来初始化JavaFX工具包,并在JavaFX应用程序线程上创建一个JavaFX场景。

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
        );
    }
}

媒体场景生成器.java

创建一个 JavaFX 媒体播放器,该媒体播放器按顺序播放给定文件夹中的所有.mp3媒体文件。它为媒体提供了一些控件(播放、暂停、跳过曲目、当前曲目播放进度指示器)。

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;
    }
}

如果你只是想要一个带有MediaPlayer而没有Swing的本地JavaFX应用程序

上面使用 Swing 的解决方案回答了提出的问题。但是,我注意到有时人们会选择这个答案并使用它来创建基于 Java 的媒体播放器,即使他们没有将应用程序嵌入到其中的现有 Swing 应用程序。

如果您没有现有的Swing应用程序,请从您的应用程序中完全删除Swing代码并编写本机JavaFX应用程序。为此,请使用下面的JavaFXMediaPlayer类而不是上面示例中的类JavaFXMediaPlayerLaunchedFromSwing

JavaFX媒体播放器

import 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();
    }
}

对后续问题的回答

一旦我将JavaFX添加到netbean中的库中,我的. JAR文件是否会自动将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演示和示例下载的一部分。

 类似资料:
  • 问题内容: 我正在制作一个Java应用程序,我需要播放音频。尽管我计划循环播放背景音乐,但我主要播放的是我的大炮射击(它是大炮射击游戏)和弹丸爆炸的小声音文件。我找到了两种不同的方法来实现此目的,但是两种方法都不符合我的要求。 第一种方法实际上是一种方法: 问题是我的整个程序停止运行,直到声音文件完成或至少接近完成。 第二种方法是这样的: 我这里的问题是,每次声音文件提早结束或根本不播放时,这取决

  • 我一直无法让应用程序录制音频,同时让iPhone音乐应用程序通过蓝牙扬声器播放。 例如,如果我这样做: 然后音乐应用程序将开始通过iPhone内置的扬声器播放音乐,而不是通过蓝牙。换句话说,似乎没有办法在应用程序中录制音频的同时还允许通过蓝牙播放音乐。 如果我删除AVAudioSessionColloryOptionDefaultToSpeaker,那么音频路由将切换到接收器。这比让它通过iPho

  • 我想在我的循环应用程序中持续播放音乐,就像商店中的许多游戏应用程序一样。 但是,我不确定何时初始化音乐循环开始以及如何停止它。我创建了一个类,其中包含开始和停止音乐的逻辑。 我的应用程序结构也是这样的 主飞镖 Wrapper.dart

  • 问题内容: 我目前正在编写一些聊天程序,现在想通过客户端命令播放音乐,例如: 因此,链接将从发送歌曲的客户端发送到服务器。然后,服务器应 不 下载歌曲,而是将其流式传输到每个客户端(他们也不应下载)。问题是,我不知道如何通过基于TCP的连接流mp3。 我的问题是,是否有人可以向我提供我所需要的库/教程/思想/代码示例。 作为替代方案,直接从一个客户的计算机流式传输音乐也是可以的。如果我(作为客户端

  • 我正在做一个简单的媒体录制/播放器应用程序,录制部分已成功完成。但现在我对媒体播放器的角色有了问题。让我告诉你这些问题: 当我尝试用媒体播放器播放媒体文件时,会显示如下准备错误: JAVAio。IOException:准备失败:状态=0x1 我如何解决这个问题? 我的三门课: -RecordFragment.java: 播放片段。java: -播放适配器。java: