我有一个简单的 TableView(Java FX 2.0,但我想这个问题相当普遍),它获得了默认的排序功能。然而,表格的最后一行有一个总数,所以我想从排序算法中排除最后一行。
我找到了一个 Swing JTable 的解决方案,它包括为总行创建一个单独的表- 这可以转置为 TableView,但它似乎有点麻烦。我已经尝试实现我自己的比较器,但我认为不可能创建一个既可以升序又可以降序工作的比较器。
我有一个简单的 TableView(Java FX 2.0,但我想这个问题相当普遍),它获得了默认的排序功能。然而,表格的最后一行有一个总数,所以我想从排序算法中排除最后一行。
我找到了一个 Swing JTable 的解决方案,它包括为总行创建一个单独的表- 这可以转置为 TableView,但它似乎有点麻烦。我已经尝试实现我自己的比较器,但我认为不可能创建一个既可以升序又可以降序工作的比较器。
使用 JavaFX 8 可以定义排序策略,并且更容易解决问题。假设包含总计的行是TOTAL
:
table.sortPolicyProperty().set(t -> {
Comparator<Row> comparator = (r1, r2) ->
r1 == TOTAL ? 1 //TOTAL at the bottom
: r2 == TOTAL ? -1 //TOTAL at the bottom
: t.getComparator() == null ? 0 //no column sorted: don't change order
: t.getComparator().compare(r1, r2); //columns are sorted: sort accordingly
FXCollections.sort(t.getItems(), comparator);
return true;
});
根据 lolsvemir 的回答,我使用自定义比较器成功实现了“TOTAL”。我使用列的 sortTypeProperty 设置比较器:
col.setComparator(new BigDecimalColumnComparator(col.sortTypeProperty()));
自定义比较器:
public class BigDecimalColumnComparator implements Comparator<BigDecimal> {
private final ObjectProperty<TableColumn.SortType> sortTypeProperty;
public BigDecimalColumnComparator(ObjectProperty<TableColumn.SortType> sortTypeProperty) {
this.sortTypeProperty = sortTypeProperty;
}
@Override
public int compare(BigDecimal o1, BigDecimal o2) {
TableColumn.SortType sortType = sortTypeProperty.get();
if (sortType == null) {
return 0;
}
if (o1 instanceof TotalBigDecimal) {
if (sortType == TableColumn.SortType.ASCENDING) {
return 1;
} else {
return -1;
}
} else if (o2 instanceof TotalBigDecimal) {
if (sortType == TableColumn.SortType.ASCENDING) {
return -1;
} else {
return 1;
}
}
return o1.compareTo(o2);
}
}
我遇到了同样的问题,并且由于 TableView 属性调用单元格工厂来获取表中可见的尽可能多的行,而且不仅对于不超过 TableView.setItems() 方法设置的列表大小的行索引,IMO 它是最好直接由单元工厂为需要它的每一列设置汇总值。
这是此类单元工厂类的简单示例:
public class LocalDateTableCell<T> implements
Callback<TableColumn<T, LocalDate>, TableCell<T, LocalDate>> {
@Override
public TableCell<T, LocalDate> call(TableColumn<T, LocalDate> p) {
TableCell<T, LocalDate> cell = new TableCell<T, LocalDate>() {
@Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
setText(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.format(item));
}
if (getTableView().getItems().size() == getIndex())
setText("Test"); // This shows in the summary row
}
};
return cell;
}
}
这种方法的优点是这样的行根本不参与排序(因为它不在表项列表中)并且也不可选择。此外,通过重写 TableRow 工厂可以轻松为整个摘要行设置不同的背景颜色并将其与其他行区分开来。
但是,向下滚动时,此附加行将不可见,因为 TableView 滚动实现不知道附加行,并且只会滚动到视口底部项目列表中的最后一行。这可以通过覆盖 TableViewSkin.getItemCount() 方法来解决,如下例所示。重写 TableView 本身不是必需的,但如果经常使用此类表,建议这样做。
public class MyTableViewSkin<T> extends TableViewSkin<T> {
private TableView<T> tableView;
public MyTableViewSkin(final TableView<T> tableView) {
super(tableView);
this.tableView = tableView;
}
@Override
public int getItemCount() {
return tableView.getItems() == null || tableView.getItems().size() == 0 ?
0 : tableView.getItems().size() + 1;
}
}
public class MyTableView<S> extends TableView<S> {
public MyTableView() {
super();
setSkin(new MyTableViewSkin<>(this));
}
}
这可能看起来像一个黑客,但就像一个魅力。