How to make a table column with data type Integer editable without changing it to String
I have a table column with Integer datatype. I want this column to be editable without changing the data type to String anywhere. I used textfieldtablecell, but it only takes the value when I hit enter. So I want a different method. Please suggest something. To do this [I may have done something similar. But my cell doesn't become editable.
public class EditCell implements initializable{
@FXML
private TableView<ResourceMaster> roletable;
@FXML
private TableColumn<ResourceMaster, Integer> loadedHrs;
@Override
public void initialize(URL location, ResourceBundle resources) {
Callback<TableColumn<ResourceMaster,Integer>, TableCell<ResourceMaster,Integer>> txtCellFactory =
(TableColumn<ResourceMaster,Integer> p) -> {return new EditingCell();};
loadedHrs.setCellFactory(txtCellFactory);
}
public class EditingCell extends TableCell<ResourceMaster, Integer> {
private TextField textField;
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (textField == null) {
createTextField();
}
// setText(null);
commitEdit(Integer.valueOf((textField.getText())));
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.requestFocus();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
@Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
//setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(String.valueOf(getString()));
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(String.valueOf(getString()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(String.valueOf(getString()));
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Integer.valueOf(textField.getText()));
EditingCell.this.getTableView().requestFocus();//why does it lose focus??
EditingCell.this.getTableView().getSelectionModel().selectBelowCell();
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent t) {
if (t.getCode().isDigitKey()) {
if (CellField.isLessOrEqualOneSym()) {
CellField.addSymbol(t.getText());
} else {
CellField.setText(textField.getText());
}
textField.setText(CellField.getText());
textField.deselect();
textField.end();
textField.positionCaret(textField.getLength() + 2);//works sometimes
}
}
});
}
private Integer getString() {
return getItem();
}
}
}
+6
source to share
2 answers
Just use a cell factory, which creates a textbox in the cell on edit. To commit your edits, simply parse the text from the text box.
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);
}
}
+10
source to share
You can create a table cell using StringConverter which converts your object to a cell representation. You can implement your own StringConverter for your class
cell.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<AnyClass>() {
@Override
public String toString(AnyClass object) {
return null;
}
@Override
public AnyClass fromString(String string) {
return null;
}
}));
Also JavaFX contains some default converters. For example IntegerStringConverter for your case,
TextFieldTableCell.forTableColumn(new IntegerStringConverter())
0
source to share