JavaFX 2: Save edit in TableCell

前端 未结 2 2018
隐瞒了意图╮
隐瞒了意图╮ 2021-01-15 08:54

In my JavaFX-program I use a TableCell where you can edit a value. Like shown at the examples on the JavaFX-page \"Example\", I use this function to save the changes (functi

相关标签:
2条回答
  • 2021-01-15 09:11

    Listening to a change in focus on the TextField is one way.. I added a listener to the focusedProperty of the textField. The example from Oracle didn't include this. [edit - here is a link to another question that has a different approach UITableView - Better Editing through Binding? ]

    private void createTextField() {
            textField = new TextField(getItem());
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
    
            // Detect a change in focus on the text field.. If we lose the focus we take appropriate action
            textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
                public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                    if(!newValue.booleanValue())
                        commitEdit(textField.getText());
                }
            } );
            textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
                @Override public void handle(KeyEvent t) {
                    if (t.getCode() == KeyCode.ENTER) {
                        commitEdit(textField.getText());
                    } else if (t.getCode() == KeyCode.ESCAPE) {
                        cancelEdit();
                    }
                }
            });
        }
    
    0 讨论(0)
  • 2021-01-15 09:23
      import javafx.beans.property.ObjectProperty;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.collections.ObservableList;
        import javafx.scene.Node;
      import javafx.scene.control.Cell;
      import javafx.scene.control.ComboBox;
      import javafx.scene.control.TextField;
      import javafx.scene.input.KeyCode;
     import javafx.scene.input.KeyEvent;
     import javafx.scene.input.MouseEvent;
     import javafx.scene.layout.HBox;
    import javafx.util.StringConverter;
    
    class CellGenerator {
    
    /***************************************************************************
     * * Private fields * *
     **************************************************************************/
    private final static StringConverter defaultStringConverter = new StringConverter<Object>() {
        @Override
        public String toString(Object t) {
            return t == null ? null : t.toString();
        }
    
        @Override
        public Object fromString(String string) {
            return (Object) string;
        }
    };
    
    static <T> StringConverter<T> defaultStringConverter() {
        return (StringConverter<T>) defaultStringConverter;
    }
    
    private static <T> String getItemText(Cell<T> cell, StringConverter<T> converter) {
        return converter == null ? cell.getItem() == null ? "" : cell.getItem().toString()
                : converter.toString(cell.getItem());
    }
    
    /***************************************************************************
     * * TextField convenience * *
     **************************************************************************/
    static <T> void updateItem(final Cell<T> cell, final StringConverter<T> converter, final TextField textField) {
        updateItem(cell, converter, null, null, textField);
    }
    
    static <T> void updateItem(final Cell<T> cell, final StringConverter<T> converter, final HBox hbox,
            final Node graphic, final TextField textField) {
        if (cell.isEmpty()) {
            cell.setText(null);
            cell.setGraphic(null);
        } else {
            if (cell.isEditing()) {
                if (textField != null) {
                    textField.setText(getItemText(cell, converter));
                }
                cell.setText(null);
                if (graphic != null) {
                    hbox.getChildren().setAll(graphic, textField);
                    cell.setGraphic(hbox);
                } else {
                    cell.setGraphic(textField);
                }
            } else {
                cell.setText(getItemText(cell, converter));
                cell.setGraphic(graphic);
            }
        }
    }
    
    static <T> void startEdit(final Cell<T> cell, final StringConverter<T> converter, final HBox hbox,
            final Node graphic, final TextField textField) {
        if (textField != null) {
            textField.setText(getItemText(cell, converter));
        }
        cell.setText(null);
        if (graphic != null) {
            hbox.getChildren().setAll(graphic, textField);
            cell.setGraphic(hbox);
        } else {
            cell.setGraphic(textField);
        }
        textField.selectAll();
        // requesting focus so that key input can immediately go into the
        // TextField (see RT-28132)
        textField.requestFocus();
    }
    
    static <T> void cancelEdit(Cell<T> cell, final StringConverter<T> converter, Node graphic) {
        cell.setText(getItemText(cell, converter));
        cell.setGraphic(graphic);
    
    }
    
    static <T> TextField createTextField(final Cell<T> cell, final StringConverter<T> converter) {
    
        final TextField textField = new TextField(getItemText(cell, converter));
        EdittingCell cellEdit=(EdittingCell)cell;
        textField.setOnMouseExited(event -> {
    
            if (converter == null) {
                throw new IllegalStateException("Attempting to convert text input into Object, but provided "
                        + "StringConverter is null. Be sure to set a StringConverter "
                        + "in your cell factory.");
            }
    
            cell.commitEdit(converter.fromString(textField.getText()));
    
        });
    
        textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
    
            if (event.getCode() == KeyCode.ESCAPE) {
                cell.cancelEdit();
                event.consume();
            } else if (event.getCode() == KeyCode.RIGHT) {
                cellEdit.getTableView().getSelectionModel().selectRightCell();
                event.consume();
            } else if (event.getCode() == KeyCode.LEFT) {
                cellEdit.getTableView().getSelectionModel().selectLeftCell();
                event.consume();
            } else if (event.getCode() == KeyCode.UP) {
                cellEdit.getTableView().getSelectionModel().selectAboveCell();
                event.consume();
            } else if (event.getCode() == KeyCode.DOWN) {
                cellEdit.getTableView().getSelectionModel().selectBelowCell();
                event.consume();
            } else if (event.getCode() == KeyCode.ENTER) {
                if (converter == null) {
                    throw new IllegalStateException("Attempting to convert text input into Object, but provided "
                            + "StringConverter is null. Be sure to set a StringConverter "
                            + "in your cell factory.");
                }
    
                cell.commitEdit(converter.fromString(textField.getText()));
    
                event.consume();
            }
            else if (event.getCode() == KeyCode.TAB) {
    
                cell.commitEdit(converter.fromString(textField.getText()));
    
                cellEdit.setNextColumn(event);
    
                event.consume();
            }
        });
    
        return textField;
    }}
    

    //the table cell

      import java.util.ArrayList;
      import java.util.List;
    
      import javafx.beans.property.ObjectProperty;
      import javafx.beans.property.SimpleObjectProperty;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.event.EventHandler;
      import javafx.scene.control.*;
       import javafx.scene.input.KeyCode;
       import javafx.scene.input.KeyEvent;
       import javafx.util.Callback;
       import javafx.util.StringConverter;
       import javafx.util.converter.DefaultStringConverter;
    
     public class EdittingCell<S, T> extends TableCell<S, T> {
    
    public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> 
    forTableColumn() {
        return forTableColumn(new DefaultStringConverter());
    }
    
    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> 
    forTableColumn(
            final StringConverter<T> converter) {
        return new Callback<TableColumn<S, T>, TableCell<S, T>>() {
            @Override
            public TableCell<S, T> call(TableColumn<S, T> list) {
                return new EdittingCell<S, T>(converter);
            }
        };
    }
    
    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> 
    forTableColumn(final StringConverter<T> converter,
            final boolean isFieldEditable) {
        return new Callback<TableColumn<S, T>, TableCell<S, T>>() {
            @Override
            public TableCell<S, T> call(TableColumn<S, T> list) {
                return new EdittingCell<S, T>(converter, isFieldEditable);
            }
        };
    }
    
    /***************************************************************************
     * * Fields * *
     **************************************************************************/
    public TextField textField;
    private static int currentRow = -1;
    private static int control = 0;
    
    public EdittingCell() {
        this(null);
        textField = CellGenerator.createTextField(this, getConverter());
    }
    
    public EdittingCell(StringConverter<T> converter) {
    
        this.getStyleClass().add("text-field-table-cell");
    
        setConverter(converter);
        textField = CellGenerator.createTextField(this, getConverter());
        // textField.setEditable(false);
    
    }
    
    public EdittingCell(StringConverter<T> converter, boolean isFieldEditable) {
    
        this.getStyleClass().add("text-field-table-cell");
    
        setConverter(converter);
        textField = CellGenerator.createTextField(this, getConverter());
        textField.setEditable(isFieldEditable);
    
    }
    
    /***************************************************************************
     * * Properties * *
     **************************************************************************/
    // --- converter
    private ObjectProperty<StringConverter<T>> converter = new SimpleObjectProperty<StringConverter<T>>(this,
            "converter");
    
    public final ObjectProperty<StringConverter<T>> converterProperty() {
        return converter;
    }
    
    public TextField getTextFiedCell() {
        return textField;
    }
    
    public final void setConverter(StringConverter<T> value) {
        converterProperty().set(value);
    }
    
    public final StringConverter<T> getConverter() {
        return converterProperty().get();
    }
    
    @Override
    public void startEdit() {
        if (!isEditable() || !getTableView().isEditable() || !getTableColumn().isEditable()) {
            return;
        }
        super.startEdit();
        if (isEditing()) {
    
            CellGenerator.startEdit(this, getConverter(), null, null, textField);
        }
    }
    
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        CellGenerator.cancelEdit(this, getConverter(), null);
    }
    
    /** {@inheritDoc} */
    @Override
    public void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        CellGenerator.updateItem(this, getConverter(), null, null, textField);
        // System.out.println("Silas");
    }
    
    public TableView<S> getContextTableView() {
    
        return getTableView();
    }
    
    public void setNextColumn(KeyEvent event) {
        TableColumn nextColumn = getNextColumn(!event.isShiftDown());
    
        if (nextColumn != null) {
    
            // Get Selected index to reset current editable row
            int selectedRow = getTableRow().getIndex();
            // Set row that serves as a control for tapping through
            if (currentRow == -1) {
                currentRow = getTableRow().getIndex();
            }
            // Reset editing upon selection change row
            if (currentRow != selectedRow) {
                currentRow = selectedRow;
            }
    
            int colSize = getTableView().getColumns().size();
            int colindex = getTableView().getColumns().indexOf(nextColumn);
    
            if (colindex == colSize - 1) {
                control++;
            }
            if (control > 0 && colindex == 0) {
                currentRow++;
            }
    
            if (getTableView().getItems().size() > currentRow) {
                getTableView().edit(currentRow, nextColumn);
                // getTableView().getSelectionModel().select(currentRow,
                // nextColumn);
            } else {
                currentRow = 0;
                // getTableView().getSelectionModel().select(currentRow,
                // nextColumn);
                getTableView().edit(currentRow, nextColumn);
            }
        }
    }
    
    private TableColumn<S, ?> getNextColumn(boolean forward) {
    
        List<TableColumn<S, ?>> columns = new ArrayList<>();
    
        for (TableColumn<S, ?> column : getTableView().getColumns()) {
    
            columns.addAll(getLeaves(column));
    
        }
    
        // There is no other column that supports editing.
    
        if (columns.size() < 2) {
            return null;
        }
        int currentIndex = columns.indexOf(getTableColumn());
        int nextIndex = currentIndex;
        if (forward) {
            nextIndex++;
            if (nextIndex > columns.size() - 1) {
                nextIndex = 0;
    
            }
        } else {
            nextIndex--;
            if (nextIndex < 0) {
    
                nextIndex = columns.size() - 1;
            }
    
        }
        return columns.get(nextIndex);
    }
    
    private ObservableList<TableColumn<S, ?>> getLeaves(TableColumn<S, ?> column2) {
        ObservableList<TableColumn<S, ?>> columns = FXCollections.observableArrayList();
        if (column2.getColumns().isEmpty()) {
            // We only want the leaves that are editable.
            if (column2.isEditable()) {
                columns.addAll(column2);
            }
            return columns;
        } else {
            for (TableColumn<S, ?> column : column2.getColumns()) {
                columns.addAll(getLeaves(column));
            }
            return columns;
        }
    
    }
    

    }

    //How to use this

        TableColumn<NewInvoice, BigDecimal> quantityCol = new 
       TableColumn<NewInvoice, BigDecimal>("Quantity");
        quantityCol.setCellValueFactory(cellData -> 
       cellData.getValue().quantityProperty());
        quantityCol.setCellFactory(EdittingCell.forTableColumn( new 
       BigDecimalStringConverter()));
        quantityCol.setStyle("-fx-alignment:CENTER-RIGHT;");
        quantityCol.setOnEditCommit(new EventHandler<CellEditEvent<NewInvoice, 
       BigDecimal>>() {
            @Override
            public void handle(CellEditEvent<NewInvoice, BigDecimal> t) {
         t.getTableView().getItems().get(t.getTablePosition().getRow()
       ).setQuantity(t.getNewValue());
            }
        });
    
    0 讨论(0)
提交回复
热议问题