This is a screenshot from a JavaFX app called the Maven POM Updater. A TableView displays a list of Maven POM files, one per row. If the POM file can be parsed successfully, its values are displayed and it is eligible to be edited. If the parsing throws an error, an error message is displayed in the row itself, the row is colored red, and the row (actually the set of cells) becomes un-editable.
Cells are Rendered Black for Normal Usage and Red for a Parsing Error |
Controller Code
The version TableColumn is tcVersion and the parent TableColumn is tcParent.
In the JavaFX Controller, tcVersion and tcParent are initialized as follows. Note the reference to the custom class WarningCellFactory. POMObject is a model POJO with fields for each of the TableColumns.
tcVersion.setCellValueFactory(
new PropertyValueFactory<POMObject, String>("version")
);
tcVersion.setCellFactory(new WarningCellFactory());
tcVersion.setOnEditCommit(t -> {
tblPOMSDirty = true;
((POMObject) t.getTableView().getItems().get(t.getTablePosition().getRow())).setVersion(t.getNewValue());
});
tcParentVersion.setCellValueFactory(
new PropertyValueFactory<POMObject, String>("parentVersion")
);
tcParentVersion.setCellFactory(new WarningCellFactory());
tcParentVersion.setOnEditCommit(t -> {
tblPOMSDirty = true;
((POMObject) t.getTableView().getItems().get(t.getTablePosition().getRow())).setParentVersion(t.getNewValue());
});
tblPOMSDirty is a special flag for the operation of the system.
The setOnEditCommit Lambda will update the underlying model POMObject POJO when the user presses the return key in one of the textboxes.
Cell Factory
I supply a customized CellFactory to the TableColumns called WarningCellFactory. This can be used to produce a very different rendering of cells, say an Image or other specialized control. In this case, I want to use as much off-the-shelf functionality as possible, but I don't want to accept the default styling and behavior entirely.
WarningCellFactory is based on the TextFieldTableCell class. This class provides the desired editing behavior: Label -> TextField on a double-click. My WarningCellFactory class implements the required Callback / call() method. My call() method returns an anonymous class that extends TextFieldTableCell. I introduce a private method to make the code a little more readable called "createTableCell()"; this can be removed by a direct "new" of the anonymous class.
public class WarningCellFactory implements Callback<TableColumn<POMObject,String>, TableCell<POMObject,String>>{
@Override public TableCell<POMObject, String> call(TableColumn<POMObject, String> col) {
return createTableCell(col);
}
private TextFieldTableCell<POMObject, String> createTableCell(TableColumn<POMObject, String> col) {
TextFieldTableCell<POMObject, String> cell = new TextFieldTableCell<POMObject, String>(new DefaultStringConverter()) {
@Override public void updateItem(String arg0, boolean empty) {
super.updateItem(arg0, empty);
if( !empty ) {
this.setText( arg0 );
POMObject pomObject = (POMObject) this.getTableRow().getItem();
if( pomObject != null && pomObject.getParseError() ) {
this.setTextFill(Color.RED);
this.setEditable( false );
} else {
this.setTextFill(Color.BLACK);
this.setEditable( true );
}
} else {
this.setText( null ); // clear from recycled obj
this.setTextFill(Color.BLACK);
this.setEditable( true );
}
}
};
return cell;
}
}
TextFieldTableCell will also need a StringConverter supplied as a constructor argument. Since I'm dealing entirely with Strings, this can be safely assumed as DefaultStringConverter. If my POMObject POJO contained fields with different types, I would prepare different flavors of TextFieldTableCell constructors with different StringConverts (say a LongStringConverter for a Long field).
The special rendering sets the fill and editable properties on the returned component of the TableCell.
You could also try to style the TableView after-the-fact. I vastly prefer building the TableCells correctly from the start. That way, we don't have to worry about re-applying any after-action formatting if the TableView is modified.
Thank you very much! This post concluded my misfortunate googling all over the web. :-)
ReplyDelete