Не удается получить JavaFX Tableview с мигающим фоном ячейки при обновлении для правильной работы - PullRequest
1 голос
/ 31 марта 2020

Я изучаю JavaFX и сейчас смотрю на TableView. Я хочу поместить цены на акции в таблицу и мигать / мигать фоном ячейки при обновлении.

Я много искал и видел несколько предложений, однако не смог найти то, что я ищу , Кроме того, мне кажется, что у меня проблемы с пониманием логики c таблиц, в частности, когда и как создаются и обновляются ячейки.

Рассмотрим следующий код (в основном заимствованный из http://jaakkola.net/juhani/blog/?p=233 ):

public class FlashingTableCell<S, T> extends TableCell<S, T> {

    private static final Color INCREASE_HIGHLIGHT_COLOR = Color.rgb(0, 255, 0, 0.8);
    private static final Color DECREASE_HIGHLIGHT_COLOR = Color.rgb(255, 0, 0, 0.8);
    private static final Color HIGHLIGHT_COLOR = Color.rgb(0, 255, 0, 0.8);
    private static final Duration HIGHLIGHT_TIME = Duration.millis(600);

    private final Background bgIncrease = new Background(new BackgroundFill(INCREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
    private final Background bgDecrease = new Background(new BackgroundFill(DECREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
    private final Background bgChange = new Background(new BackgroundFill(HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));

    private final BorderPane background = new BorderPane();
    private final Label lblText = new Label("");
    private final FadeTransition animation = new FadeTransition(HIGHLIGHT_TIME, background);

    private final StackPane container = new StackPane();

    private T prevValue;
    private S prevItem;

    final private Comparator<T> comparator;


    public FlashingTableCell(Comparator<T> comparator, Pos alignment) {
        super();
        this.comparator = comparator;

        lblText.textProperty().bindBidirectional(textProperty());
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        setPadding(Insets.EMPTY);
        container.getChildren().addAll(background, lblText);
        container.setAlignment(alignment);
        setGraphic(container);
    }

    @Override
    protected void updateItem(T value, boolean empty) {
        super.updateItem(value, empty);

        System.out.println("updateItem " + this.hashCode() + " " + getIndex() + " value=" + value + " (" + prevValue + ")" + empty);

        S currentItem = getTableRow() != null && getTableRow().getItem() != null ? (S) getTableRow().getItem() : null;

        /*
         * We check that the value has been updated and that the row model/item
         * under the cell is the same. JavaFX table reuses cells so item is not
         * always the same!
         */
        boolean valueChanged = (prevValue == null && value != null) || (value != null && (prevValue.hashCode() != value.hashCode()));
        boolean sameItem = currentItem != null && prevItem != null && currentItem == prevItem;

        if (valueChanged && sameItem) {

            if (comparator != null) {
                int compare = comparator.compare(value, prevValue);
                if (compare > 0) {
                    background.setBackground(bgIncrease);
                } else if (compare < 0) {
                    background.setBackground(bgDecrease);
                }
            } else {
                background.setBackground(bgChange);
            }

            lblText.setText(String.format("%1.2f", value));

            animation.setFromValue(1);
            animation.setToValue(0);
            animation.setCycleCount(1);
            animation.setAutoReverse(false);
            animation.playFromStart();
        }

        prevValue = value;
        prevItem = currentItem;
    }
}

и эта фабрика ячеек:

public class FlashingTableCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {
    @Override
    public TableCell<S, T> call(TableColumn<S, T> p) {
        System.out.println("************** CREATING FLASHING TABLE CELL **************");
        FlashingTableCell<S,T> cell = new FlashingTableCell<S,T>(null, Pos.CENTER);
        return cell;
    }
}

И я использую это так:

public class Main extends Application {

    Timer timer = new Timer();

    @Override
    public void start(Stage primaryStage) {

        TableView<InstrumentPrice> table = new TableView<>();
        ObservableList<InstrumentPrice> data = getInitialTableData();
        table.setItems(data);

        TableColumn<InstrumentPrice, String> nameCol = new TableColumn<>("Name");
        nameCol.setCellValueFactory(new PropertyValueFactory<>("instrumentName"));

        TableColumn<InstrumentPrice, Double> openCol = new TableColumn<>("Open");
        openCol.setCellValueFactory(new PropertyValueFactory("open"));
        // Flashing table cell
        FlashingTableCellFactory<tabletest1.InstrumentPrice, Double> ftc2 = new FlashingTableCellFactory<tabletest1.InstrumentPrice, Double>();
        openCol.setCellFactory(ftc2);

        table.getColumns().setAll(nameCol, openCol);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
            // Get and update first item in data array
            InstrumentPrice p = data.get(0);
            p.setOpen(p.getOpen()+1.0);
            data.set(0, p);
            }
        }, 10*1000, 5*1000); // 10 seconds

        StackPane rootLayout = new StackPane(table);
        Scene scene = new Scene(rootLayout, 1000, 300);
        primaryStage.setTitle("Example");
        primaryStage.setScene(scene);
        primaryStage.setX(0);
        primaryStage.setY(0);
        primaryStage.show();
    }

     private ObservableList<InstrumentPrice> getInitialTableData() {
        List list = new ArrayList<InstrumentPrice>();
        list.add(new InstrumentPrice("ABC", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("DEF", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("GHI", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("JKL", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("MNO", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("PQR", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("STU", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        list.add(new InstrumentPrice("VWX", 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, 0, 0.0, 0));
        ObservableList<InstrumentPrice> data = FXCollections.observableList(list);
        return data;
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Я печатаю отладку на консоль, и вот некоторые из них:

************** CREATING FLASHING TABLE CELL 1299017468
updateItem 1299017468 0 value=0.0 (null)false
updateItem 1299017468 1 value=0.0 (0.0)false
updateItem 1299017468 2 value=0.0 (0.0)false
updateItem 1299017468 3 value=0.0 (0.0)false
updateItem 1299017468 4 value=0.0 (0.0)false
updateItem 1299017468 5 value=0.0 (0.0)false
updateItem 1299017468 6 value=0.0 (0.0)false
updateItem 1299017468 7 value=0.0 (0.0)false
updateItem 1299017468 -1 value=null (0.0)true
************** CREATING FLASHING TABLE CELL 312035237
updateItem 312035237 0 value=0.0 (null)false
updateItem 312035237 -1 value=null (0.0)true
************** CREATING FLASHING TABLE CELL 616040193
updateItem 616040193 0 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1836880566
updateItem 1836880566 1 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1717614984
updateItem 1717614984 2 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 114981818
updateItem 114981818 3 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 151715918
updateItem 151715918 4 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 1690114806
updateItem 1690114806 5 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 397552694
updateItem 397552694 6 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 705642570
updateItem 705642570 7 value=0.0 (null)false
************** CREATING FLASHING TABLE CELL 575848070
updateItem 575848070 8 value=null (null)true
************** CREATING FLASHING TABLE CELL 349657094
updateItem 349657094 9 value=null (null)true
************** CREATING FLASHING TABLE CELL 221445895
updateItem 221445895 10 value=null (null)true
************** CREATING FLASHING TABLE CELL 666967962
updateItem 666967962 11 value=null (null)true
updateItem 616040193 -1 value=null (0.0)true
updateItem 1836880566 -1 value=null (0.0)true
updateItem 1717614984 -1 value=null (0.0)true
updateItem 114981818 -1 value=null (0.0)true
updateItem 151715918 -1 value=null (0.0)true
updateItem 1690114806 -1 value=null (0.0)true
updateItem 397552694 -1 value=null (0.0)true
updateItem 705642570 -1 value=null (0.0)true
updateItem 666967962 0 value=1.0 (null)false
updateItem 666967962 0 value=1.0 (1.0)false
updateItem 221445895 1 value=0.0 (null)false
updateItem 221445895 1 value=0.0 (0.0)false
updateItem 349657094 2 value=0.0 (null)false
updateItem 349657094 2 value=0.0 (0.0)false
updateItem 575848070 3 value=0.0 (null)false
updateItem 575848070 3 value=0.0 (0.0)false
updateItem 705642570 4 value=0.0 (0.0)false
updateItem 705642570 4 value=0.0 (0.0)false
updateItem 397552694 5 value=0.0 (0.0)false
updateItem 397552694 5 value=0.0 (0.0)false
updateItem 1690114806 6 value=0.0 (0.0)false
updateItem 1690114806 6 value=0.0 (0.0)false
updateItem 151715918 7 value=0.0 (0.0)false
updateItem 151715918 7 value=0.0 (0.0)false
updateItem 114981818 8 value=null (0.0)true
updateItem 114981818 8 value=null (0.0)true
updateItem 1717614984 9 value=null (0.0)true
updateItem 1717614984 9 value=null (0.0)true
updateItem 1836880566 10 value=null (0.0)true
updateItem 1836880566 10 value=null (0.0)true
updateItem 616040193 11 value=null (0.0)true
updateItem 616040193 11 value=null (0.0)true

Есть много проблем, но в основном мне интересно:

  • Почему метод updateItem () вызывается дважды для каждого обновления?
  • Когда я обновляю только строку 0, почему я получаю вызовы updateItem () для строк 1..n? Я не изменяю размеры таблицы или чего-либо еще.
  • Лог "sameItem" c, похоже, не работает вообще
  • Что я должен делать, когда updateItem вызывается с пустым == true ?

Каким-то образом я считаю, что все эти вопросы связаны, и что это как-то вызвано моим неправильным пониманием чего-то с фабрикой клеток и созданием клеток. Я делал подобные вещи во многих других языках / структурах, и никогда не был так смущен, как сейчас ...

Буду признателен за любую информацию о том, что я сделал неправильно!

...