JavaFX TableView排序时忽略空单元格

时间:2018-11-14 03:17:14

标签: java javafx tableview

在有空单元格的情况下对列进行排序时遇到问题。

我为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 :(

我认为错误出在比较器中,但我不知道出了什么问题。

编辑:我希望空值始终位于该列的底部。我尝试过这样的事情:

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;

但是它不起作用:/(也许是因为Slaw建议的问题)

我的解决方案:

非常感谢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 :(得分:2)

令我惊讶的是,它甚至曾经工作过一次。我认为这会很好:

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(compare(x,y))== -sgn(compare(y,   x))表示所有x和y。(这意味着compare(x,y)必须抛出一个   并且仅当compare(y,x)引发异常时才发生异常。)

o15o2null时,便是这种违规的例子。在这种情况下,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_VALUEInteger.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);
};