如何让歌曲持续时间在 JavaFx 音乐播放器中工作

How to get song duration to work in JavaFx Music Player

我使用 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) and this youtube video (https://www.youtube.com/watch?v=-D2OIekCKes) 来创建音乐播放器。

如果有任何帮助,我将不胜感激。提前致谢!

你不应该使用 Timer,或者一般的线程,来做这样的事情。 MediaPlayer 的属性是可观察的,因此您应该向它们添加侦听器,或者将 UI 属性绑定到它们。下面是将 ProgressBar 的进度 属性 绑定到玩家的示例:

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...) and lambda expressions.

每次创建新的 MediaPlayer 时,您都需要执行上述操作,否则将处理使进度条保持最新的问题。你可以对标签做类似的事情,例如,以人类可读的格式显示当前时间和总时间。

此外,除了向 volumeSlider 添加侦听器之外,您还可以这样做:

mediaPlayer.volumeProperty().bind(volumeSlider.valueProperty());

有关详细信息,请参阅 Using JavaFX Properties and Binding


顺便说一句,你不仅不应该在这里使用 Timer,而且你使用它的方式也不正确。在 JavaFX 中,有一个名为 JavaFX Application Thread 的特殊线程。只有那个线程应该直接或间接地与 UI 交互。使用任何其他线程与 UI 交互是损坏的代码,并可能导致未定义的行为——JavaFX 不是线程安全的。

您可以使用 Platform#runLater(Runnable) 在 FX 线程上安排操作。