如果您需要在 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);
}
}
}
屏幕截图顺序: