将 CheckBox 列添加到现有的 TableView
Posted
技术标签:
【中文标题】将 CheckBox 列添加到现有的 TableView【英文标题】:Adding a CheckBox column to an existing TableView 【发布时间】:2021-10-28 07:50:40 【问题描述】:我最近想将CheckBox
列添加到现有的TableView
。为了孤立地研究这个问题,我从Example 13-6 Creating a Table and Adding Data to It 开始。我添加了BooleanProperty
和Person
模型类的访问器,并添加了一个新的TableColumn
和CheckBoxTableCell
作为单元工厂。如图所示,我在每一行看到一个CheckBox
。虽然所有值都是true
,但没有一个被检查;复选框是实时的,但永远不会调用 setActive()
。最近关于这个主题的questions 表明我遗漏了一些东西;我欢迎任何见解。
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);
【问题讨论】:
这是一个错误:bugs.openjdk.java.net/browse/JDK-8235630 【参考方案1】:总结:如here 所述,这很可能是bug;避免该陷阱的步骤包括:
验证数据模型是否正确导出属性,如图here。 如here、here 和here 所述,在可能的情况下,严格检查将PropertyValueFactory
替换为显式Callback
的价值。
问题是CheckBoxTableCell
无法根据提供的参数找到或绑定ObservableProperty<Boolean>
:
active.setCellFactory(CheckBoxTableCell.forTableColumn(active));
CheckBoxTableCell
遵循表列以访问目标 Boolean
属性。要查看效果,请将active
参数替换为Callback
,该ObservableValue<Boolean>
为行i
显式返回ObservableValue<Boolean>
:
active.setCellFactory(CheckBoxTableCell.forTableColumn(
(Integer i) -> data.get(i).active));
虽然这使复选框起作用,但根本问题是Person
类需要active
属性的访问器。 Using JavaFX Properties and Binding 讨论了属性方法命名约定,Ensemble8 tablecellfactory
的 Person
类说明了一个工作模型类,其中每个属性都有一个属性获取器,如下所示。
通过此更改PropertyValueFactory
可以找到新添加的BooleanProperty
,并且forTableColumn()
的原始形式有效。请注意,PropertyValueFactory
的便利性带有一些limitations。特别是,工厂对先前缺少的属性访问器的支持没有引起注意。幸运的是,同一个访问器允许为每个列的值工厂替换一个简单的Callback
。如图here,而不是PropertyValueFactory
,
active.setCellValueFactory(new PropertyValueFactory<>("active"));
传递一个返回相应属性的lamda expression:
active.setCellValueFactory(cd -> cd.getValue().activeProperty());
另请注意,Person
现在可以是 private
。此外,显式类型参数的使用在编译期间提供了更强的类型检查。
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://***.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;
【讨论】:
如果我们可以完全控制数据项,建议不要使用 PropertyValueFactory :) 另一方面,不处理 ReadOnlyObjectPropertyWrapper(如果bean prop 既可读又可写)正确是 CheckBoxXXCell bugs.openjdk.java.net/browse/JDK-8235630 中的一个错误 感谢您引用这个有用的错误报告;它确实看起来在 API 中很矛盾。请不要犹豫编辑此答案或添加您自己的详细说明。我的目标是在此期间发布一些相当具有决定性的东西。我讨厌指导其他人学习教程,只是为了让他们遇到类似的问题。以上是关于将 CheckBox 列添加到现有的 TableView的主要内容,如果未能解决你的问题,请参考以下文章
将 UIView 添加到现有的 UIViewController