Получить строку из метода переопределения TableView и UpdateItem

MapeSVK спросил: 28 апреля 2018 в 09:51 в: java

Я получаю строку из tableView. Я использую setRowFactory для получения строки, а затем я использую ее.

Мне нужно переопределить метод updateItem, чтобы получить каждую строку, и если элемент внутри этой строки имеет ошибку, тогда используйте красный цвет, иначе используйте зеленый цвет.

Элемент внутри строки является "историческим" объектом, потому что строки представляют собой фрагменты истории - истории, которые были созданы после выполнения некоторых действий в приложении.

Итак, у меня есть что-то вроде этого:

@Override
        protected void updateItem(History history, boolean empty) {
            super.updateItem(history, empty);
            if (empty) {
                setStyle("");
            } else if (history.isHasError() == true) {
                getStyleClass().clear();
                getStyleClass().add("errorHistoryRow");
            } else if (history.isHasError() == false){
                getStyleClass().clear();
                getStyleClass().add("");
            }
        }

Но мне нужно добавить этот элемент updateItem к уже определенной строке в этом методе.

private void openErrorMessageAfterHoveringOverRow() {        historyTableView.setRowFactory(tableView -> {
        final TableRow<History> row = new TableRow<>();        for (History history : model.getAllHistoryObservableArrayList()) {
            ***I NEED TO PUT IT HERE***
        }                           for (History his : model.getAllHistoryObservableArrayList()) {            row.hoverProperty().addListener((observable) -> {
                History historyRow = row.getItem();                Point p = MouseInfo.getPointerInfo().getLocation();
                int x = p.x;
                int y = p.y;                Popup popup = new Popup();
                popup.setX(x - 300);
                popup.setY(y - 200);
                TextArea ta = new TextArea();                AnchorPane layout = new AnchorPane();
                Scene scene = new Scene(layout);
                stageSingleton().setScene(scene);                if (row.isHover() && his.equals(historyRow)) {
                    ta.setText(row.getItem().getErrorMessage());
                    popup.getContent().addAll(ta);
                    stageSingleton().show();
                    popup.show(stageSingleton());                } else if (!row.isHover() && his.equals(historyRow)) {
                    popup.hide();
                    stageSingleton().close();
                }
            });
        }
        return row;
    });       
}

Итак, как я могу, пожалуйста, внедрить метод updateItem в уже определенную строку в этом методе? Потому что методы ниже работают, но у меня не может быть 2 разных метода setRowFactory в моем проекте. Поэтому мне нужно объединить их одним способом.

public void test() {
        historyTableView.setRowFactory(tableView -> new TableRow<History>() {
        @Override
        protected void updateItem(History history, boolean empty) {
            super.updateItem(history, empty);
            if (empty) {
                setStyle("");
            } else if (history.isHasError() == true) {
                getStyleClass().clear();
                getStyleClass().add("errorHistoryRow");
            } else if (history.isHasError() == false){
                getStyleClass().clear();
                getStyleClass().add("");
            }
        }
    });
}

2 ответа

Есть решение
fabian ответил: 28 апреля 2018 в 10:18

Невозможно использовать разные rowFactory s (по крайней мере, вы не можете удалить строки, которые уже были созданы). Вам нужно объединить функциональные возможности в строках, возвращаемых вашим rowFactory.

Некоторые дополнительные примечания:

  • Вам также необходимо удалить класс стиля, если ваша строка становится пустой. Однако очистка классов стиля препятствует стилю по умолчанию (вы удаляете класс стиля table-row-cell). В этом случае проще использовать псевдокласс. Более того, добавление пустой строки в качестве класса стилей никак не выгодно.
  • Не используйте InvalidationListener для свойства hover. Этот тип слушателя запускается каждый раз, когда значение изменяется, если оно изменяется от true до false или наоборот.
public class HistoryRow extends TableRow<History> {    private static final PseudoClass ERROR = PseudoClass.getPseudoClass("error");    public HistoryRow() {
        hoverProperty().addListener((o, oldValue, newValue) -> {
            if (newValue) {
                History historyRow = getItem();
                if (historyRow != null && historyRow.isHasError()) {
                    // TODO: display popup here
                } 
            }
        });
    }    @Override
    protected void updateItem(History history, boolean empty) {
        super.updateItem(history, empty);
        pseudoClassStateChanged(ERROR, !empty && history != null && history.isHasError());
    }}

В вашей таблице стилей CSS, изменяющейся от класса стиля до псевдокласса, вам нужно настроить селектора. Вам нужно использовать селектор псевдокома :error вместо селектора классов .errorHistoryRow.

Динамическое изменение от ошибочного элемента истории до не-ошибочного и наоборот сделайте, добавив BooleanProperty в History и добавив / удалив прослушиватель в методе updateItem, если это необходимо.

MapeSVK ответил: 28 апреля 2018 в 10:30
Спасибо за ваше решение. Я действительно не могу с этим работать. Это сложно для меня, поэтому, если вы можете сказать мне несколько вещей, это может мне очень помочь. 1. Где я могу поместить свой код для изменения фона прямо сейчас? после вызова этого псевдокласса? 2. Как я могу создать этот класс в моем контроллере? где поставить все это, пожалуйста? Но это выглядит отлично. Спасибо
fabian ответил: 28 апреля 2018 в 10:39
Стиль для строки делается из таблицы стилей CSS, добавленной в сцену / TableView или одного из ее предков. Одно из его правил будет выглядеть так: .table-row-cell:error { -fx-selection-bar-non-focused: red; -fx-selection-bar: purple; }. Вы можете использовать класс из метода initialize вашего контроллера: historyTableView.setRowFactory(t -> new HistoryRow()) или создать статический заводский метод для обратного вызова и использовать <HistoryRow fx:factory="methodName"/> выполнить это назначение из fxml.
MapeSVK ответил: 28 апреля 2018 в 11:15
Он работает, и он выглядит идеально. Большое спасибо! Хорошего дня.
ilya ответил: 28 апреля 2018 в 09:59

Вы можете вызывать метод updateItem другого класса и иметь их оба вместо того, чтобы внедрять его внутри метода. Итак, вы можете сделать

Updater updater = new Updater();//class which contains updateItem(History history,boolean empty) method
    for (History history : getAllHistoryObservableArrayList()) {
        updater.updateItem(history, empty)
    }