Hiho,
I have a problem with getting ListView to update "nicely". It's a playlist with a bunch of playlist items. Basically, when the style or content of an item changes, I want it to change in the ListView. Currently, I refresh the whole list, which works I guess but it seems like a really poor (unclear) solution to me (and it flickers). Is there a way to refresh/repaint a specific item? I haven't been able to find any.
For reference, each item needs to be updated when the following happens:
- The file related to the item is being read and eg it fails; or the metadata is retrieved.
- Or; from user input, eg when changing the current song.
Can I make use of a Listener somehow? I've looked at bindings etc but I don't seem to find what I'm looking for. Any help greatly appreciated
Edited again: Working code below
Initialise the list:
protected Playlist(List<PlaylistItem> list){
...
// initialise the items
backup = FXCollections.observableArrayList(list);
setItems(backup);
// Use a custom CellFactory
setCellFactory(new Callback<ListView<PlaylistItem>, ListCell<PlaylistItem>>() {
@Override
public ListCell<PlaylistItem> call(ListView<PlaylistItem> list) {
return new PlaylistCell();
}
});
...
}
The cells created by the factory:
private class PlaylistCell extends ListCell<PlaylistItem> {
private PlaylistItem lastItem = null;
private final BooleanProperty booleanProperty = new SimpleBooleanProperty(false);
/** Add a listener to the boolean property upon construction */
private PlaylistCell() {
booleanProperty.addListener( new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) { updateItem(lastItem, lastItem == null); };
}
});
}
@Override
public void updateItem(PlaylistItem item, boolean empty) {
super.updateItem(item, empty);
booleanProperty.set(false);
if (lastItem != item){
// remove the pointer if we change item
if (lastItem != null && booleanProperty == lastItem.getBooleanProperty())
lastItem.setBooleanProperty(null);
// and attach it to the new item
if (item != null)
item.setBooleanProperty(booleanProperty);
}
// redraw the cell
if (!empty && item != null) {
lastItem = item;
// current song in bold
if (item.equals(current)) {
setId("current-item");
} else{
setId(null);
}
// mark queued songs & update text
if (queue.contains(item)) {
int i = queue.indexOf(item);
super.setText(item.toString() + "\t (" + (i + 1) + (i != queue.lastIndexOf(item) ? ", ...)": ')'));
} else {
super.setText(item.toString());
}
}
// draw an empty cell
else {
lastItem = null;
setText(null);
setId(null);
}
}
}
And then when I eg double-click an item it's to current or when I queue an item, I set the BooleanProperty to true (ie has changed) to trigger the update call.