将 CheckBox 列添加到现有的 TableView [英] Adding a CheckBox column to an existing TableView

查看:29
本文介绍了将 CheckBox 列添加到现有的 TableView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近想将 CheckBox 列添加到现有

import javafx.application.Application;导入 javafx.beans.property.BooleanProperty;导入 javafx.beans.property.SimpleBooleanProperty;导入 javafx.beans.property.SimpleStringProperty;导入 javafx.beans.property.StringProperty;导入 javafx.collections.FXCollections;导入 javafx.collections.ObservableList;导入 javafx.geometry.Insets;导入javafx.scene.Scene;导入 javafx.scene.control.Label;导入 javafx.scene.control.TableColumn;导入 javafx.scene.control.TableView;导入 javafx.scene.control.cell.CheckBoxTableCell;导入 javafx.scene.control.cell.PropertyValueFactory;导入javafx.scene.layout.VBox;导入javafx.scene.text.Font;导入javafx.stage.Stage;/*** 示例 13-6 创建表并向其添加数据* https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm#CJAGAAEE*/公共类 TableViewSample 扩展应用程序 {私有最终 TableView<Person>表 = 新表视图<>();私有最终 ObservableList<Person>数据= FXCollections.observableArrayList(新人(Jacob"、Smith"、jacob.smith@example.com"),新人(伊莎贝拉",约翰逊",isabella.johnson@example.com"),新人(Ethan",Williams",ethan.williams@example.com"),新人(Emma"、Jones"、emma.jones@example.com"),新人(迈克尔",布朗",michael.brown@example.com"));公共静态无效主要(字符串[]参数){启动(参数);}@覆盖公共无效开始(阶段阶段){stage.setTitle(表格视图示例");stage.setWidth(600);stage.setHeight(400);final Label label = new Label(通讯录");label.setFont(new Font(Arial", 20));table.setEditable(true);表列<人,布尔值>active = new TableColumn<>(Active");active.setCellValueFactory(new PropertyValueFactory<>(active"));active.setCellFactory(CheckBoxTableCell.forTableColumn(active));表列<人员,字符串>firstName = new TableColumn<>("First Name");firstName.setCellValueFactory(new PropertyValueFactory<>(firstName"));表列<人员,字符串>lastName = new TableColumn<>(姓氏");lastName.setCellValueFactory(new PropertyValueFactory<>(lastName"));表列<人员,字符串>email = new TableColumn<>(Email");email.setCellValueFactory(new PropertyValueFactory<>(email"));table.setItems(数据);table.getColumns().addAll(active, firstName, lastName, email);最终的 VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(新插图(8));vbox.getChildren().addAll(label, table);stage.setScene(新场景(vbox));舞台.show();}公共静态类人{私有最终 BooleanProperty 活动;私有最终 StringProperty 名字;私人最终 StringProperty 姓氏;私人最终 StringProperty 电子邮件;私人人员(字符串 fName,字符串 lName,字符串电子邮件){this.active = new SimpleBooleanProperty(true);this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}公共布尔 getActive() {返回 active.get();}公共无效setActive(布尔b){active.set(b);}公共字符串 getFirstName() {返回名字.get();}公共无效 setFirstName(字符串 s){firstName.set(s);}公共字符串 getLastName() {返回姓氏.get();}公共无效 setLastName(字符串 s){姓氏.set(s);}公共字符串 getEmail() {返回 email.get();}公共无效 setEmail(String s) {email.set(s);}}}

解决方案

总结:如前所述

import javafx.application.Application;导入 javafx.beans.property.BooleanProperty;导入 javafx.beans.property.SimpleBooleanProperty;导入 javafx.beans.property.SimpleStringProperty;导入 javafx.beans.property.StringProperty;导入 javafx.collections.FXCollections;导入 javafx.collections.ObservableList;导入 javafx.geometry.Insets;导入javafx.scene.Scene;导入 javafx.scene.control.Label;导入 javafx.scene.control.TableColumn;导入 javafx.scene.control.TableView;导入 javafx.scene.control.cell.CheckBoxTableCell;导入javafx.scene.layout.VBox;导入javafx.scene.text.Font;导入javafx.stage.Stage;/*** https://stackoverflow.com/a/68969223/230513*/公共类 TableViewSample 扩展应用程序 {私有最终 TableView<Person>表 = 新表视图<>();私有最终 ObservableList<Person>数据= FXCollections.observableArrayList(新人(Jacob"、Smith"、jacob.smith@example.com"),新人(伊莎贝拉",约翰逊",isabella.johnson@example.com"),新人(Ethan",Williams",ethan.williams@example.com"),新人(Emma"、Jones"、emma.jones@example.com"),新人(迈克尔",布朗",michael.brown@example.com"));公共静态无效主要(字符串[]参数){启动(参数);}@覆盖公共无效开始(阶段阶段){stage.setTitle(表格视图示例");stage.setWidth(600);stage.setHeight(400);final Label label = new Label(通讯录");label.setFont(new Font(Arial", 20));table.setEditable(true);表列<人,布尔值>active = new TableColumn<>(Active");active.setCellValueFactory(cd -> cd.getValue().activeProperty());active.setCellFactory(CheckBoxTableCell.forTableColumn(active));表列<人员,字符串>firstName = new TableColumn<>("First Name");firstName.setCellValueFactory(cd -> cd.getValue().firstNameProperty());表列<人员,字符串>lastName = new TableColumn<>(姓氏");lastName.setCellValueFactory(cd -> cd.getValue().lastNameProperty());表列<人员,字符串>email = new TableColumn<>(Email");email.setCellValueFactory(cd -> cd.getValue().emailProperty());table.setItems(数据);table.getColumns().addAll(active, firstName, lastName, email);最终的 VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(新插图(8));vbox.getChildren().addAll(label, table);stage.setScene(新场景(vbox));舞台.show();}私人静态类人{私有最终 BooleanProperty 活动;私有最终 StringProperty 名字;私人最终 StringProperty 姓氏;私人最终 StringProperty 电子邮件;私人人员(字符串 fName,字符串 lName,字符串电子邮件){this.active = new SimpleBooleanProperty(true);this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}公共布尔属性 activeProperty() {返回活跃;}公共字符串属性 firstNameProperty() {返回名字;}公共 StringProperty lastNameProperty() {返回姓氏;}公共字符串属性 emailProperty() {返回电子邮件;}}}

I recently wanted to add a CheckBox column to an existing TableView. To study the problem in isolation, I started with Example 13-6 Creating a Table and Adding Data to It. I added a BooleanProperty and accessors to the Person model class, and I added a new TableColumn with a CheckBoxTableCell as the cell factory. As shown in the image, I see a CheckBox on each row. Although all values are true, none are checked; the checkboxes are live, but setActive() is never called. Recent questions on this topic suggest that I'm missing something; I'd welcome any insight.

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 * Example 13-6 Creating a Table and Adding Data to It
 * https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm#CJAGAAEE
 */
public class TableViewSample extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data
        = FXCollections.observableArrayList(
            new Person("Jacob", "Smith", "jacob.smith@example.com"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
            new Person("Ethan", "Williams", "ethan.williams@example.com"),
            new Person("Emma", "Jones", "emma.jones@example.com"),
            new Person("Michael", "Brown", "michael.brown@example.com")
        );

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Table View Sample");
        stage.setWidth(600);
        stage.setHeight(400);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);

        TableColumn<Person, Boolean> active = new TableColumn<>("Active");
        active.setCellValueFactory(new PropertyValueFactory<>("active"));
        active.setCellFactory(CheckBoxTableCell.forTableColumn(active));

        TableColumn<Person, String> firstName = new TableColumn<>("First Name");
        firstName.setCellValueFactory(new PropertyValueFactory<>("firstName"));

        TableColumn<Person, String> lastName = new TableColumn<>("Last Name");
        lastName.setCellValueFactory(new PropertyValueFactory<>("lastName"));

        TableColumn<Person, String> email = new TableColumn<>("Email");
        email.setCellValueFactory(new PropertyValueFactory<>("email"));

        table.setItems(data);
        table.getColumns().addAll(active, firstName, lastName, email);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(8));
        vbox.getChildren().addAll(label, table);

        stage.setScene(new Scene(vbox));
        stage.show();
    }

    public static class Person {

        private final BooleanProperty active;
        private final StringProperty firstName;
        private final StringProperty lastName;
        private final StringProperty email;

        private Person(String fName, String lName, String email) {
            this.active = new SimpleBooleanProperty(true);
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }

        public boolean getActive() {
            return active.get();
        }

        public void setActive(boolean b) {
            active.set(b);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String s) {
            firstName.set(s);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String s) {
            lastName.set(s);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String s) {
            email.set(s);
        }
    }
}

解决方案

Summary: As noted here, this is likely a bug; steps to avoid the pitfall include these:

  • Verify that the data model exports properties correctly, as shown here.
  • Critically examine the value of replacing PropertyValueFactory with an explicit Callback, when possible, as outlined here, here and here.

The problem is that CheckBoxTableCell can't find or bind the ObservableProperty<Boolean> based on the parameter supplied:

active.setCellFactory(CheckBoxTableCell.forTableColumn(active));

The CheckBoxTableCell defers to the table column for access to the target Boolean property. To see the effect, replace the active parameter with a Callback that returns the ObservableValue<Boolean> for row i explicitly:

active.setCellFactory(CheckBoxTableCell.forTableColumn(
    (Integer i) -> data.get(i).active));

While this makes the checkboxes work, the underlying problem is that the Person class needs an accessor for the active property. Using JavaFX Properties and Binding discusses the property method naming conventions, and the Person class of the Ensemble8 tablecellfactory illustrates a working model class with a property getter for each attribute, also shown below.

With this change PropertyValueFactory can find the newly added BooleanProperty, and the original form of forTableColumn() works. Note that the convenience of PropertyValueFactory comes with some limitations. In particular, the factory's fall-through support for the previously missing property accessor goes unnoticed. Fortunately, the same accessor allows substitution of a simple Callback for each column's value factory. As shown here, instead of PropertyValueFactory,

active.setCellValueFactory(new PropertyValueFactory<>("active"));

Pass a lamda expression that returns the corresponding property:

active.setCellValueFactory(cd -> cd.getValue().activeProperty());

Note also that Person can now be private. Moreover, the use of explicit type parameters affords stronger type checking during compilation.

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 * https://stackoverflow.com/a/68969223/230513
 */
public class TableViewSample extends Application {

    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data
        = FXCollections.observableArrayList(
            new Person("Jacob", "Smith", "jacob.smith@example.com"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
            new Person("Ethan", "Williams", "ethan.williams@example.com"),
            new Person("Emma", "Jones", "emma.jones@example.com"),
            new Person("Michael", "Brown", "michael.brown@example.com")
        );

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Table View Sample");
        stage.setWidth(600);
        stage.setHeight(400);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);

        TableColumn<Person, Boolean> active = new TableColumn<>("Active");
        active.setCellValueFactory(cd -> cd.getValue().activeProperty());
        active.setCellFactory(CheckBoxTableCell.forTableColumn(active));

        TableColumn<Person, String> firstName = new TableColumn<>("First Name");
        firstName.setCellValueFactory(cd -> cd.getValue().firstNameProperty());

        TableColumn<Person, String> lastName = new TableColumn<>("Last Name");
        lastName.setCellValueFactory(cd -> cd.getValue().lastNameProperty());

        TableColumn<Person, String> email = new TableColumn<>("Email");
        email.setCellValueFactory(cd -> cd.getValue().emailProperty());

        table.setItems(data);
        table.getColumns().addAll(active, firstName, lastName, email);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(8));
        vbox.getChildren().addAll(label, table);

        stage.setScene(new Scene(vbox));
        stage.show();
    }

    private static class Person {

        private final BooleanProperty active;
        private final StringProperty firstName;
        private final StringProperty lastName;
        private final StringProperty email;

        private Person(String fName, String lName, String email) {
            this.active = new SimpleBooleanProperty(true);
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }

        public BooleanProperty activeProperty() {
            return active;
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

        public StringProperty emailProperty() {
            return email;
        }
    }
}

这篇关于将 CheckBox 列添加到现有的 TableView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆