如何在播放列表 TableView 中突出显示当前正在播放的歌曲?
How to highlight current playing song in playlist TableView?
我正在编写某种音乐播放器应用程序,我的播放列表 table 位于左侧,我正试图在播放列表中突出显示当前播放的歌曲。当我通过双击播放列表中的歌曲来播放它时,这很好用,但是,我的问题是当当前歌曲结束后自动播放一首新歌曲时,或者当我单击下一首或上一首按钮时。
我通过双击处理高亮显示的方式是直接在行工厂中进行,然后将其添加并将该功能添加到 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 事件处理程序的行工厂 class:
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();
}
可能最简单的方法是为当前播放的歌曲引入 属性 并(取消)设置项目和歌曲更改的 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;
});
通过将以下样式 sheet 添加到场景中,您可以设置行的样式:
/* 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
.
修改
注意:您可能还想添加不同的规则来显示正在播放和 selected/focused 不同的歌曲。
我正在编写某种音乐播放器应用程序,我的播放列表 table 位于左侧,我正试图在播放列表中突出显示当前播放的歌曲。当我通过双击播放列表中的歌曲来播放它时,这很好用,但是,我的问题是当当前歌曲结束后自动播放一首新歌曲时,或者当我单击下一首或上一首按钮时。
我通过双击处理高亮显示的方式是直接在行工厂中进行,然后将其添加并将该功能添加到 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 事件处理程序的行工厂 class:
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();
}
可能最简单的方法是为当前播放的歌曲引入 属性 并(取消)设置项目和歌曲更改的 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;
});
通过将以下样式 sheet 添加到场景中,您可以设置行的样式:
/* 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
.
注意:您可能还想添加不同的规则来显示正在播放和 selected/focused 不同的歌曲。