代码之家  ›  专栏  ›  技术社区  ›  arxakoulini

JavaFX-如何在模型包含列表时动态绑定TableView

  •  1
  • arxakoulini  · 技术社区  · 5 年前

    让我们假设我们有以下场景;

    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() 列表这样,将创建的列数将是最大列表的大小。列表较小的行的多余单元格将为空。

    1 回复  |  直到 5 年前
        1
  •  3
  •   Community Egal    4 年前

    您需要将问题分为多个步骤:

    1. 获取要在表中显示的人员列表
    2. 创建所需的列并设置自定义单元格值工厂
    3. 创建tableview

    分步代码:

    步骤1:获取要显示的人员列表

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

    这只是一种嘲弄。您肯定会访问您的模型或持久性层以获得人员列表。

    步骤2:获取要显示的列数

    private Integer getNumberOfFavoriteColumn(ObservableList<Person> persons){
        int maxNumberOfFavorite = 0;
        for(Person person : persons){
            maxNumberOfFavorite = Math.max(maxNumberOfFavorite, person.getNumbers().size());
        }
        return maxNumberOfFavorite;     
    }
    

    这里很简单。我们循环并检索收藏夹号码列表的最大大小。

    步骤3:创建所需列并设置自定义单元格值工厂

    我们需要为单元值工厂实现我们自己的回调。一种方法是创建一个实现回调的类(请注意,回调是一个函数接口,所以如果愿意,可以使用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;
        }
    

    如果此人没有此号码,但您可以根据自己的需要进行调整,我选择返回空字符串。

    步骤4:创建表视图

    现在我们拥有了创建tableview所需的一切:

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

    当做 昆廷。