2 回答
TA贡献1813条经验 获得超2个赞
对 UI 的任何更新,即使是通过侦听器触发的,也需要从应用程序线程完成。(您可以通过使用 进行更新来解决此问题Platform.runLater。)
此外,您不能依赖同一个单元格在它应该显示为标记的整个时间内保持相同的单元格。
为了克服这个问题,您需要将有关标记单元格的信息存储在项目本身或一些可观察的外部数据结构中。
以下示例将上次更新的时间存储在 a 中,ObservableMap并使用 aAnimationTimer从地图中清除过期条目。此外,它使用TableRows 根据地图的内容更新伪类。
private static class Item {
private final IntegerProperty value = new SimpleIntegerProperty();
}
private final ObservableMap<Item, Long> markTimes = FXCollections.observableHashMap();
private AnimationTimer updater;
private void updateValue(Item item, int newValue) {
int oldValue = item.value.get();
if (newValue != oldValue) {
item.value.set(newValue);
// update time of item being marked
markTimes.put(item, System.nanoTime());
// timer for removal of entry
updater.start();
}
}
@Override
public void start(Stage primaryStage) {
Item item = new Item(); // the item that is updated
TableView<Item> table = new TableView<>();
table.getItems().add(item);
// some additional items to make sure scrolling effects can be tested
IntStream.range(0, 100).mapToObj(i -> new Item()).forEach(table.getItems()::add);
TableColumn<Item, Number> column = new TableColumn<>();
column.getStyleClass().add("mark-column");
column.setCellValueFactory(cd -> cd.getValue().value);
table.getColumns().add(column);
final PseudoClass marked = PseudoClass.getPseudoClass("marked");
table.setRowFactory(tv -> new TableRow<Item>() {
final InvalidationListener reference = o -> {
pseudoClassStateChanged(marked, !isEmpty() && markTimes.containsKey(getItem()));
};
final WeakInvalidationListener listener = new WeakInvalidationListener(reference);
@Override
protected void updateItem(Item item, boolean empty) {
boolean wasEmpty = isEmpty();
super.updateItem(item, empty);
if (empty != wasEmpty) {
if (empty) {
markTimes.removeListener(listener);
} else {
markTimes.addListener(listener);
}
}
reference.invalidated(null);
}
});
Scene scene = new Scene(table);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
updater = new AnimationTimer() {
@Override
public void handle(long now) {
for (Iterator<Map.Entry<Item, Long>> iter = markTimes.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Item, Long> entry = iter.next();
if (now - entry.getValue() > 2_000_000_000L) { // remove after 1 sec
iter.remove();
}
}
// pause updates, if there are no entries left
if (markTimes.isEmpty()) {
stop();
}
}
};
final Random random = new Random();
Thread t = new Thread(() -> {
while (true) {
try {
Thread.sleep(4000);
} catch (InterruptedException ex) {
continue;
}
Platform.runLater(() -> {
updateValue(item, random.nextInt(4));
});
}
});
t.setDaemon(true);
t.start();
}
样式文件
.table-row-cell:marked .table-cell.mark-column {
-fx-background-color: red;
}
添加回答
举报