I am facing an issue with a JavaFX FilteredList. I have a ListView of songs, and I'm using a FilteredList to implement search functionality. When I filter the list by entering a keyword in the search field, the FilteredList returns duplicate results. This duplication issue occurs when I use the FilteredList to display the filtered results in the ListView. Even when the keyword is null, the list still contains duplicate entries. I am using a custom ListCell with three columns (song number, title, artist, and duration) in the ListView. I think the reason is using hbox and vbox.
hbox và vbox:
playList.setCellFactory(new Callback<ListView<Song>, ListCell<Song>>() {
@Override
public ListCell<Song> call(ListView<Song> param) {
return new ListCell<Song>() {
@Override
protected void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
// Tạo hai nhãn cho mỗi mục
Label titleLabel = new Label(item.getTitle());
Label artistLabel = new Label(item.getArtist());
Label numberLabel = new Label(String.valueOf(item.getsongNumber()));
Label DurationLabel = new Label(item.getDuration());
// Đặt layout cho nhãn
HBox hbox = new HBox();
VBox vbox = new VBox(titleLabel,artistLabel);
hbox.getChildren().addAll(numberLabel, vbox, DurationLabel);
vbox.setMinWidth(275);
numberLabel.setMinWidth(36);
HBox.setMargin(DurationLabel, new Insets(7, 5, 5, 5));
HBox.setMargin(numberLabel, new Insets(7, 0, 5, 5));
// Đặt nội dung cho mục
setGraphic(hbox);
}
}
};
}
});
// Gán danh sách bài hát trực tiếp cho ListView
playList.setItems(songs);
filteredList:
private void filterSongs(String keyword) {
// Tạo một FilteredList mới từ danh sách bài hát gốc
newFilteredList = new FilteredList<>(songs);
System.out.println("Filtering with keyword: " + keyword);
newFilteredList.setPredicate(song ->
song.getTitle().toLowerCase().contains(keyword.toLowerCase()) ||
song.getArtist().toLowerCase().contains(keyword.toLowerCase()));
System.out.println("Filtered List Size: " + newFilteredList.size());
for (Song song : newFilteredList) {
System.out.println(song.getTitle());
}
// Đặt FilteredList mới làm nguồn dữ liệu cho ListView
playList.setItems(newFilteredList);
playList.refresh(); // Cập nhật hiển thị của ListView
}
when i search, the filteredList display only true result
Your list cell is incorrectly implemented. Since you set the graphic when the cell is not empty, you need to set it back to null if the cell becomes empty. The implementation should be:
playList.setCellFactory(new Callback<ListView<Song>, ListCell<Song>>() {
@Override
public ListCell<Song> call(ListView<Song> param) {
return new ListCell<Song>() {
@Override
protected void updateItem(Song item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
// setText(...) not needed here, since you don't set the text in the else clause:
// setText(null);
setGraphic(null);
} else {
// Tạo hai nhãn cho mỗi mục
Label titleLabel = new Label(item.getTitle());
Label artistLabel = new Label(item.getArtist());
Label numberLabel = new Label(String.valueOf(item.getsongNumber()));
Label DurationLabel = new Label(item.getDuration());
// Đặt layout cho nhãn
HBox hbox = new HBox();
VBox vbox = new VBox(titleLabel,artistLabel);
hbox.getChildren().addAll(numberLabel, vbox, DurationLabel);
vbox.setMinWidth(275);
numberLabel.setMinWidth(36);
HBox.setMargin(DurationLabel, new Insets(7, 5, 5, 5));
HBox.setMargin(numberLabel, new Insets(7, 0, 5, 5));
// Đặt nội dung cho mục
setGraphic(hbox);
}
}
};
}
});