How to make a table column with Integer datatype editable without changing it to String
Just use a cell factory that creates a text field in the cell when editing. To commit the edit, just parse the text from the text field.
Example:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class EditableTableColumnWithInteger extends Application {
@Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
table.setEditable(true);
table.getItems().addAll(createData());
TableColumn<Item, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
TableColumn<Item, Number> valueCol = new TableColumn<>("Value");
valueCol.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
valueCol.setCellFactory(col -> new IntegerEditingCell());
table.getColumns().add(nameCol);
table.getColumns().add(valueCol);
Button dataDumpButton = new Button("Dump data");
dataDumpButton.setOnAction( e ->
table.getItems().stream().map(item -> item.getName()+":"+item.getValue()).forEach(System.out::println));
HBox controls = new HBox(5, dataDumpButton);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(new BorderPane(table, null, null, controls, null), 600, 400));
primaryStage.show();
}
public class IntegerEditingCell extends TableCell<Item, Number> {
private final TextField textField = new TextField();
private final Pattern intPattern = Pattern.compile("-?\\d+");
public IntegerEditingCell() {
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (! isNowFocused) {
processEdit();
}
});
textField.setOnAction(event -> processEdit());
}
private void processEdit() {
String text = textField.getText();
if (intPattern.matcher(text).matches()) {
commitEdit(Integer.parseInt(text));
} else {
cancelEdit();
}
}
@Override
public void updateItem(Number value, boolean empty) {
super.updateItem(value, empty);
if (empty) {
setText(null);
setGraphic(null);
} else if (isEditing()) {
setText(null);
textField.setText(value.toString());
setGraphic(textField);
} else {
setText(value.toString());
setGraphic(null);
}
}
@Override
public void startEdit() {
super.startEdit();
Number value = getItem();
if (value != null) {
textField.setText(value.toString());
setGraphic(textField);
setText(null);
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setGraphic(null);
}
// This seems necessary to persist the edit on loss of focus; not sure why:
@Override
public void commitEdit(Number value) {
super.commitEdit(value);
((Item)this.getTableRow().getItem()).setValue(value.intValue());
}
}
private List<Item> createData() {
Random rng = new Random();
List<Item> items = new ArrayList<>();
for (int i=1; i<=20; i++) {
items.add(new Item("Item "+i, rng.nextInt(20)));
}
return items ;
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value) {
this.setName(name);
this.setValue(value);
}
public final StringProperty nameProperty() {
return this.name;
}
public final java.lang.String getName() {
return this.nameProperty().get();
}
public final void setName(final java.lang.String name) {
this.nameProperty().set(name);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
}
public static void main(String[] args) {
launch(args);
}
}