0

使用在普通 Java 应用程序中使用 JavaFX MediaPlayer 播放音频的公认答案中提供的代码示例?当我将绝对路径作为字符串传递给文件构造函数时,我可以从计算机上的目录播放 mp3。

我的问题是我试图从我已导入 eclipse 的目录中访问 mp3 文件。我想这样做,以便我可以将我的项目导出为 .jar 并让其他人能够使用它。当我传递相对路径字符串( /ProjectName/Mp3Directory )并运行它时,我得到

Cannot find video source directory: /ProjectName/Mp3Directory

我还尝试从相对路径创建一个 URL,然后将其转换为 URI 并将其传递给 File 构造函数,但我也无法让它工作。

如何获取以下代码以找到包含 mp3 (Mp3Directory) 的导入目录并成功运行?

package application;

import java.io.*;
import java.net.URL;
import java.util.*;

import javafx.application.Platform;
import javafx.beans.value.*;
import javafx.embed.swing.JFXPanel;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.media.*;
import javafx.util.Duration;

import javax.swing.*;

/** Example of playing all mp3 audio files in a given directory 
 * using a JavaFX MediaView launched from Swing 
 */
public class JavaFXVideoPlayerLaunchedFromSwing {
  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(new Runnable() {
      @Override public void run() {
        initFX(fxPanel);        
      }
    });
  }

  private static void initFX(JFXPanel fxPanel) {
    // This method is invoked on JavaFX thread
    Scene scene = new SceneGenerator().createScene();
    fxPanel.setScene(scene);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        initAndShowGUI();
      }
    });
  }
}

class SceneGenerator {    
  final Label currentlyPlaying = new Label();
  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("/ProjectName/mp3Directory");
    if (!dir.exists() || !dir.isDirectory()) {
      System.out.println("Cannot find video source directory: " + dir);
      Platform.exit();
      return null;
    }

    // create some media players.
    final List<MediaPlayer> players = new ArrayList<MediaPlayer>();
    for (String file : dir.list(new FilenameFilter() {
      @Override public boolean accept(File dir, String name) {
        return name.endsWith(".mp3");
      }
    })) players.add(createPlayer("file:///" + (dir + "\\" + file).replace("\\", "/").replaceAll(" ", "%20")));
    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++) {
      final MediaPlayer player     = players.get(i);
      final MediaPlayer nextPlayer = players.get((i + 1) % players.size());
      player.setOnEndOfMedia(new Runnable() {
        @Override public void run() {
          player.currentTimeProperty().removeListener(progressChangeListener);
          mediaView.setMediaPlayer(nextPlayer);
          nextPlayer.play();
        }
      });
    }

    // allow the user to skip a track.
    skip.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent actionEvent) {
        final MediaPlayer curPlayer = mediaView.getMediaPlayer();
        MediaPlayer nextPlayer = players.get((players.indexOf(curPlayer) + 1) % players.size());
        mediaView.setMediaPlayer(nextPlayer);
        curPlayer.currentTimeProperty().removeListener(progressChangeListener);
        curPlayer.stop();
        nextPlayer.play();
      }
    });

    // allow the user to play or pause a track.
    play.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent 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(new ChangeListener<MediaPlayer>() {
      @Override public void changed(ObservableValue<? extends MediaPlayer> observableValue, MediaPlayer oldPlayer, MediaPlayer 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.
    layout.setStyle("-fx-background-color: cornsilk; -fx-font-size: 20; -fx-padding: 20; -fx-alignment: center;");
    layout.getChildren().addAll(
      invisiblePause,
      VBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(
        currentlyPlaying,
        mediaView,
        HBoxBuilder.create().spacing(10).alignment(Pos.CENTER).children(skip, play, progress).build()
      ).build()
    );
    progress.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(progress, Priority.ALWAYS);
    return new Scene(layout, 800, 600);
  }

  /** 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 = new ChangeListener<Duration>() {
      @Override public void changed(ObservableValue<? extends Duration> observableValue, Duration oldValue, Duration newValue) {
        progress.setProgress(1.0 * newPlayer.getCurrentTime().toMillis() / newPlayer.getTotalDuration().toMillis());
      }
    };
    newPlayer.currentTimeProperty().addListener(progressChangeListener);

    String source = newPlayer.getMedia().getSource();
    source = source.substring(0, source.length() - ".mp4".length());
    source = source.substring(source.lastIndexOf("/") + 1).replaceAll("%20", " ");
    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(new Runnable() {
      @Override public void run() {
        System.out.println("Media error occurred: " + player.getError());
      }
    });
    return player;
  }
}
4

2 回答 2

1

相对路径不应以斜线开头。“/ProjectName”相当于当前驱动器根目录中名为 ProjectName 的文件夹。所以你可以尝试“ProjectName/mp3Directory”......虽然对于在 Eclipse 和可运行 JAR 中都可以使用的东西,你应该获取应用程序正在运行的文件夹并从那里创建一个相对路径(参见Get应用程序的路径以获取更多信息):

URL url = getClass().getResource("").toURI().toURL();
String applicationDir = url.getPath();

if(url.getProtocol().equals("jar")) {
    appDir = new File(((JarURLConnection)url.openConnection()).getJarFileURL().getFile()).().getFile()).getParent();
}

String mp3Dir = appDir + "ProjectName" + System.getProperty("file.separator") + "mp3Directory";

尽管这并不是您问题的直接答案,但我认为对于您不想强迫用户将其 MP3 文件放在特定文件夹中的通用应用程序,axiopisty 建议使用文件选择器(结合使用设置文件或首选项 API 保存选择)将是可行的方法。

于 2013-11-11T21:07:50.193 回答
1

也许尝试允许用户选择其中包含 mp3 的文件夹,在您的方法中使用类似这样的内容createScene

final JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

// final File dir = new File("/ProjectName/mp3Directory");
File dir = null;
int selection = fc.showDialog(null, "Open");
if(selection == JFileChooser.APPROVE_OPTION) {
    dir = fc.getSelectedFile();
} else {
    System.out.print("Please select a directory to continue");
    System.exit(0);
}
于 2013-11-11T20:37:28.233 回答