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


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







All Articles