【问题标题】:How to highlight current playing song in playlist TableView?如何在播放列表 TableView 中突出显示当前播放的歌曲?
【发布时间】:2018-08-18 00:54:35
【问题描述】:

我正在编写某种音乐播放器应用程序,我的播放列表位于左侧,我试图突出显示播放列表中当前正在播放的歌曲。当我通过从播放列表中双击歌曲来播放歌曲时,这很好用,但是,我的问题是当一首新歌曲在当前歌曲结束后自动播放时,或者当我单击下一个或上一个按钮时。

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

在过去的几天里,我一直在尝试通过下一个和上一个按钮使其工作,但没有成功。

我目前的想法如下:在行工厂中添加某种自定义事件侦听器,它自己侦听播放列表中当前播放索引的变化,但我不确定如何实现,因为一般来说,我对 JavaFX 和 GUI 很陌生。

这是通过双击播放歌曲时应用程序的外观图片: Application

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

几个全局变量:

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

播放列表表构造函数:

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

控制器类的initialize方法中带有onMouseClick事件处理程序的行工厂:

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

【问题讨论】:

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


    【解决方案1】:

    可能最简单的方法是为当前播放的歌曲引入一个属性并(取消)在项目和歌曲更改上设置 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 的值即可突出显示包含当前播放歌曲的行。

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

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

    【讨论】:

    • 您好,非常感谢您的回答。我有点明白你的意思,但不是 100%。我正在尝试应用您的代码,但这一行存在问题:row.pseudoClassStateChanged(playing, currentSong.get());由于 currentSong.get() 返回一个 PlaylistTable 项,但该方法需要一个布尔值。我不知道该放什么。
    • @RudyAilabouni 已经在我的帖子中解决了这个问题。当然应该和行的item比较...
    • 非常感谢!有效!数小时以来一直试图找到解决方案!
    • @RudyAilabouni 如果它回答了问题,您应该将此答案标记为正确。
    • 我会的。我知道这是一个愚蠢的问题,但是在哪里可以选择呢? :) 编辑 - 评分下的勾号?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多