美文网首页
2021-03-20_TableView

2021-03-20_TableView

作者: 微笑碧落 | 来源:发表于2021-04-23 12:37 被阅读0次

    1.定义数据模型(Data Model)

    • 当你在JavaFX应用程序中创建表格时,一个最佳实践是:创建一个类用于定义数据模型并且提供方法和属性。
    • 事实上这个也符合MVC设计模式
    • 例子中的Property类型,详见后续文章
    public static class Person {
        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
    }
    
    

    2.创建OBservableList

    • ObservableList对象具有自动追踪其包含元素的改变的功能,所以TableView的内容将会在数据改变时自动更新。
    final ObservableList<Person> data = FXCollections.observableArrayList(
        new Person(),
        new Person(),
        new Person(),
        new Person(),
        new Person()
    );
    

    3.创建TableColumn并添加进TableView

    • 这一步可以通过FXML文件来实现。也可以通过如下代码来实现
    • 不指明TableColumn的数据类型
    TableColumn firstNameCol = new TableColumn("FirstName");
    
    • 指明TableColumn的数据类型
    TableColumn<Person, String> firstNameCol =  new TableColumn<>("FirstName");
    
    • 在FXML中定义一个TableColmn。注意在controller中定义的TableColumn可以带有泛型
    @FXML
    private TableColumn<DocArg,String> argValueColumn;
    
    • 添加TableColumn进TableView。如果是在FXML中创建的。这个步骤可以省略
    tableView.getColumns().add(tableColumn);
    

    4.把数据关联到表格的列。

    • setCellValueFactory方法为每列指定了一个单元格工厂(cell factory),这些cell factory是通过PropertyValueFactory类来实现的,它将Person类中对应的属性映射到对应的表格列中。
    • 当数据模型被定义完毕,并且数据被关联到列之后,你可以通过TableView类的setItems方法来向表格中添加数据:如:table.setItems(data)。
    • 如果没有指明TableColumn的数据类型:
    firstNameCol.setCellValueFactory(
        new PropertyValueFactory<>("firstName")
    );
    
    • 指明TableColumn的数据类型的时候。注意getValue()方法。
    • 当数据模型里面包含对象的时候,为了访问这个嵌套对象,就需要用这个方式。
    tableColumn.setCellValueFactory(tf -> tf.getValue().getArgsList().get(1).valueProperty());
    

    5.增加删除行

    • 事实上是通过操作设置给TableView对象的OBservableList来实现的。
    • ObservableList对象具有自动追踪其包含元素的改变的功能,所以TableView的内容将会在数据改变时自动更新。

    6.编辑单一单元格内容

    • 使用setCellFactory,指定TextFieldTableCell类来使其变成一个文本域。
    • setOnEditCommit方法处理编辑过程,并且将更新后的值分配给对应的表格单元格(事实上是传给对应的model)
    firstNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
    firstNameCol.setOnEditCommit(
        (CellEditEvent<Person, String> t) -> {
            ((Person) t.getTableView().getItems().get(t.getTablePosition().getRow()))
            .setFirstName(t.getNewValue());
    });
    

    7.ComboBoxCell指定选项值

    typeColumn.setCellFactory(t->{
      ObservableList<String> typeList = FXCollections.observableArrayList("单行输入",
                        "多行输入",
                        "单选输入",
                        "今天日期",
                        "昨天日期",
                        "明天日期");
      ComboBoxTableCell<DocArg,String > comboBoxTableCell = new ComboBoxTableCell<>(typeList);
      return comboBoxTableCell;
     });
    
    //简单版本
    outageTypeColumn.setCellFactory(t-> new ComboBoxTableCell<>(MissionTextParser.MISSION_OUTAGE));
    

    8.设置列自动铺满可用控件

    8.1代码中设置

    Column Resize Policy //在Scene Builder软件的控件属性设置项里面。修改成 constrained-resize。确保这个TableView的列能够铺满所有的可用空间。
    

    8.2. FXML文件中如下修改

    <TableView >
      <columnResizePolicy>
        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
        </columnResizePolicy>
     </TableView>
    

    9. 添加序号列

    • DocType替换为数据模型类即可
    noColumn.setCellFactory((col) ->{
      TableCell<DocType, String> cell = new TableCell<DocType, String>() {
        @Override
        public void updateItem(String item, boolean empty) {
          super.updateItem(item, empty);
          this.setText(null);
          this.setGraphic(null);
    
           if (!empty) {
            int rowIndex = this.getIndex() + 1;
             this.setText(String.valueOf(rowIndex));
          }
      }};
      return cell;
    });
    

    10. 获得用户选择的行

    int recordIndex = recordTableView.getSelectionModel().getSelectedIndex();
    

    11.修改列的宽度

    noColumn.setMaxWidth(50);
    checkedCol.setMaxWidth(50);
    noColumn.setMinWidth(50);
    checkedCol.setMinWidth(50);
    

    11.增加选择框

    • 效果如下


      image.png

    11.1 CheckBoxTableCell类

    /* CheckBoxTableCell.java 1.0 2010-2-2
     *
     * Copyright (c) 2012 by Chen Zhiwu
     * All rights reserved.
     *
     * The copyright of this software is own by the authors.
     * You may not use, copy or modify this software, except
     * in accordance with the license agreement you entered into
     * with the copyright holders. For details see accompanying license
     * terms.
     */
    public class CheckBoxTableCell<S, T> extends TableCell<S, T> {
        private final CheckBox checkBox;
        private final boolean showText;
        private final Callback<T, String> toString;
        private final Callback<Integer, ObservableValue<Boolean>> getSelectedProperty;
        private ObservableValue<Boolean> booleanProperty;
    
    
        public CheckBoxTableCell() {
            this(null, null);
        }
    
        public CheckBoxTableCell(
                Callback<Integer, ObservableValue<Boolean>> toString) {
            this(toString, null);
        }
    
        public CheckBoxTableCell(
                Callback<Integer, ObservableValue<Boolean>> getSelectedProperty,
                Callback<T, String> toString) {
            this.getSelectedProperty = getSelectedProperty;
            this.toString = toString;
            this.showText = toString != null;
            this.checkBox = new CheckBox();
            setAlignment(Pos.CENTER);
            setGraphic(checkBox);
    
            if (showText) {
                checkBox.setAlignment(Pos.CENTER_LEFT);
            }
        }
    
        public CheckBoxTableCell(
                Callback<T, ObservableValue<Boolean>> callback,
                Callback<Integer, ObservableValue<Boolean>> getSelectedProperty,
                Callback<T, String> toString) {
            this.getSelectedProperty = getSelectedProperty;
            this.toString = toString;
            this.showText = toString != null;
            this.checkBox = new CheckBox();
            setAlignment(Pos.CENTER);
            setGraphic(checkBox);
    
            if (showText) {
                checkBox.setAlignment(Pos.CENTER_LEFT);
            }
        }
    
        @Override
        protected void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
                setGraphic(null);
                return;
            }
            if (this.showText) {
                setText(this.toString.call(item));
            }
            setGraphic(this.checkBox);
            if (this.booleanProperty instanceof BooleanProperty)
                this.checkBox.selectedProperty().unbindBidirectional(
                        (BooleanProperty) this.booleanProperty);
            ObservableValue localObservableValue = getSelectedProperty();
            if (localObservableValue instanceof BooleanProperty) {
                this.booleanProperty = localObservableValue;
                this.checkBox.selectedProperty().bindBidirectional(
                        (BooleanProperty) this.booleanProperty);
            }
            this.checkBox.visibleProperty().bind(getTableView().editableProperty()
                    .and(getTableColumn().editableProperty())
                    .and(editableProperty()));
        };
    
        private ObservableValue getSelectedProperty() {
            return ((this.getSelectedProperty != null) ? (ObservableValue) this.getSelectedProperty
                    .call(Integer.valueOf(getIndex())) : getTableColumn()
                    .getCellObservableValue(getIndex()));
        }
    }
    

    11.2CellFactory类

    public class CellFactory {
    
        //         table check box
    
    
        public static <S> Callback<TableColumn<S, Boolean>, TableCell<S, Boolean>> tableCheckBoxColumn() {
            return tableCheckBoxColumn(null, null);
        }
    
        public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> tableCheckBoxColumn(
                Callback<Integer, ObservableValue<Boolean>> paramCallback) {
            return tableCheckBoxColumn(paramCallback, null);
        }
    
        public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> tableCheckBoxColumn(
                Callback<Integer, ObservableValue<Boolean>> paramCallback,
                boolean paramBoolean) {
            Callback<T, String> callback = new Callback<T, String>() {
                @Override
                public String call(T t) {
                    return ((t == null) ? "" : t.toString());
                }
            };
            return tableCheckBoxColumn(paramCallback, callback);
        }
    
        public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> tableCheckBoxColumn(
                final Callback<Integer, ObservableValue<Boolean>> getSelectedProperty,
                final Callback<T, String> toString) {
            return new Callback<TableColumn<S, T>, TableCell<S, T>>() {
                @Override
                public TableCell<S, T> call(TableColumn<S, T> paramTableColumn) {
                    return new CheckBoxTableCell<S,T>(getSelectedProperty,toString);
                }
            };
        }
    }
    

    11.3使用方法

    • 把FileWrap换成对应的Model即可。
    • 其中的filetable由fxml文件获取。
    • 注意checkedCol.setCellValueFactory(new PropertyValueFactory<>("checked"));需要指定model正确的BooleanProperty属性名称,否则无法双向绑定更新
    • 注意g.isChecked()需要和model一致
    public class FileWrap {
        private StringProperty fileName;
        private BooleanProperty checked;
    
        public String getFileName() {
            return fileName.get();
        }
    
        public StringProperty fileNameProperty() {
            return fileName;
        }
    
        public void setFileName(String fileName) {
            this.fileName.set(fileName);
        }
    
        public boolean isChecked() {
            return checked.get();
        }
    
        public BooleanProperty checkedProperty() {
            return checked;
        }
    
        public void setChecked(boolean checked) {
            this.checked.set(checked);
        }
    
        public FileWrap() {
            this.checked = new SimpleBooleanProperty(false);
            this.fileName = new SimpleStringProperty("/");
        }
    }
    
    public class MainController implements Initializable {
        ObservableList<FileWrap> fileWraps = FXCollections.observableArrayList();
    
        @FXML
        private TableView<FileWrap> filesTable;
    
        @Override
        public void initialize(URL location, ResourceBundle resources) {
    
            //选择列
            TableColumn<FileWrap, Boolean> checkedCol= new TableColumn<>("选择");
            checkedCol.setCellValueFactory(new PropertyValueFactory<>("checked"));
            checkedCol.setCellFactory(CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                @Override
                public ObservableValue<Boolean> call(Integer index) {
                    final FileWrap g= filesTable.getItems().get(index);
                    ObservableValue<Boolean> retval = new SimpleBooleanProperty(g,"available",g.isChecked());
                    retval.addListener(new ChangeListener<Boolean>() {
                        @Override
                        public void changed(ObservableValue<? extends Boolean> observable,Boolean oldValue, Boolean newValue) {
                            g.setChecked(newValue);
                        }
                    });
                    return retval;
                }
            }));
    
            //文件名列
            TableColumn<FileWrap, String>  fileNameCol= new TableColumn<>("文件名称");
            fileNameCol.setCellValueFactory(new PropertyValueFactory<>("fileName"));
    
            //序号列
            TableColumn<FileWrap, String> noColumn= new TableColumn<>("序号");
            noColumn.setCellFactory((col) ->{
                TableCell<FileWrap, String> cell = new TableCell<FileWrap, String>() {
                    @Override
                    public void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
                        this.setText(null);
                        this.setGraphic(null);
    
                        if (!empty) {
                            int rowIndex = this.getIndex() + 1;
                            this.setText(String.valueOf(rowIndex));
                        }
                    }};
                return cell;
            });
    
    
            noColumn.setMaxWidth(50);
            checkedCol.setMaxWidth(50);
            noColumn.setMinWidth(50);
            checkedCol.setMinWidth(50);
            filesTable.getColumns().add(noColumn);
            filesTable.getColumns().add(checkedCol);
            filesTable.getColumns().add(fileNameCol);
            filesTable.setItems(fileWraps);
        }
    }
    

    参考文章

    1.DOC-03-13 表格视图(TableView)

    相关文章

      网友评论

          本文标题:2021-03-20_TableView

          本文链接:https://www.haomeiwen.com/subject/kliicltx.html