Reputation: 514
I have a TableView
control which consists of several columns containg different types including String
s and Number
s. I have been trying to write a suitable callback function for an editable Number cell, but I can't get anywhere with it as I get a variety of issues ranging from empty cells to exceptions.
I have read through http://docs.oracle.com/javafx/2/ui_controls/table-view.htm but this only covers String values in cells. The sticking point seems to be lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
. This line seems to be tailored for Text fields and not for Number fields.
Also, I wish to perform validation on the numbers entered. Does this require a custom callback for the CellFactory
in order to do this? If so, how can I develop a callback that accepts Number types and validates them?
Here's a code snippet of what I currently have in my project:
@FXML private TableView<BMIRecord> fxBMITable;
@FXML private TableColumn<BMIRecord, String> fxBMITableDate;
@FXML private TableColumn<BMIRecord, String> fxBMITableTime;
@FXML private TableColumn<BMIRecord, Number> fxBMITableHeight;
@FXML private TableColumn<BMIRecord, Number> fxBMITableWeight;
@FXML private TableColumn<BMIRecord, Number> fxBMITableBMI;
// ...
private void someFunc() {
fxBMITable.setEditable(true);
/* BMI table callback configuration */
fxBMITableHeight.setCellValueFactory(new Callback<CellDataFeatures<BMIRecord, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<BMIRecord, String> p) {
return new SimpleStringProperty(p.getValue().getDateString());
}
});
/*
* ERROR:
* The method setCellFactory(Callback<TableColumn<BMIRecord,Number>,TableCell<BMIRecord,Number>>)
* in the type TableColumn<BMIRecord,Number> is not applicable for the arguments
* (Callback<TableColumn<Object,String>,TableCell<Object,String>>)
*/
fxBMITableHeight.setCellFactory(TextFieldTableCell.forTableColumn());
fxBMITableHeight.setOnEditCommit(new EventHandler<CellEditEvent<BMIRecord, Number>>() {
@Override
public void handle(CellEditEvent<BMIRecord, Number> t) {
((BMIRecord)t.getTableView().getItems().get(t.getTablePosition().getRow())).setHeight(t.getNewValue().doubleValue());
}
});
}
Thanks for any help in advance.
Upvotes: 9
Views: 14672
Reputation: 2851
jalvafx library:
Solution prevent user from invalid input. Only 0-9, coma and point symbols are allowed. You can set minimun and maximum number value.
Method to use signature:
TableViewUtils.setEditNumberCellFactory(
TableColumn<T, K> cell,
BiConsumer<T, Double> changeHandler,
String editControlHeader,
Double minAllowedValue,
Double maxAllowedValue,
Function<T, Boolean> ignoreEdit)
Mock table:
TableView<String> tableView = new TableView<>();
tableView.getItems().addAll("USA", "Canada", "Brazil");
TableColumn<String, String> country = new TableColumn<>("Country");
TableColumn<String, Integer> column = new TableColumn<>("Some value");
tableView.getColumns().add(country);
tableView.getColumns().add(column);
country.setCellValueFactory(
data -> new SimpleObjectProperty<>(data.getValue()));
column.setCellValueFactory(
data -> new SimpleObjectProperty<>(800));
Solution:
BiConsumer<String, Double> changeHandler = (item, newValue) -> {
System.out.println("New value is " + newValue);
// Your code
};
Function<String, Boolean> ignoreEdit = item -> item.equalsIgnoreCase("USA");
TableViewUtils.setEditNumberCellFactory(column, changeHandler, "New value:", 200.0, 800.0, ignoreEdit);
Upvotes: 0
Reputation: 153
use this
age.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
Upvotes: 1
Reputation: 15742
TextFieldTableCell is type parameterized and has a stringConverter
property that you can use to convert to/from String and your desired type.
Try something like:
TextFieldTableCell.<BMIRecord, Number>forTableColumn(new NumberStringConverter())
NumberStringConverter has some additional constructors for specifying the formatting, see the javadocs.
Here's a more complete example:
public class Person {
public Person(String name0, int age0) {
name = name0;
age = age0;
}
public String name;
public int age;
}
TableView<Person> personTable = new TableView<>();
TableColumn<Person, Number> age = new TableColumn<>();
age.setCellValueFactory(new Callback<CellDataFeatures<Person, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(CellDataFeatures<Person, Number> p) {
return new SimpleIntegerProperty(p.getValue().age);
}
});
age.setCellFactory(TextFieldTableCell.<Person, Number>forTableColumn(new NumberStringConverter()));
This does not work well, though, because NumberStringConverter is so, to be blunt, badly implemented that it simply throws a ParseException
at you if you happen to enter a string instead of a number in the cell.
However it should be relatively trivial to implement your own string converter, where you could also do some simple validation (e.g. value should be between 0 and 100).
Upvotes: 15