TableView从排序中排除底行(总计)

时间:2012-03-14 10:17:52

标签: java javafx javafx-2 javafx-8

我有一个简单的TableView(Java FX 2.0,但我认为问题相当通用),它获得了默认的排序功能。但是该表在最后一行中有一个总数,所以我想从排序算法中排除最后一行。

我找到了一个包含在creating a separate table for the total row中的Swing JTable的解决方案 - 它可以转换为TableView,但看起来有点麻烦。我已经尝试过实现我自己的比较器,但是我认为不可能创建一个既可以升级也可以升级的比较器。降序。

4 个答案:

答案 0 :(得分:3)

基于lolsvemir的回答,我成功地使用自定义Comparator实现了“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);
    }
}

答案 1 :(得分:3)

使用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;
});

答案 2 :(得分:2)

如果你总是在Comparator的compareTo()方法中返回0?这意味着所有元素“都是相同的”并且不应该发生地方交换?

答案 3 :(得分:1)

我有同样的问题,并且由于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));
  }
}

这可能看起来像一个黑客,但就像一个魅力。