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

查看:26
本文介绍了将 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 扩展应用程序 {私人最终 TableViewtable = new TableView();私有最终 ObservableList数据= 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"));公共静态无效主(字符串 [] args){发射(参数);}@覆盖公共无效开始(阶段阶段){stage.setTitle(表格视图示例");stage.setWidth(600);stage.setHeight(400);final Label label = new Label(地址簿");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumnactive = new TableColumn<>(Active");active.setCellValueFactory(new PropertyValueFactory<>(active"));active.setCellFactory(CheckBoxTableCell.forTableColumn(active));TableColumnfirstName = new TableColumn<>(First Name");firstName.setCellValueFactory(new PropertyValueFactory<>(firstName"));TableColumnlastName = new TableColumn<>(Last Name");lastName.setCellValueFactory(new PropertyValueFactory<>(lastName"));TableColumnemail = new TableColumn<>(Email");email.setCellValueFactory(new PropertyValueFactory<>(email"));table.setItems(data);table.getColumns().addAll(active, firstName, lastName, email);最终 VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(8));vbox.getChildren().addAll(label, table);stage.setScene(新场景(vbox));舞台表演();}公共静态类人{私有最终 BooleanProperty 活动;私人最终 StringProperty firstName;私人最终 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() {返回 firstName.get();}公共无效setFirstName(字符串s){firstName.set(s);}公共字符串 getLastName() {返回 lastName.get();}public void setLastName(String s) {lastName.set(s);}公共字符串 getEmail() {返回 email.get();}公共无效setEmail(字符串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 扩展应用程序 {私人最终 TableViewtable = new TableView();私有最终 ObservableList数据= 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"));公共静态无效主(字符串 [] args){发射(参数);}@覆盖公共无效开始(阶段阶段){stage.setTitle(表格视图示例");stage.setWidth(600);stage.setHeight(400);final Label label = new Label(地址簿");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumnactive = new TableColumn<>(Active");active.setCellValueFactory(cd -> cd.getValue().activeProperty());active.setCellFactory(CheckBoxTableCell.forTableColumn(active));TableColumnfirstName = new TableColumn<>(First Name");firstName.setCellValueFactory(cd -> cd.getValue().firstNameProperty());TableColumnlastName = new TableColumn<>(Last Name");lastName.setCellValueFactory(cd -> cd.getValue().lastNameProperty());TableColumnemail = new TableColumn<>(Email");email.setCellValueFactory(cd -> cd.getValue().emailProperty());table.setItems(data);table.getColumns().addAll(active, firstName, lastName, email);最终 VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(8));vbox.getChildren().addAll(label, table);stage.setScene(新场景(vbox));舞台表演();}私有静态类人{私有最终 BooleanProperty 活动;私人最终 StringProperty firstName;私人最终 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() {返回活跃;}公共 StringProperty firstNameProperty() {返回名字;}公共 StringProperty lastNameProperty() {返回姓氏;}公共 StringProperty 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天全站免登陆