JavaFX 表行更新

我试图实现的场景是,


每当一个特定TableCell的TableRow被更新,该行的颜色会变为红色,并在3秒后的颜色应自动恢复到原来的。

下面是MCVE,


主类


import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import javafx.application.Application;

import javafx.collections.FXCollections;

import javafx.collections.ObservableList;

import javafx.scene.Scene;

import javafx.scene.control.TableColumn;

import javafx.scene.control.TableView;

import javafx.stage.Stage;


public class TestProjectWin10 extends Application {

    private final ObservableList<Element> data = FXCollections.observableArrayList();


    public final Runnable changeValues = () -> {

        int i = 0;

        while (i <= 100000) {

            if (Thread.currentThread().isInterrupted()) {

                break;

            }

            data.get(0).setOccurence(System.currentTimeMillis());

            data.get(0).count();

            i = i + 1;

        }

    };


    private final ExecutorService executor = Executors.newSingleThreadExecutor(runnable -> {

        Thread t = new Thread(runnable);

        t.setDaemon(true);

        return t;

    });


    @Override

    public void start(Stage primaryStage) {


        TableView<Element> table = new TableView<>();

        table.getStylesheets().add(this.getClass().getResource("tableColor.css").toExternalForm());

        table.setEditable(true);


        TableColumn<Element, String> nameCol = new TableColumn<>("Name");

        nameCol.setPrefWidth(200);

        nameCol.setCellValueFactory(cell -> cell.getValue().nameProperty());

        nameCol.setCellFactory((TableColumn<Element, String> param) -> new ColorCounterTableCellRenderer(table));

        table.getColumns().add(nameCol);


        this.data.add(new Element());

    }



这是什么问题..?

  1. 我检查当前时间和更新发生时间之间的差异是否小于 3 秒 - 行颜色为红色(在ColorCounterTableCellRenderer-updateItem方法中)

  2. 在单独的计时器 ( ColorCounterTableCellRenderer) 中,我尝试检查当前时间和更新发生时间之间的差异是否超过 3 秒 - 去除红色。

但是在计时器(createTimer- 方法)代码中:tr.getItem()总是null,因此不会删除红色。

这是实现我想要的正确方法吗?为什么tr.getItem()返回null

测试:我运行代码并等待executor代码结束并检查红色是否在 3 秒后被移除。


撒科打诨
浏览 246回答 2
2回答

慕姐8265434

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

相关分类

Java