假设我们有以下情况;
TableView<Person> table = new TableView<>();
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
table.getColumns().addAll(firstNameCol,lastNameCol);
ObservableList<Person> data = // get data
table.getItems().addAll()
还有一个看起来像这样的模型;
class Person{
private String firstName; // or SimpleStringProperty
private String lastName;
private List<Integer> favouriteNumbers; // or ListProperty etc
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public List<Integer> getFavouriteNumbers(){
return favouriteNumbers;
}
}
一个人可以有许多在运行时定义的喜欢的数字。我需要动态创建一个像这样的表;
名字|姓|最喜欢的1号|最喜欢的2号|最喜欢的3号|等等。
我可以通过遍历getFavouriteNumbers()
列表来动态创建和添加列。这样,将创建的列数将是最大列表的大小。列表较小的行的多余单元格为空。
问题是,我无法弄清楚如何为这些列应用绑定。
有什么想法吗?非常感谢。
答案 0 :(得分:1)
您需要以多个步骤拆分问题:
我使用了一个简单的Person类版本来解决您的问题。
class Person {
private final List<Integer> numbers;
public Person( Integer... numbers){
this.numbers = Arrays.asList(numbers);
}
public List<Integer> getNumbers(){
return numbers;
}
}
我们可以在应用程序中编写此方法:
private ObservableList<Person> createItems() {
ObservableList items = FXCollections.observableArrayList();
items.add(new Person(0,1,2,3,4));
items.add(new Person(2,3));
return items;
}
这只是一种模拟。您当然可以访问您的模型或持久层以获取Person列表。
private Integer getNumberOfFavoriteColumn(ObservableList<Person> persons){
int maxNumberOfFavorite = 0;
for(Person person : persons){
maxNumberOfFavorite = Math.max(maxNumberOfFavorite, person.getNumbers().size());
}
return maxNumberOfFavorite;
}
这里非常简单。我们循环并检索“最爱号码”列表的最大大小。
我们需要为单元格值工厂实现我们自己的回调。一种实现方法是创建一个实现Callback的类(请注意,callback是一个功能接口,因此您可以根据需要使用lambda甚至匿名类,也可以使用..)。
public class PersonCallback implements Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>> {
private Function<Person,Object> extractor;
public PersonCallback(Function<Person,Object> extractorFunction) {
extractor = extractorFunction;
}
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> cellData) {
return new SimpleObjectProperty(extractor.apply(cellData.getValue()));
}
}
然后我们可以创建列:
private List<TableColumn> createColumns(ObservableList<Person> persons) {
List<TableColumn> columns = new ArrayList();
for(int i = 0; i < getNumberOfFavoriteColumn(persons); i++) {
final int index = i;
TableColumn column = new TableColumn(String.format("Favorite Number %d", i + 1));
column.setCellValueFactory(new PersonCallback((person) -> { return person.getNumbers().size() > index ? person.getNumbers().get(index) : "";}));
columns.add(column);
}
return columns;
}
如果此人没有此号码,但您可以根据需要进行调整,我选择返回一个空字符串。
现在,我们拥有创建表视图所需的一切:
private TableView<Person> createTableView(){
ObservableList<Person> persons = createItems();
List<TableColumn> columns = createColumns(persons);
TableView<Person> tableView = new TableView();
tableView.getColumns().addAll(columns.toArray(new TableColumn[0]));
tableView.setItems(persons);
return tableView;
}
如果将所有内容放在一起,我们将获得:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class JavaFXApplication extends Application {
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(createTableView());
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView<Person> createTableView(){
ObservableList<Person> persons = createItems();
List<TableColumn> columns = createColumns(persons);
TableView<Person> tableView = new TableView();
tableView.getColumns().addAll(columns.toArray(new TableColumn[0]));
tableView.setItems(persons);
return tableView;
}
private List<TableColumn> createColumns(ObservableList<Person> persons) {
List<TableColumn> columns = new ArrayList();
for(int i = 0; i < getNumberOfFavoriteColumn(persons); i++) {
final int index = i;
TableColumn column = new TableColumn(String.format("Favorite Number %d", i + 1));
column.setCellValueFactory(new PersonCallback((person) -> { return person.getNumbers().size() > index ? person.getNumbers().get(index) : "";}));
columns.add(column);
}
return columns;
}
private ObservableList<Person> createItems() {
ObservableList items = FXCollections.observableArrayList();
items.add(new Person(0,1,2,3,4));
items.add(new Person(2,3));
return items;
}
private Integer getNumberOfFavoriteColumn(ObservableList<Person> persons){
int maxNumberOfFavorite = 0;
for(Person person : persons){
maxNumberOfFavorite = Math.max(maxNumberOfFavorite, person.getNumbers().size());
}
return maxNumberOfFavorite;
}
private class PersonCallback implements Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>> {
private Function<Person,Object> extractor;
public PersonCallback(Function<Person,Object> extractorFunction) {
extractor = extractorFunction;
}
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> cellData) {
return new SimpleObjectProperty(extractor.apply(cellData.getValue()));
}
}
private class Person {
private final List<Integer> numbers;
public Person( Integer... numbers){
this.numbers = Arrays.asList(numbers);
}
public List<Integer> getNumbers(){
return numbers;
}
}
}
当然可以改进此解决方案,但我认为它将帮助您理解概念并为您提供解决问题的指示(而且我只是很快开始使用JavaFX)
关于, 昆汀。
编辑:添加说明和格式