我想了解更多关于如何实际使用或子类(如有必要)CheckBoxTableCell。有一个特定的情况我想使用这个类,因此复选框不会绑定到底层数据模型属性。
假设我有一个列呼叫'选择'其中有复选框。此列或多或少用作对行的可视标记。用户可以勾选这些框,然后使用按钮对勾选的行执行某些操作(例如,删除所有勾选的行)。
我正在搜索有关此主题的教程。虽然有一些教程或解释,但它们涉及与复选框相关的一些支持数据模型。
所以我正在寻找关于此的更详细解释,其中复选框是动态生成的,并且用作用户界面的辅助辅助,例如上面解释的示例。此外,我想知道编辑如何发挥作用并将其正确编码为标准和约定,特别是当Java 8引入了属性更新,新的javafx类等时。
如果有帮助,一个常见的参考示例可能是“人物”的数据模型,它只有一个属性“名称”。 ObservableList可以绑定到显示名称的TableView。设置在最左侧(tableview)的另一列是针对每个名称的复选框。最后,至少一个按钮允许对人员列表进行某种形式的操纵。为了简单起见,该按钮只是根据当按钮被操作时是否标记了该人的姓名时,删除了列表中的人员。此外,一个按钮可以添加新人,但它可以是可选的。
我希望我能够以简明扼要的方式撰写主题,并且有一个明确的解决方案。提前感谢能够提供相关信息的任何人。
答案 0 :(得分:14)
使用如上所述的数据模型Person
示例,布尔属性,例如,已注册状态已添加,因此第三个表格栏名为“已注册”#39;添加到TableView。
考虑代码示例:
//The Data Model
public class Person
{
/*
* Fields
*/
private StringProperty firstName;
private StringProperty lastName;
private BooleanProperty registered;
/*
* Constructors
*/
public Person(String firstName, String lastName, boolean registered)
{
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.registered = new SimpleBooleanProperty(registered);
}
public Person()
{
this(null, null, false);
}
/*
* Properties
*/
public StringProperty firstNameProperty() { return firstName; }
public String getFirstName() { return this.firstName.get(); }
public void setFirstName(String value) { this.firstName.set(value); }
public StringProperty lastNameProperty() { return lastName; }
public String getLastName() { return this.lastName.get(); }
public void setLastName(String value) { this.lastName.set(value); }
public BooleanProperty registeredProperty() { return registered; }
public boolean isRegistered() { return this.registered.get(); }
public void setRegistered(boolean value) { this.registered.set(value); }
}
//Dummy values for the data model
List<Person> personList = new ArrayList<Person>();
personList.add( new Person("John", "Smith", true) ;
personList.add( new Person("Jack", "Smith", false) );
TableView<Person> tblView = new TableView<Person>();
tblView.setItems( FXCollections.observableList(personList) );
TableColumn firstName_col = new TableColumn("First Name");
TableColumn lastName_col = new TableColumn("Last Name");
TableColumn registered_col = new TableColumn("Registered");
firstName.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));
lastName.setCellValueFactory(new PropertyValueFactory<Person,String>("lastName"));
registered_col.setCellValueFactory(
new Callback<CellDataFeatures<Person,Boolean>,ObservableValue<Boolean>>()
{
//This callback tell the cell how to bind the data model 'Registered' property to
//the cell, itself.
@Override
public ObservableValue<Boolean> call(CellDataFeatures<Person, Boolean> param)
{
return param.getValue().registeredProperty();
}
});
//This tell how to insert and render a checkbox in the cell.
//
//The CheckBoxTableCell has the updateItem() method which by default links up the
//cell value (i.e. the 'Registered' property to the checkbox. And this method is
//automatically call at the appropriate time, such as when creating and rendering
//the cell (I believe).
//
//In this case, as the registed_col.setCellValueFactory() method has specified
//'Registered' in the actual data model (i.e. personList), therefore the checkbox will
//be bound to this property.
registered_col.setCellFactory( CheckBoxTableCell.forTableColumn(registered_col) );
tblView.getColumns.addAll(firstName_col, lastName_col, registered_col);
//table display preference - should not affect this exercise/problem
tblView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
此代码正常运行。当通过数据模型或tblView
UI组件进行迭代以访问Registered
属性时,它将显示正确的值,即使它发生更改(即取消/勾选复选框)。
尝试添加未绑定到数据模型的复选框的原始问题尚未得到解答。
假设另一个列呼叫&#39;选择&#39;添加它,它只是包含一个复选框,以直观地指示可以(或是)选择一行或多行。重申,此列复选框与数据模型Person
没有任何相关含义。因此,在Person
类中创建一个属性以保存此值在语义上是不必要的,并且可能被认为是编码不良的做法。那问题是如何解决的?
如何将任意BooleanProperty(或personList中每个人的列表)链接或绑定到相应的复选框?
TableColumn select_col = new TableColumn("Select");
//Set a boolean property to represent cell value.
select_col.setCellValueFactory(
new Callback<CellDataFeatures<Person,Boolean>,ObservableValue<Boolean>>()
{
@Override
public ObservableValue<Boolean> call(CellDataFeatures<Person,Boolean> param)
{
//PROBLEM -- What Code goes here?
}
};
//This call should be okay - it would display the checkbox according to the provided
//boolean (property). This was proven with
//registered_col.setCellFactory(CheckBoxTableCell.forTableColumn(registered_col)
select_col.setCellFactory(CheckBoxTableCell.forTableColumn(select_col);
一种解决方案是创建一个(匿名)内部类,其子类Person
并添加&#39;选择&#39;属性。使用类似的代码来注册&#39;属性及其表格列链接&#39;选择&#39;财产,它应该工作。如上所述,仅仅为了解决视觉问题而进行子类化会破坏数据模型的语义。
更好的解决方案是 - 为personList
中的每个人创建一个布尔属性的内部列表,并将它们链接在一起。那么如何在personList
方法中检索与setCellValueFactory()
中每个人相对应的适当布尔属性?一种可能的解决方案是使用personList
中的索引位置,select列的boolean属性列表和行索引。所以归结为将行索引放在setCellValueFactory(CellDataFeatures)
内,这是如何正确完成的?
考虑代码:
TableColumn<Person,Boolean> select_col = new TableColumn<Person,Boolea>("Select");
List<BooleanProperty> selectedRowList = new ArrayList<BooleanProperty>();
//This callback allows the checkbox in the column to access selectedRowList (or more
//exactly, the boolean property it contains
Callback<Integer,ObservableValue<Boolean>> selectedStateSelectColumn =
new Callback<Integer,ObservableValue<Boolean>>()
{
//index in this context reference the table cell index (I believe)
@Override
public ObservableValue<Boolean> call(Integer index)
{
return selectedRowList.get(index);
}
}
//Initialise the selectedRowList
for(Person p : personList)
{
//initially, it starts off as false, i.e. unticked state
selectedRowList.add( new SimpleBooleanProperty() );
}
select_col.setCellValueFactory(
new Callback<CellDataFeatures<Person,Boolean>,ObservableValue<Boolean>>
{
//retrieve the cell index and use it get boolean property in the selectedRowList
@Override
public ObservableValue<Boolean> call(CellDataFeatures<Person,Boolean> cdf)
{
TableView<Person> tblView = cdf.getTableView();
Person rowData = cdf.getValue();
int rowIndex = tblView.getItems().index( rowData );
return selectedRowList.get( rowIndex );
}
}
select_col.setCellFactory(
CheckBoxTableCell.forTableColumn(selectedStateSelectColumn));
这些代码段对我有用。它只需要重新组织即可编译和运行。但是,要点部分是正确的。
这个问题或情况很常见,但实施和解决却花了我几天的时间。我希望这对其他人有利。
答案 1 :(得分:6)
Java 8
在控制器中:
checked.setCellValueFactory(
param -> param.getValue().isChecked()
);
checked.setCellFactory(CheckBoxTableCell.forTableColumn(checked));
模特:
public class FileFound {
private String fileName;
private Long fileSize;
private String fileExt;
private String fullPath;
private Path filePath;
private BooleanProperty checked = new SimpleBooleanProperty(true);
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
}
public String getFileExt() {
return fileExt;
}
public void setFileExt(String fileExt) {
this.fileExt = fileExt;
}
public String getFullPath() {
return fullPath;
}
public void setFullPath(String fullPath) {
this.fullPath = fullPath;
}
public Path getFilePath() {
return filePath;
}
public void setFilePath(Path filePath) {
this.filePath = filePath;
}
public ObservableBooleanValue isChecked() {
return checked;
}
public void setChecked(Boolean checked) {
this.checked.set(checked);
}}