Pergunta

Eu tenho um TableView simples (Java FX 2.0, mas suponho que o problema seja bastante genérico) que obtém o recurso de classificação padrão.No entanto, a tabela tem um total na última linha, então gostaria de excluir essa última linha do algoritmo de classificação.

Encontrei uma solução para um Swing JTable que consiste em criando uma tabela separada para a linha total - isso seria transponível para um TableView, mas parece um pouco complicado.Tentei implementar meu próprio Comparador, mas não acho que seja possível criar um que funcione em ordem crescente e decrescente.

Foi útil?

Solução

Com o JavaFX 8 é possível definir uma política de classificação e o problema é mais fácil de resolver.Supondo que a linha que contém os totais seja 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;
});

Outras dicas

Com base na resposta de lolsvemir, implementei com sucesso um "TOTAL" com um comparador personalizado.Defino o comparador com sortTypeProperty da coluna:col.setComparator(new BigDecimalColumnComparator(col.sortTypeProperty()));

Comparador personalizado:

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

e se você sempre retornar 0 no método compareTo do seu comparador ()?Isso significa que todos os elementos "são os mesmos" e nenhuma troca de lugares deve ocorrer?

Eu tive o mesmo problema e, devido à propriedade TableView chamar a fábrica de células para quantas linhas forem visíveis na tabela, e não apenas para índices de linha até o tamanho da lista definida pelo método TableView.setItems(), IMO é é melhor definir o valor de resumo diretamente pela fábrica de células para cada coluna que precisa dele.

Aqui está um exemplo simples dessa classe de fábrica de células:

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;
  }
}

As vantagens desta abordagem são que tal linha não está envolvida na classificação (porque não está na lista de itens da tabela) e também não é selecionável.Além disso, com a substituição da fábrica TableRow, é fácil definir cores de fundo diferentes para toda a linha de resumo e distingui-la de outras linhas.

No entanto, essa linha adicional não ficará visível durante a rolagem para baixo porque a implementação de rolagem do TableView não conhece a linha adicional e rolará apenas até a última linha da lista de itens na parte inferior da janela de visualização.Isso pode ser resolvido substituindo o método TableViewSkin.getItemCount(), como no exemplo a seguir.Substituir o próprio TableView não é necessário, mas é recomendado se essa tabela for usada com frequência.

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

Isso pode parecer um hack, mas funciona perfeitamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top