HIHO,
我有一个让ListView更新“很好”的问题。这是一个包含一堆播放列表项的播放列表。基本上,当项目的样式或内容发生变化时,我希望它在ListView中进行更改。目前,我刷新了整个列表,我认为这可行,但对我来说它似乎是一个非常糟糕(不清楚)的解决方案(并且它闪烁)。有没有办法刷新/重绘特定项目?我一直都找不到。
作为参考,当发生以下情况时,需要更新每个项目:
我能以某种方式使用听众吗?我看过绑定等,但我似乎找不到我想要的东西。任何帮助非常感谢
再次编辑:下面的工作代码
初始化清单:
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();
}
});
...
}
工厂创建的单元格:
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);
}
}
}
然后,当我双击某个项目时,或者当我排队项目时,我将BooleanProperty设置为true(即已更改)以触发更新调用。
答案 0 :(得分:0)
假设queue
是要播放的队列中的ObservableList<PlaylistItem>
个项目,current
是表示当前正在播放的项目的ObjectProperty<PlaylistItem>
(或类似内容),我认为你只需要像
private class PlaylistCell extends ListCell<PlaylistItem> {
public PlaylistCell() {
textProperty().bind(Bindings.createStringBinding(this::calculateText,
itemProperty(), emptyProperty(), current, queue);
idProperty().bind(Bindings
.when(current.isEqualTo(itemProperty())
.then("current-item")
.otherwise(""));
}
private String calculateText() {
if (isEmpty() || getItem() == null) return null ;
PlaylistItem item = getItem();
if (queue.contains(item)) {
int index = queue.indexOf(item) ;
boolean unique = index == queue.lastIndexOf(item);
return String.format("%s (%d%s)", item ,index + 1, (unique ? "" : ", ..."));
} else {
return item.toString();
}
}
}
我建议使用CSS PseudoClass
而不是操纵id:
private class PlaylistCell extends ListCell<PlaylistItem> {
private final BooleanBinding isCurrent = current.isEqualTo(itemProperty());
private final PseudoClass currentPC = PseudoClass.getPseudoClass("current");
public PlaylistCell() {
textProperty().bind(Bindings.createStringBinding(this::calculateText,
itemProperty(), emptyProperty(), current, queue);
isCurrent.addListener((obs, wasCurrent, isNowCurrent) ->
pseudoClassStateChanged(currentPC, isNowCurrent));
}
// ...
}
然后更改CSS以使用选择器
.list-cell:current { /* ... */ }
而不是
#current-item { /* ... *. }
作为创建绑定的替代方法,您还可以使用extractor创建数据列表,这将导致在当前正在播放的项目或队列时调用通常的updateItem()
方法,改变:
ObservableList<PlaylistItem> items = FXCollections.observableArrayList(
item -> new Observable[] { current, queue /* , other properties the toString() depends on...*/ });
ListView<PlaylistItem> listView = new ListView<>();
listView.setItems(items);
然后
public class PlaylistCell extends ListCell<PlayListItem> {
private final PseudoClass currentPC = PseudoClass.getPseudoClass("current");
@Override
protected void updateItem(PlaylistItem item, boolean empty) {
pseudoClassStateChanged(currentPC, current.isEqualTo(item));
if (empty) {
setText(null);
} else {
if (queue.contains(item)) {
int index = queue.indexOf(item) ;
boolean unique = index == queue.lastIndexOf(item);
return String.format("%s (%d%s)", item ,index + 1, (unique ? "" : ", ..."));
} else {
return item.toString();
}
}
}
}