JavaFX TableView Игнорировать пустые ячейки при сортировке - PullRequest
0 голосов
/ 14 ноября 2018

У меня проблемы при сортировке столбцов, когда есть пустые ячейки.

Я создал новый Comparator для моего codeMed столбца:

codeMed.setComparator(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {

            if (o1 == null)return -1;
            if (o2 == null) return -1;
            return o1 < o2 ? -1 : o1 == o2 ? 0 :1;
        }
    });

Сначала кажется, что он работает нормально:

It works !

Но если я решу отсортировать другой столбец, то сортировка столбца codeMed произойдет:

It doesn't work :(

Я представляюошибка в компараторе, но я не знаю, в чем проблема.

EDIT : я хочу, чтобы нулевые значения всегда были в нижней части столбца.Я пробовал что-то подобное:

if (codeMed.getSortType() == TableColumn.SortType.DESCENDING) {
    return (o1 != null ? o1 : Integer.MAX_VALUE) - (o2 != null ? o2 : Integer.MAX_VALUE);
} else if (codeMed.getSortType()==TableColumn.SortType.ASCENDING){
    return (o1 != null ? o1 : Integer.MIN_VALUE) - (o2 != null ? o2 : Integer.MIN_VALUE);
}
return 0;

Но это не работает: / (Может быть, из-за проблемы, которую предлагает Слав)

Мое решение:

СпасибоJai, я адаптирую твой код только потому, что хочу использовать его для 2 разных столбцов:

Comparator<Integer> integerComparator = new Comparator<>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            final boolean isDesc = tabInfosPatient.getSortOrder().get(0).getSortType() == TableColumn.SortType.DESCENDING;
            if (o1 == null && o2 == null) return 0;
            else if (o1 == null) return isDesc ? -1 : 1;
            else if (o2 == null) return isDesc ? 1 : -1;
            else return Integer.compare(o1, o2);
        }
    };

1 Ответ

0 голосов
/ 14 ноября 2018

Я удивлен, что это даже сработало однажды. Вот то, что я думаю, будет хорошо работать:

codeMed.setComparator(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return (o1 != null ? o1 : Integer.MAX_VALUE) - (o2 != null ? o2 : Integer.MAX_VALUE);
        }
    });

Это предполагает, что любое значение null обрабатывается так, как если бы оно представляло наибольшее возможное значение int. Это заставит его переместиться в конец списка в возрастающем отсортированном столбце или вверху, если он находится в убывающем отсортированном столбце. Если необходимо обратное, переключите Integer.MAX_VALUE на Integer.MIN_VALUE.

То, что вы сделали, не работает, потому что вы нарушили это:

Разработчик должен убедиться, что sgn (сравнить (x, y)) == -sgn (сравнить (y, x)) для всех x и y. (это подразумевает, что сравнение (x, y) должно бросить исключение тогда и только тогда, когда сравнение (y, x) вызывает исключение.)

Примером такого нарушения является случай, когда o1 равен 5, а o2 равен null. В этом случае compare(o1, o2) возвращает -1 и compare(o2, o1) возвращает -1. Один из них должен возвращать положительное значение, а другой - отрицательное, либо оба должны возвращать 0.

Обновление

Это то, что вам нужно.

public class Model {
    private final ObjectProperty<Integer> v = new SimpleObjectProperty<>();

    public Model(Integer v) {
        this.v.setValue(v);
    }

    public final ObjectProperty<Integer> vProperty() {
        return this.v;
    }

    public final Integer getV() {
        return this.vProperty().get();
    }

    public final void setV(final Integer v) {
        this.vProperty().set(v);
    }
}

ObservableList<Model> list = FXCollections.observableArrayList();
list.addAll(new Model(20), new Model(-30), new Model(null), new Model(10));

TableView<Model> tv = new TableView<>();
TableColumn<Model, Integer> tc = new TableColumn<>();
tc.setCellValueFactory(new PropertyValueFactory<>("v"));
tv.getColumns().add(tc);
tv.setItems(list);

Comparator<Integer> ascComparator = (o1, o2) ->
                                (o1 != null ? o1 : Integer.MAX_VALUE) - 
                                (o2 != null ? o2 : Integer.MAX_VALUE);

Comparator<Integer> descComparator = (o1, o2) ->
                                (o1 != null ? o1 : Integer.MIN_VALUE) - 
                                (o2 != null ? o2 : Integer.MIN_VALUE);

@SuppressWarnings("unchecked")
Comparator<Integer> defaultComparator = TableColumn.DEFAULT_COMPARATOR;

tc.comparatorProperty().bind(
        Bindings.when(tc.sortTypeProperty().isEqualTo(SortType.ASCENDING))
                .then(ascComparator)
                .otherwise(
                        Bindings.when(tc.sortTypeProperty().isEqualTo(SortType.DESCENDING))
                                .then(descComparator)
                                .otherwise(defaultComparator)));

Кроме того, я хотел бы отметить, что, хотя использование Integer.MIN_VALUE и Integer.MAX_VALUE должно работать большую часть времени, существует гораздо более высокий риск возникновения проблем целочисленного и переполнения, но я не уверен, что это проблема использования компараторов и сопоставимых объектов.

Если вы хотите быть более безопасным, сделайте кучу if-else:

Comparator<Integer> ascComparator = (o1, o2) -> {
    if (o1 == null && o2 == null) return 0;
    else if (o1 == null && o2 != null) return -1;
    else if (o1 != null && o2 == null) return 1;
    else return Integer.compare(o1, o2);
};

Обновите снова

Посмотрев на то, что вы пытались, я понял, что это работает:

Comparator<Integer> comparator = (o1, o2) -> {
    final boolean isDesc = tc.getSortType() == SortType.DESCENDING;
    if (o1 == null && o2 == null) return 0;
    else if (o1 == null && o2 != null) return isDesc ? -1 : 1;
    else if (o1 != null && o2 == null) return isDesc ? 1 : -1;
    else return Integer.compare(o1, o2);
};
...