На самом деле вы можете обрабатывать как преобразование, так и предотвращать неправильный ввод, используя TextFormatter
, используя StringConverter
и UnaryOperator
. В следующем коде предполагается, что у вас есть ObjectProperty<Integer>
в вашем классе Water
, а метод amountProperty()
возвращает его.
Если метод Water.toString(int)
или Water.toString(Integer)
не существует, необходимо выполнить преобразование из int
в строку, чтобы следующий код работал.
private static final StringConverter<Integer> VALUE_CONVERTER = new StringConverter<Integer>() {
@Override
public String toString(Integer object) {
return object == null ? Water.getAreaFormat() : Water.toString(object);
}
@Override
public Integer fromString(String string) {
return Water.toInt(string);
}
};
// filter copied unmodified from your code
private static final UnaryOperator<TextFormatter.Change> VALUE_FILTER = change -> {
int maxLength = 10;
if (change.isAdded()) {
if(change.getControlNewText().length() <= maxLength){
if (change.getText().contains(",")) {
change.setText(change.getText().replaceAll(",", "."));
}
change = change.getControlNewText().matches("^\\d*(\\.\\d{0,1})?$") ? change : null;
} else {
if (change.getText().length() == 1){
change = null;
} else {
int allowedLength = maxLength - change.getControlText().length();
change.setText(change.getText().substring(0, allowedLength));
}
}
}
return change;
};
@FXML
private TableColumn<Water, Integer> valueColumn;
@FXML
private void initialize(){
waterTable.setItems(FXCollections.observableArrayList(thisMonthWaterList));
valueColumn.setCellValueFactory(cellData -> cellData.getValue().amountProperty());
valueColumn.setCellFactory(new Callback<TableColumn<Water, Integer>, TableCell<Water, Integer>>() {
@Override
public TableCell<Water, Integer> call(TableColumn<Water, Integer> param) {
return new TableCell<Water, Integer>() {
private final TextFormatter<Integer> formatter;
private final TextField textField;
{
textField = new TextField();
formatter = new TextFormatter<>(VALUE_CONVERTER, null, VALUE_FILTER);
textField.setTextFormatter(formatter);
formatter.valueProperty().addListener((o, oldValue, newValue) -> {
Water water = (Water) getTableRow().getItem();
if (!Objects.equals(water.getAmount(), newValue)) {
// update item and db, if value was modified
water.setAmount(newValue);
WaterDA.update(water);
}
});
}
@Override
protected void updateItem(Integer value, boolean empty){
super.updateItem(value, empty);
if (empty){
setGraphic(null);
} else {
setGraphic(textField);
formatter.setValue(value);
}
}
};
}
});
}
Предполагается, что ваши TableCell
всегда должны быть в "состоянии редактирования". Если это не так, вам нужно реализовать изменение состояния в методах startEdit
/ cancelEdit
и commitEdit
.