I'm using JavaFX 17 to make an editable table. The table data comes from an observable list of MyCustomClass objects. I then made all cells editable by setting the cell factory of each column to TextFieldTableCell. So far so good. Setter function receives a CellEditEvent as expected; I can get the object that the row's data originated from, the column that was changed, the values that were changed.
@FXML
private void onEdit(TableColumn.CellEditEvent<MyCustomClass, String> editedCell) {
MyCustomClass object = cell.getRowValue();
String ValueBeforeUserMadeEdit = cell.getOldValue();
String valueThatIsNowShowing = cell.getNewValue();
}
Now the bad news. The event object does not have a function for indicating which property (or ideally, which property setter) should be used to update the value inputted by the user (i.e. the property that relates to the changed column). I originally gave the property name to the cell in a PropertyValueFactory, which has a function for getting that String. However, I can't find a way to get the property value factory from the cell, and even if I did it seems like too much work to then find the property setter from that string.
It would be easier to create a subclass of TextFieldTableCell that stores a reference to the correct setter, but I am hoping someone can tell me if there is built in functionality for this. Seems like there should have been, even at version 17. I'm a student, and really trying to understand this stuff, so any help at all is really appreciated!
Handler per Column
There's another approach, if you really need to define your own on-edit-commit handlers. It would look something like this:
When you do it this way, you know exactly which setter to call because each column gets its own on-edit-commit handler (and columns are associated with a specific property). I personally would prefer this approach.
Get Cell's ObservableValue
Given this method is annotated with
@FXML, I assume you're trying to use this one method as the implementation for the on-edit-commit handler of multiple columns. This can complicate things, but what you want is possible:Note: I did not write this in an IDE, so there may be some slight syntax errors. But it should compile, at least on newer versions of Java.
But note this is essentially what the default implementation does. And note that the existence of this default on-edit-commit handler is documented:
So, unless you need to change the default behavior, you likely don't need to worry about implementing your own on-edit-commit handler.
Potential Issues
The above requires that the
cellValueFactoryreturns an instance ofWritableValue. And thisWritableValuemust be linked to the model's property. This should be no problem if your model class exposes JavaFX properties like so:Note: If your model uses JavaFX properties then I suggest using lambda expressions instead of
PropertyValueFactory. Check out Why should I avoid using PropertyValueFactory in JavaFX?.Otherwise,
PropertyValueFactorywill return aReadOnlyObjectWrapperthat is divorced from the model's property after getting the current value. In other words, even thoughReadOnlyObjectWrapperdoes implementWritableValue, setting the property will not forward the new value to the model item.If you cannot or are unwilling to modify your model to use JavaFX properties, then you can use a different cell-value factory implementation than
PropertyValueFactory. For example:Then replace
new PropertyValueFactory<>("foo")withnew JavaBeanValueFactory<>("foo").Or you could do something like this:
Or anything you can think of where the property will forward new values to the model.