如何在播放列表TableView中突出显示当前播放的歌曲?

时间:2018-03-09 12:36:33

标签: java user-interface javafx tableview media-player

我正在编写某种音乐播放器应用程序,我在左侧有播放列表,我正在尝试突出播放列表中当前播放的歌曲。当我通过从播放列表中双击来播放歌曲时,这样可以正常工作,但是,我的问题是当新歌曲在当前歌曲结束后自动播放时,或者当我单击下一个或上一个按钮时。

我通过双击处理突出显示的方式是直接在行工厂中添加它并将该功能添加到TableRow.onMouseClick事件处理程序。

在过去的几天里,我一直试图通过下一个和前一个按钮来实现这个功能但没有成功。

我目前的想法如下:在行工厂中添加某种自定义事件监听器,它监听自己播放列表中当前播放索引的变化,但我不知道如何实现它,如我是JavaFX和GUI的新手。

以下是通过双击播放歌曲时应用的外观图: Application

以下是一些相关的代码部分:

一些全局变量:

private TableRow<PlaylistTable> lastPlayed;
private TableRow<PlaylistTable> currentPlayed;

PlaylistTable构造函数:

private final Song song;
private final SimpleStringProperty songTitle;
private final SimpleStringProperty artist;
private final SimpleStringProperty album;
private final SimpleStringProperty trackNumber;

public PlaylistTable(LibraryTable row){
    this.song = row.getSong();
    this.songTitle = new SimpleStringProperty(row.getSongTitle());
    this.artist = new SimpleStringProperty(row.getArtist());
    this.album = new SimpleStringProperty(row.getAlbum());
    this.trackNumber = new SimpleStringProperty(row.getTrackNumber());
}

具有onMouseClick事件处理程序的行Factory,位于控制器类的initialize方法中:

 playlistTable.setRowFactory(e -> {
        TableRow<PlaylistTable> row = new TableRow<>();

        row.setOnMouseClicked(e1 -> {

            if (e1.getButton() == MouseButton.PRIMARY && e1.getClickCount() == 2) {
                if (lastPlayed == null) {
                    lastPlayed = row;
                } else if (lastPlayed != row) {
                    lastPlayed.setStyle("");  //("-fx-background-color: #39CCCC;-fx-border-color: white; -fx-text-fill: white;");
                    lastPlayed = row;
                }
                playSongFromPlaylist();
                currentPlayed = row;

                row.setStyle("-fx-background-color: #FFDC00;-fx-border-color: black; -fx-text-fill: white;");
                System.out.println("highlighting row");


            }
        });

按下一个按钮时。

public void onNext() {
    if (mediaPlayer != null) {
        MediaPlayer.Status status = mediaPlayer.getStatus();
        if (status == MediaPlayer.Status.PLAYING || status == MediaPlayer.Status.PAUSED) {
            mediaPlayer.stop();
            playlist.next().orElse(0);
            playSong();
           /* Song song = playlist.getCurrentSong().get();
            File songFile = song.getFilePath().toAbsolutePath().toFile();
            currentSong = new Media(songFile.toURI().toString());
            mediaPlayer = new MediaPlayer(currentSong);
            mediaPlayer.setAutoPlay(false);
            mediaPlayer.play();
            currentSongName.setText(song.getMetadata().getSongTitle().orElse("Unknown Song"));
            playing = true;
            playButton.setText("\u23F8");*/
        } else if (status == MediaPlayer.Status.READY) {
            playlist.setCurrent(0);
            playSong();
        }
    }

这个方法调用播放歌曲的实际方法,即playSongFromPlaylist,但是这个方法在这里有点无关紧要,因为它需要小心或一切,实际控制音乐播放器本身及其外观。

public void playSong() {
    if (!playlist.getCurrentSong().isPresent()) {
        System.out.println("returning");
        return;
    }

    System.out.println(playlistTable.getSelectionModel().getSelectedIndex());
    int currentIndex = playlist.getCurrent().get();
    Song song = playlist.getCurrentSong().get();
    System.out.println("current index: " + currentIndex);

    playlistTable.getSelectionModel().select(currentIndex);
    selectedFromButtons = true;
    System.out.println(playlistTable.getSelectionModel().getSelectedIndex());
    playSongFromPlaylist();
}

1 个答案:

答案 0 :(得分:1)

最简单的方法可能是为当前播放的歌曲引入一个属性,并且(un)在项目和歌曲更改上设置CSS伪类:

final ObjectProperty<PlaylistTable> currentSong = new SimpleObjectProperty();
final PseudoClass playing = PseudoClass.getPseudoClass("playing");

playlistTable.setRowFactory(e -> {

    final TableRow<PlaylistTable> row = new TableRow<>();
    InvalidationListener listener = o -> {
        row.pseudoClassStateChanged(playing, currentSong.get() == row.getItem());
    };
    row.itemProperty().addListener(listener);
    currentSong.addListener(listener);

    ...

    return row;
});

通过将以下样式表添加到场景中,您可以设置行的样式:

/* filled pseudoclass is important here to prevent selection
   of empty rows when no song is playing */
.table-view .table-row-cell:filled:playing {
    -fx-background-color: #FFDC00;
    -fx-border-color: black;
    -fx-text-fill: white;
}

这样,您只需设置currentSong的值,即可突出显示包含当前播放歌曲的行。

您需要从事件处理程序中删除样式。无论如何,这都无法正常工作,因为行的项属性可以由TableView修改。

注意:您可能还想添加不同的规则来显示同时播放和选择/聚焦的歌曲。