我使用JavaFX创建了一个音乐播放器。然而,我不明白我怎么能知道我目前正在播放的歌曲的持续时间。
编辑: 我在代码中添加了以下几行,现在歌曲的持续时间是可见的。但是,当我播放下一首歌曲时,歌曲的持续时间是不可见的。以下是我添加到代码中的行:
mediaPlayer.currentTimeProperty().addListener(new TimeListener());
TimeListener = new ChangeListener<Duration>()
{
@Override public void changed(ObservableValue<? extends Duration> o, Duration oldVal, Duration newVal)
{
//now newVal is of Duration class
}
};
}
public class TimeListener implements ChangeListener {
public void changed(ObservableValue o, Object oldVal, Object newVal) {
//Update time display with MediaPlayer's current time:
playTime.setText(newVal.toString());
}
}
这是我创建音乐播放器的代码:
public class MusicController implements Initializable
{
@FXML
private ImageView trackLogo;
@FXML
private Button next, previous, pause, play, reset;
@FXML
private Slider VolumeSlider;
@FXML
private AnchorPane Panel;
@FXML
private Label playTime, appTitle, songTitle;
@FXML
private ProgressBar songProgressBar;
@FXML
private Media media;
private MediaPlayer mediaPlayer;
private File directory;
private File [] files;
private ArrayList<File> songs;
private int songNumber;
private Timer timer;
private TimerTask task;
private boolean running;
private ChangeListener<Duration> TimeListener;
@Override
public void initialize(URL url, ResourceBundle rb)
{
songs = new ArrayList<File>();
directory = new File("music");
files = directory.listFiles();
if(files!=null)
{
for(File file : files)
{
songs.add(file);
System.out.println(file);
}
}
media = new Media(songs.get(songNumber).toURI().toString());
mediaPlayer = new MediaPlayer(media);
mediaPlayer.currentTimeProperty().addListener(new TimeListener());
songTitle.setText(songs.get(songNumber).getName());
VolumeSlider.valueProperty().addListener(new ChangeListener<Number>()
{
public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2)
{
mediaPlayer.setVolume(VolumeSlider.getValue() * 0.01);
}
});
TimeListener = new ChangeListener<Duration>()
{
@Override public void changed(ObservableValue<? extends Duration> o, Duration oldVal, Duration newVal)
{
//now newVal is of Duration class
}
};
}
public class TimeListener implements ChangeListener {
public void changed(ObservableValue o, Object oldVal, Object newVal) {
//Update time display with MediaPlayer's current time:
playTime.setText(newVal.toString());
}
}
public void playMedia()
{
beginTimer();
mediaPlayer.setVolume(VolumeSlider.getValue() * 0.01);
mediaPlayer.play();
}
public void pauseMedia()
{
cancelTimer();
mediaPlayer.pause();
}
public void resetMedia()
{
songProgressBar.setProgress(0);
mediaPlayer.seek(Duration.seconds(0));
}
public void previousMedia()
{
if (songNumber > 0)
{
songNumber--;
mediaPlayer.stop();
if(running)
{
cancelTimer();
}
media = new Media(songs.get(songNumber).toURI().toString());
mediaPlayer = new MediaPlayer(media);
songTitle.setText(songs.get(songNumber).getName());
playMedia();
}
else
{
songNumber = songs.size() - 1;
mediaPlayer.stop();
if(running)
{
cancelTimer();
}
media = new Media(songs.get(songNumber).toURI().toString());
mediaPlayer = new MediaPlayer(media);
songTitle.setText(songs.get(songNumber).getName());
playMedia();
}
}
public void nextMedia()
{
if (songNumber < songs.size() - 1)
{
songNumber++;
mediaPlayer.stop();
if(running)
{
cancelTimer();
}
media = new Media(songs.get(songNumber).toURI().toString());
mediaPlayer = new MediaPlayer(media);
songTitle.setText(songs.get(songNumber).getName());
playMedia();
}
else
{
songNumber = 0;
mediaPlayer.stop();
if(running)
{
cancelTimer();
}
media = new Media(songs.get(songNumber).toURI().toString());
mediaPlayer = new MediaPlayer(media);
songTitle.setText(songs.get(songNumber).getName());
playMedia();
}
}
public void beginTimer()
{
timer = new Timer();
task = new TimerTask()
{
public void run()
{
running = true;
double current = mediaPlayer.getCurrentTime().toSeconds();
double end = media.getDuration().toSeconds();
System.out.println(current/end);
songProgressBar.setProgress(current/end);
if (current/end ==1)
{
cancelTimer();
}
}
};
timer.scheduleAtFixedRate(task, 0, 1000);
}
public void cancelTimer()
{
running = false;
timer.cancel();
}
}
我已尝试阅读Oracle文档(https://docs.oracle.com/javase/8/javafx/media-tutorial/playercontrol.htm)还有这个youtube视频(https://www.youtube.com/watch?v=-D2OIekCKes(来创建音乐播放器。
如果有任何帮助,我将不胜感激。提前感谢!
对于这样的事情,不应该使用Timer
或一般的线程。MediaPlayer
的属性是可观察的,因此您应该向它们添加监听器,或者将UI属性绑定到它们。以下是将ProgressBar
的progress属性绑定到播放器的示例:
progressBar.progressProperty().bind(
Bindings.createDoubleBinding(() -> {
Duration current = mediaPlayer.getCurrentTime();
Duration total = mediaPlayer.getCycleDuration();
return current.toMilli() / total.toMillis();
},
mediaPlayer.currentTimeProperty(),
mediaPlayer.cycleDurationProperty())
);
以上使用了Bindings#createDoubleBinding(Callable,Observable…(和lambda表达式
每次创建新的MediaPlayer
时,您都需要执行上述操作,但除此之外,这将处理保持进度条最新的问题。您还可以对以可读格式显示当前时间和总时间的标签执行类似操作。
此外,不需要在volumeSlider
中添加侦听器,您可以执行以下操作:
mediaPlayer.volumeProperty().bind(volumeSlider.valueProperty());
有关详细信息,请参阅使用JavaFX属性和绑定。
顺便说一句,你不仅不应该在这里使用Timer
,而且你使用它的方式是不正确的。在JavaFX中,有一个名为JavaFX应用程序线程的特殊线程。只有该线程应该直接或间接地与UI交互。使用任何其他线程与UI交互都是破坏代码,并可能导致未定义的行为——JavaFX不是线程安全的。
您可以使用Platform#runLater(Runnable)
在FX线程上安排操作。