javafx: несколько событий в setRowFactory и объединение анонимного внутреннего класса и лямбда-выражений

У меня есть 2 набора событий, которые меняют внешний вид строки таблицы.

  1. таблица мигает, когда мигают некоторые условия
  2. подсветка таблицы при добавлении нового элемента

Предположим, мой TableView называется table, структура моего кода такая:

TableView<Trade> table = ... ;
table.setRowFactory(            private final BooleanBinding itemIsNewTrade = Bindings.isNotNull(itemProperty()).and(Bindings.equal(itemProperty(), recentlyAddedTrade));

        {
            // anonymous constructor:
            itemIsNewTrade.addListener((obs, wasNew, isNew) -> pseudoClassStateChanged(newTradePseudoClass, isNew));
        }   

            tv -> {
            TableRow<Trade> row = new TableRow<>();
            Timeline flasher = new Timeline(

                    new KeyFrame(Duration.seconds(0.5), e -> {
                        row.pseudoClassStateChanged(flashHighlight, true);
                    }),

                    new KeyFrame(Duration.seconds(1.0), e -> {
                        row.pseudoClassStateChanged(flashHighlight, false);
                    })
            );
            flasher.setCycleCount(Animation.INDEFINITE);

            ChangeListener<Boolean> cautionListener = (obs, cautionWasSet, cautionIsNowSet) -> {
                if (cautionIsNowSet) {
                    flasher.play();
                } else {
                    flasher.stop();
                    row.pseudoClassStateChanged(flashHighlight, false);
                }
            };

            row.itemProperty().addListener((obs, oldItem, newItem) -> {
                if (oldItem != null) {
                    oldItem.cautionProperty().removeListener(cautionListener);
                }
                if (newItem == null) {
                    flasher.stop();
                    row.pseudoClassStateChanged(flashHighlight, false);
                } else {
                    newItem.cautionProperty().addListener(cautionListener);
                    if (newItem.cautionProperty().get()) {
                        flasher.play();
                    } else {
                        flasher.stop();
                        row.pseudoClassStateChanged(flashHighlight, false);
                    }
                }
            });
            return row ;
        }
    );

ОБНОВЛЕНИЕ: Код для мигания таблицы взят из здесь, а код для подсветки таблицы взят из здесь. Я попытался объединить оба вместе, имея структуру, подобную приведенной выше.

Но я получаю ошибку. Я просто не знаю, как объединить анонимный внутренний класс и лямбда-выражение вместе

Как мне это преодолеть?


person mynameisJEFF    schedule 24.08.2015    source источник


Ответы (1)


Лучший способ сделать это — создать отдельный класс TableRow вместо анонимного внутреннего класса.

Я создал пример реализации ниже.

Некоторые вещи, о которых стоит упомянуть:

  1. Вам нужно определить стиль .table-row-cell:new в файле CSS для недавно добавленного TableRow.
  2. Вам нужно определить стиль .table-row-cell:flash в файле CSS для TableRow(ов), которые в данный момент мигают.
  3. Конструктор должен знать (ObjectExpression), где хранится недавно добавленный элемент, что, вероятно, recentlyAddedTrade в вашем случае.
  4. Конструктор должен знать (Function<T, BooleanExpression>), как извлечь свойство, определяющее состояние мигания. В вашем случае это должно быть Trade::cautionProperty.

Вот пример реализации:

public static class AnimatedTableRow<T> extends TableRow<T> {

    private static final PseudoClass PS_NEW = PseudoClass.getPseudoClass("new");
    private static final PseudoClass PS_FLASH = PseudoClass.getPseudoClass("flash");

    private final ObjectExpression<T> recentItem;
    private final InvalidationListener recentlyAddedListener = fObs -> recentItemChanged();

    private final Function<T, BooleanExpression> flashExtractor;
    private final ChangeListener<Boolean> flashListener = (fObs, fOld, fNew) -> flasherChanged(fNew);
    private final Timeline flashTimeline;

    public AnimatedTableRow(ObjectExpression<T> fRecentlyAddedProperty,
            Function<T, BooleanExpression> fFlashExtractor) {
        recentItem = fRecentlyAddedProperty;
        recentItem.addListener(new WeakInvalidationListener(recentlyAddedListener));

        flashExtractor = fFlashExtractor;
        flashTimeline = new Timeline(
                new KeyFrame(Duration.seconds(0.5), e -> pseudoClassStateChanged(PS_FLASH, true)),
                new KeyFrame(Duration.seconds(1.0), e -> pseudoClassStateChanged(PS_FLASH, false)));
        flashTimeline.setCycleCount(Animation.INDEFINITE);
    }

    private void flasherChanged(boolean fNew) {
        if (fNew) {
            flashTimeline.play();
        } else {
            flashTimeline.stop();
            pseudoClassStateChanged(PS_FLASH, false);
        }
    }

    private void recentItemChanged() {
        final T tmpRecentItem = recentItem.get();
        pseudoClassStateChanged(PS_NEW, tmpRecentItem != null && tmpRecentItem == getItem());
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        if (getItem() != null) {
            final BooleanExpression be = flashExtractor.apply(getItem());
            if (be != null) {
                be.removeListener(flashListener);
            }
        }

        super.updateItem(item, empty);

        if (getItem() != null) {
            final BooleanExpression be = flashExtractor.apply(getItem());
            if (be != null) {
                be.addListener(flashListener);
                flasherChanged(be.get());
            }
        }

        recentItemChanged();
    }
}

Использование:

table.setRowFactory(tableView -> new AnimatedTableRow<>(recentlyAddedPerson, Person::flashProperty));
person eckig    schedule 27.08.2015
comment
И как бы я назвал этот класс в setRowFactory() ? - person mynameisJEFF; 27.08.2015