TableView исключает нижнюю строку (всего) из сортировки

У меня есть простой TableView (Java FX 2.0, но я полагаю, проблема довольно общая), который получает функцию сортировки по умолчанию. Однако в последней строке таблицы есть общая сумма, поэтому я хотел бы исключить эту последнюю строку из алгоритма сортировки.

Я нашел решение для Swing JTable, которое состоит в создании отдельной таблицы для общей строки - это можно было бы транспонировать в TableView, но это кажется немного громоздким. Я попытался реализовать свой собственный компаратор, но я не думаю, что возможно создать такой, который будет работать как в порядке возрастания, так и в порядке убывания.


person assylias    schedule 14.03.2012    source источник


Ответы (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;
});
person assylias    schedule 13.01.2014

Основываясь на ответе лолсвемира, я успешно реализую «ВСЕГО» с помощью специального компаратора. Я установил компаратор с столбцом 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);
    }
}
person Tan Hui Onn    schedule 11.03.2013

У меня была такая же проблема, и из-за свойства 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));
  }
}

Это может выглядеть как взлом, но работает как шарм.

person user645859    schedule 08.10.2014