2012-03-14 90 views
3

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

我找到了一个Swing JTable的解决方案,该解决方案由creating a separate table for the total row组成 - 这可以转置为TableView,但看起来有点麻烦。我尝试过实施自己的比较器,但我不认为有可能创建一个可以在升序&降序下工作的比较器。

回答

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

如果你总是在比较器的compareTo()方法中返回0?这意味着所有的元素“都是一样的”,不应该发生地方交换?

+0

谢谢 - 如果表中有10行(0到9),第9行是总数,我希望能够对0到8行进行排序,并总是在第9行... – assylias 2012-03-14 10:27:59

+0

嗯,你可以将自己的类型放在列中,并将最后一行的子类放在比较器中,检查该类的instanceof,如果是,则返回1(-1)。你必须处理你的对象类型的ColumnFormatters才能很好地显示它。 – darijan 2012-03-14 13:54:52

+0

这确实有用 - 如果我找不到更清洁的东西,我会牢记它... – assylias 2012-03-14 14:00:26

3

基于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); 
    } 
} 
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)); 
    } 
} 

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