请解释如何使用CheckBoxTableCell

pnt*_*n84 7 tableview javafx-8

我想知道更多关于如何实际使用或子类(如果需要)CheckBoxTableCell.我想使用此类的一个特定情况,其中复选框不绑定到基础数据模型属性.

假设我有一个列调用'Select',其中包含复选框.此列或多或少用作对行的可视标记.用户可以勾选这些框,然后使用按钮对勾选的行执行某些操作(例如,删除所有勾选的行).

我正在搜索关于这个主题的教程.虽然有一些教程或解释,但它们涉及一些与复选框相关的支持数据模型.

所以我正在寻找关于此的更详细解释,其中复选框是动态生成的,并且用作用户界面的辅助辅助,例如上面解释的示例.此外,我想知道编辑是如何发挥作用并将其正确编码为标准和约定的,特别是当Java 8引入了属性更新,新的javafx类等时.

如果它有助于,一个常见的参考示例可能是'Person'的数据模型,它只有一个属性'Name'.ObservableList可以绑定到显示名称的TableView.设置在最左侧(tableview)的另一列是针对每个名称的复选框.最后,至少一个按钮允许对人员列表进行某种形式的操纵.为了简单起见,该按钮只是根据当按钮被操作时是否标记了该人的姓名时,删除了列表中的人.此外,一个按钮可以添加新人,但它可以是可选的.

我希望我能以简明扼要的方式撰写主题,并且有一个明确的解决方案.提前感谢能够提供相关信息的任何人.

pnt*_*n84 14

使用Person上面描述的数据模型示例,添加了布尔属性,例如Registered status,因此将第三个名为"Registered"的表列添加到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); }
}
Run Code Online (Sandbox Code Playgroud)


//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) );
Run Code Online (Sandbox Code Playgroud)


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);
Run Code Online (Sandbox Code Playgroud)


此代码正常工作.当通过数据模型或tblViewUI组件进行迭代以访问Registered属性时,它将显示正确的值,即使它发生更改(即取消/勾选复选框).

尝试添加不绑定到数据模型的复选框的原始问题尚未得到解决.

假设添加了另一个列调用'Select',它只包含一个复选框,用于直观地指示可以(或是)选择一行或多行.重申,此列复选框与数据模型没有任何相关含义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);
Run Code Online (Sandbox Code Playgroud)


一种解决方案是创建一个(匿名)内部类,它继承Person并添加"Select"属性.使用与"已注册"属性及其表列类似的代码来链接"选择"属性,它应该可以工作.如上所述,仅仅为了解决视觉问题而进行子类化会破坏数据模型的语义.

一个更好的解决方案是 - 为每个人创建一个布尔属性的内部列表personList并将它们链接在一起.因此,如何适当的布尔属性被检索对应于每个人personListsetCellValueFactory()方法是什么?一种可能的解决方案是使用personListselect列中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));
Run Code Online (Sandbox Code Playgroud)

这些片段对我有用.它只需要重新组织即可编译和运行.但是,要点部分是正确的.

这个问题或情况非常普遍,但实施和解决却花了我几天的时间.我希望这对其他人有利.


Ant*_*rov 8

Java 8

在控制器中:

checked.setCellValueFactory(
      param -> param.getValue().isChecked()
);

checked.setCellFactory(CheckBoxTableCell.forTableColumn(checked));
Run Code Online (Sandbox Code Playgroud)

在模型中:

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);
}}
Run Code Online (Sandbox Code Playgroud)