How to add CheckBox's to a TableView in JavaFX
In my Java Desktop Application I have a TableView in which I want to have a column with CheckBoxes.
I did find where this has been done http://www.jonathangiles.net/javafx/2.0/CellFactories/ but as the download is not available and because I don't know how soon Jonathan Giles will answer my email I thought I'd ask...
How do I put a CheckBox in a cell of my TableView?
Uses javafx.scene.control.cell.CheckBoxTableCell<S,T>
and the work's done !
ObservableList< TableColumn< RSSReader, ? >> columns =
_rssStreamsView.getColumns();
[...]
TableColumn< RSSReader, Boolean > loadedColumn = new TableColumn<>( "Loaded" );
loadedColumn.setCellValueFactory(
new Callback<CellDataFeatures<RSSReader,Boolean>,ObservableValue<Boolean>>(){
@Override public
ObservableValue<Boolean> call( CellDataFeatures<RSSReader,Boolean> p ){
return p.getValue().getCompleted(); }});
loadedColumn.setCellFactory(
new Callback<TableColumn<RSSReader,Boolean>,TableCell<RSSReader,Boolean>>(){
@Override public
TableCell<RSSReader,Boolean> call( TableColumn<RSSReader,Boolean> p ){
return new CheckBoxTableCell<>(); }});
[...]
columns.add( loadedColumn );
UPDATE: same code using Java 8 lambda expressions
ObservableList< TableColumn< RSSReader, ? >> columns =
_rssStreamsView.getColumns();
[...]
TableColumn< RSSReader, Boolean > loadedColumn = new TableColumn<>( "Loaded" );
loadedColumn.setCellValueFactory( f -> f.getValue().getCompleted());
loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>());
[...]
columns.add( loadedColumn );
Lines count is divided by two! (16 ==> 8)
UPDATE: same code using Java 10 "var" contextual word
var columns = _rssStreamsView.getColumns();
[...]
var loadedColumn = new TableColumn<RSSReader, Boolean>( "Loaded" );
loadedColumn.setCellValueFactory( f -> f.getValue().getCompleted());
loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>());
[...]
columns.add( loadedColumn );
EDIT to add full functional editable example (Java 8)
public class Os {
private final StringProperty name = new SimpleStringProperty();
private final BooleanProperty delete = new SimpleBooleanProperty();
public Os( String nm, boolean del ) {
name .set( nm );
delete.set( del );
}
public StringProperty nameProperty () { return name; }
public BooleanProperty deleteProperty() { return delete; }
}
public class FxEditableCheckBox extends Application {
@Override
public void start( Stage stage ) throws Exception {
final TableView<Os> view = new TableView<>();
final ObservableList<TableColumn<Os, ?>> columns = view.getColumns();
final TableColumn<Os, Boolean> nameColumn = new TableColumn<>( "Name" );
nameColumn.setCellValueFactory( new PropertyValueFactory<>( "name" ));
columns.add( nameColumn );
final TableColumn<Os, Boolean> loadedColumn = new TableColumn<>( "Delete" );
loadedColumn.setCellValueFactory( new PropertyValueFactory<>( "delete" ));
loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>());
columns.add( loadedColumn );
final ObservableList<Os> items =
FXCollections.observableArrayList(
new Os( "Microsoft Windows 3.1" , true ),
new Os( "Microsoft Windows 3.11" , true ),
new Os( "Microsoft Windows 95" , true ),
new Os( "Microsoft Windows NT 3.51", true ),
new Os( "Microsoft Windows NT 4" , true ),
new Os( "Microsoft Windows 2000" , true ),
new Os( "Microsoft Windows Vista" , true ),
new Os( "Microsoft Windows Seven" , false ),
new Os( "Linux all versions :-)" , false ));
view.setItems( items );
view.setEditable( true );
final Button delBtn = new Button( "Delete" );
delBtn.setMaxWidth( Double.MAX_VALUE );
delBtn.setOnAction( e -> {
final Set<Os> del = new HashSet<>();
for( final Os os : view.getItems()) {
if( os.deleteProperty().get()) {
del.add( os );
}
}
view.getItems().removeAll( del );
});
stage.setScene( new Scene( new BorderPane( view, null, null, delBtn, null )));
BorderPane.setAlignment( delBtn, Pos.CENTER );
stage.show();
}
public static void main( String[] args ) {
launch( args );
}
}
EDIT to add full functional editable example (Java 10)
public class Os {
private final StringProperty name = new SimpleStringProperty();
private final BooleanProperty delete = new SimpleBooleanProperty();
public Os( String nm, boolean del ) {
name .set( nm );
delete.set( del );
}
public StringProperty nameProperty () { return name; }
public BooleanProperty deleteProperty() { return delete; }
}
public class FxEditableCheckBoxJava10 extends Application {
@Override
public void start( Stage stage ) throws Exception {
final var view = new TableView<Os>();
final var columns = view.getColumns();
final var nameColumn = new TableColumn<Os, Boolean>( "Name" );
nameColumn.setCellValueFactory( new PropertyValueFactory<>( "name" ));
columns.add( nameColumn );
final var loadedColumn = new TableColumn<Os, Boolean>( "Delete" );
loadedColumn.setCellValueFactory( new PropertyValueFactory<>( "delete" ));
loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>());
columns.add( loadedColumn );
final var items = FXCollections.observableArrayList(
new Os( "Microsoft Windows 3.1" , true ),
new Os( "Microsoft Windows 3.11" , true ),
new Os( "Microsoft Windows 95" , true ),
new Os( "Microsoft Windows NT 3.51", true ),
new Os( "Microsoft Windows NT 4" , true ),
new Os( "Microsoft Windows 2000" , true ),
new Os( "Microsoft Windows Vista" , true ),
new Os( "Microsoft Windows Seven" , false ),
new Os( "Linux all versions :-)" , false ));
view.setItems( items );
view.setEditable( true );
final var delBtn = new Button( "Delete" );
delBtn.setMaxWidth( Double.MAX_VALUE );
delBtn.setOnAction( e -> {
final var del = new HashSet<Os>();
for( final var os : view.getItems()) {
if( os.deleteProperty().get()) {
del.add( os );
}
}
view.getItems().removeAll( del );
});
stage.setScene( new Scene( new BorderPane( view, null, null, delBtn, null )));
BorderPane.setAlignment( delBtn, Pos.CENTER );
stage.show();
}
public static void main( String[] args ) {
launch( args );
}
}
You need to set a CellFactory on the TableColumn.
For example:
Callback<TableColumn<TableData, Boolean>, TableCell<TableData, Boolean>> booleanCellFactory =
new Callback<TableColumn<TableData, Boolean>, TableCell<TableData, Boolean>>() {
@Override
public TableCell<TableData, Boolean> call(TableColumn<TableData, Boolean> p) {
return new BooleanCell();
}
};
active.setCellValueFactory(new PropertyValueFactory<TableData,Boolean>("active"));
active.setCellFactory(booleanCellFactory);
class BooleanCell extends TableCell<TableData, Boolean> {
private CheckBox checkBox;
public BooleanCell() {
checkBox = new CheckBox();
checkBox.setDisable(true);
checkBox.selectedProperty().addListener(new ChangeListener<Boolean> () {
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if(isEditing())
commitEdit(newValue == null ? false : newValue);
}
});
this.setGraphic(checkBox);
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
this.setEditable(true);
}
@Override
public void startEdit() {
super.startEdit();
if (isEmpty()) {
return;
}
checkBox.setDisable(false);
checkBox.requestFocus();
}
@Override
public void cancelEdit() {
super.cancelEdit();
checkBox.setDisable(true);
}
public void commitEdit(Boolean value) {
super.commitEdit(value);
checkBox.setDisable(true);
}
@Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty()) {
checkBox.setSelected(item);
}
}
}
TableColumn select = new TableColumn("CheckBox");
select.setMinWidth(200);
select.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, CheckBox>, ObservableValue<CheckBox>>() {
@Override
public ObservableValue<CheckBox> call(
TableColumn.CellDataFeatures<Person, CheckBox> arg0) {
Person user = arg0.getValue();
CheckBox checkBox = new CheckBox();
checkBox.selectedProperty().setValue(user.isSelected());
checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
public void changed(ObservableValue<? extends Boolean> ov,
Boolean old_val, Boolean new_val) {
user.setSelected(new_val);
}
});
return new SimpleObjectProperty<CheckBox>(checkBox);
}
});
table.getColumns().addAll( select);