Explain how to use CheckBoxTableCell

I would like to learn more about how to practically use or subclass (if necessary) CheckBoxTableCell. There is one specific case that I would like to use for this class, while the checkbox does not bind to the basic property of the data model.

Suppose I have a call to the Select column that has checkboxes. This column more or less serves as a visual marker against the row. The user can mark these fields, and then use the button to perform some actions against the marked lines (for example, delete all marked lines).

I was looking for tutorials on this. However, although there were some lessons or explanations in it, they used some model of support data related to the checkbox.

So, I am looking for a more detailed explanation on this issue, where the checkbox is dynamically generated and serves as auxiliary help for the user interface, such as the example described above. In addition, I would like to know how editing comes into play and encodes standards and conventions correctly, especially when updates appeared in Java 8 using properties, new javafx classes, etc.

If this helps, a common example of a comparison would be the "Man" data model, which has only one "Name" property. A ObservableList can be bound to a TableView that displays names. And another column set to the very left side (in table form) is a check box for each name. Finally, at least one button allows you to manipulate the list of people. And to make it simple, this button simply deletes the person (s) in the list, based on whether the sign was marked by the person’s name when the button was pressed. In addition, a button could add a new person, but it may be optional.

I hope that I wrote the article in a short and detailed form and that there is a final solution. I thank in advance everyone who can provide any relevant information.

+6
source share
2 answers

Using the example of the Person data model described above, a Boolean property, for example. The registered status is added, and therefore the third column of the "Registered" table is added to TableView.

Consider a code example:

 //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 (ie 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 (ie 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); 


This code is working correctly. When repeated using a data model or tblView UI component to access the Registered property, it displays the correct values ​​even when it changes (i.e., Undoes / ticks).

The original problem with trying to add a flag that is not tied to a data model has not yet been received.

Suppose another call to the Select column is added, and it just contains a check box to visually indicate that one or more rows can be selected (or selected). Repeating, this checkbox column has no meaning for the Person data model. And thus, creating a property inside the Person class to store this value is semantically unnecessary and is probably considered bad coding practice. So how is this problem resolved?

How does an arbitrary BooleanProperty (or a list of it for each person in the list of persons) bind or bind to the corresponding flag?

 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); 


One solution is to create a (anonymous) inner class of the Person subclass and add a Select property. Using similar code for the Registered property and its table column to bind the Select property, it should work. As indicated above, subclassing only to solve a visual problem breaks the semantics of the data model.

A better solution might be: create an internal list of logical properties for each person in personList and link them together. So, how is the corresponding Boolean property that corresponds to each person in personList in the setCellValueFactory() method setCellValueFactory() ? One possible solution is to use the index position in personList , a boolean property list for the select column and row index. So, it comes to the row index inside setCellValueFactory(CellDataFeatures) and how is this done correctly?

Consider the code:

 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, ie 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)); 

This snippet works for me. It just needs a reorganization to compile and run. However, the main part is correct.

This problem or situation is very common, but it took me days to implement and solve it. Hope this will serve others well.

+11
source

Java 8

In the controller:

 checked.setCellValueFactory( param -> param.getValue().isChecked() ); checked.setCellFactory(CheckBoxTableCell.forTableColumn(checked)); 

In the model:

 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); }} 
+4
source

Source: https://habr.com/ru/post/974138/


All Articles