如果你需要一個解決方案,如果在Person
情況下性質發生改變,這將更新表,你可以這樣做:
ObservableList<Person> persons = FXCollections
.observableArrayList(p -> new Observable[] { p.nameProperty(), p.countProperty() });
ObservableList<String> uniqueNames = FXCollections.observableArrayList();
persons.addListener((Change<? extends Person> c) -> uniqueNames
.setAll(persons.stream().map(Person::getName).distinct().collect(Collectors.toList())));
TableView<String> table = new TableView<>(uniqueNames);
TableColumn<String, String> name = new TableColumn<>("Name");
name.setCellValueFactory(n -> new SimpleStringProperty(n.getValue()));
TableColumn<String, Number> count = new TableColumn<>("Count");
count.setCellValueFactory(n -> Bindings.createIntegerBinding(() -> persons.stream()
.filter(p -> p.getName().equals(n.getValue())).collect(Collectors.summingInt(Person::getCount)), persons));
這個解決方案不是特別高效:如果底層列表中的數據發生更改(包括Person
實例中的屬性更改),所有可見單元將重新計算。這應該適用於合理的小名單;但是如果您有大量數據,則可能需要以更智能的方式處理列表中的更改(persons.addListener(...)
)(這可能會非常複雜)。
這是一個SSCCE。它顯示兩個表格:一個是具有完整人員列表的常規表格;另一個是上面設置的表格,顯示了「分組」列表。您可以通過填寫文本字段(第二個需要是整數)並按下「添加」將項目添加到主列表,或者通過選擇項目並按刪除來刪除條目。 「全表」也是可編輯的,因此您可以測試更改現有值。
import java.util.stream.Collectors;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.converter.IntegerStringConverter;
public class GroupedTable extends Application {
@Override
public void start(Stage primaryStage) {
ObservableList<Person> persons = FXCollections
.observableArrayList(p -> new Observable[] { p.nameProperty(), p.countProperty() });
ObservableList<String> uniqueNames = FXCollections.observableArrayList();
persons.addListener((Change<? extends Person> c) -> uniqueNames
.setAll(persons.stream().map(Person::getName).distinct().collect(Collectors.toList())));
TableView<String> table = new TableView<>(uniqueNames);
TableColumn<String, String> name = new TableColumn<>("Name");
name.setCellValueFactory(n -> new SimpleStringProperty(n.getValue()));
TableColumn<String, Number> count = new TableColumn<>("Count");
count.setCellValueFactory(n -> Bindings.createIntegerBinding(() -> persons.stream()
.filter(p -> p.getName().equals(n.getValue())).collect(Collectors.summingInt(Person::getCount)), persons));
table.getColumns().add(name);
table.getColumns().add(count);
TableView<Person> fullTable = new TableView<>(persons);
fullTable.setEditable(true);
TableColumn<Person, String> allNamesCol = new TableColumn<>("Name");
TableColumn<Person, Integer> allCountsCol = new TableColumn<>("Count");
allNamesCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
allNamesCol.setCellFactory(TextFieldTableCell.forTableColumn());
allCountsCol.setCellValueFactory(cellData -> cellData.getValue().countProperty().asObject());
allCountsCol.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
fullTable.getColumns().add(allNamesCol);
fullTable.getColumns().add(allCountsCol);
TextField nameTF = new TextField();
TextField countTF = new TextField();
Button add = new Button("Add");
add.setOnAction(e -> {
persons.add(new Person(nameTF.getText(), Integer.parseInt(countTF.getText())));
nameTF.clear();
countTF.clear();
});
Button delete = new Button("Delete");
delete.setOnAction(e -> persons.remove(fullTable.getSelectionModel().getSelectedItem()));
delete.disableProperty().bind(fullTable.getSelectionModel().selectedItemProperty().isNull());
HBox controls = new HBox(5, new Label("Name:"), nameTF, new Label("Count:"), countTF, add, delete);
BorderPane root = new BorderPane(new HBox(5, fullTable, table));
root.setBottom(controls);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty count = new SimpleIntegerProperty();
public Person(String name, int count) {
setName(name);
setCount(count);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final IntegerProperty countProperty() {
return this.count;
}
public final int getCount() {
return this.countProperty().get();
}
public final void setCount(final int count) {
this.countProperty().set(count);
}
}
}
屏幕截圖的序列:
那麼不要允許'ObservableList'上的重複,基於'Name'。所以如果兩個'人'具有相同的名字,那麼哪一個會出現?只有一個會出現'number =所有人的總數'?如何用項目填充'ObservableList'? – GOXR3PLUS
底層列表可能有多大?特別是,如果底層列表有任何更改,重新計算整個表是否可以接受?或者這會令人望而卻步,在性能方面呢? (另外,這裏TreeTableView會更合適嗎?) –
@ GOXR3PLUS該列表將在應用程序開始時填充。是的,只有一個會出現,數字應該是計數的總和。 – Nibor