【问题标题】:JavaFX editable cell with focus change to different populated cellJavaFX 可编辑单元格,焦点更改为不同的填充单元格
【发布时间】:2015-07-09 15:13:43
【问题描述】:

我需要 JavaFX TableView 的可编辑单元格。默认的 TextFieldTableCell 要求用户按 Enter 来提交更改。我认为典型的用户希望在单元格外部单击时保留更改。我想要的所有功能包括:

  1. 单击选择单元格并
  2. 再次单击单元格,在选定的单元格中,或回车,开始编辑。
  3. 双击单元格开始编辑。
  4. 按 Enter 将更改提交到单元格
  5. 在单元格外的任何位置更改鼠标焦点都会将更改提交到单元格

我在post 中找到了 EditCell 版本 它满足前 4 个要求,部分满足第 5 个要求,但是当用户单击表格中另一个填充的单元格时,编辑更改将丢失。触发焦点侦听器,但没有提交。单击空单元格或其他场景元素会提交更改。

post 中提供了一个据称的解决方案 但是,该解决方案仅包含 sn-ps 代码而不是工作示例。我无法实现它。

任何人都可以帮助将这些部分组合在一起并演示一个类而不是扩展 TableCell 具有我上面列出的所有功能吗?

【问题讨论】:

    标签: javafx tableview cell edit tablecell


    【解决方案1】:

    我参加这个聚会可能有点晚了,但我来了。

    无法提交更改单元格的值可能是由于 TableCell 中 commitEdit 方法的默认实现,因为它默认将失去焦点视为取消操作。

    不过,用户 James_D 创建了一个很好的解决方法here

    编辑:

    基于 James_D 工作的示例类

    import java.util.function.Function;
    
    import javafx.application.Application;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.beans.property.StringProperty;
    import javafx.event.Event;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.input.KeyCode;
    import javafx.scene.input.KeyEvent;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
    
    
    public class TableViewCommitOnFocusLoss extends Application {
    
    
        @Override
        public void start(Stage primaryStage) {
    
            TableView<Person> table = new TableView<>();
    
            table.getSelectionModel().setCellSelectionEnabled(true);
            table.setEditable(true);
    
            table.getColumns().add(createColumn("First Name", Person::firstNameProperty));
            table.getColumns().add(createColumn("Last Name", Person::lastNameProperty));
            table.getColumns().add(createColumn("Email", Person::emailProperty));
    
            table.getItems().addAll(
                    new Person("Jacob", "Smith", "jacob.smith@example.com"),
                    new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                    new Person("Ethan", "Williams", "ethan.williams@example.com"),
                    new Person("Emma", "Jones", "emma.jones@example.com"),
                    new Person("Michael", "Brown", "michael.brown@example.com")
            );
    
            Button showDataButton = new Button("Debug data");
            showDataButton.setOnAction(event -> table.getItems().stream()
                    .map(p -> String.format("%s %s", p.getFirstName(), p.getLastName()))
                    .forEach(System.out::println));
    
            Scene scene = new Scene(new BorderPane(table, null, null, showDataButton, null), 880, 600);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private <T> TableColumn<T, String> createColumn(String title, Function<T, StringProperty> property) {
            TableColumn<T, String> col = new TableColumn<>(title);
            col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
    
            col.setCellFactory(column -> EditCell.createStringEditCell());
            return col ;
        }
    
        public static class Person {
            private final StringProperty firstName = new SimpleStringProperty();
            private final StringProperty lastName = new SimpleStringProperty();
            private final StringProperty email = new SimpleStringProperty();
    
            public Person(String firstName, String lastName, String email) {
                setFirstName(firstName);
                setLastName(lastName);
                setEmail(email);
            }
    
            public final StringProperty firstNameProperty() {
                return this.firstName;
            }
    
            public final java.lang.String getFirstName() {
                return this.firstNameProperty().get();
            }
    
            public final void setFirstName(final java.lang.String firstName) {
                this.firstNameProperty().set(firstName);
            }
    
            public final StringProperty lastNameProperty() {
                return this.lastName;
            }
    
            public final java.lang.String getLastName() {
                return this.lastNameProperty().get();
            }
    
            public final void setLastName(final java.lang.String lastName) {
                this.lastNameProperty().set(lastName);
            }
    
            public final StringProperty emailProperty() {
                return this.email;
            }
    
            public final java.lang.String getEmail() {
                return this.emailProperty().get();
            }
    
            public final void setEmail(final java.lang.String email) {
                this.emailProperty().set(email);
            }
    
    
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
    }
    
    class EditCell<S, T> extends TableCell<S, T> {
    
        // Text field for editing
        // TODO: allow this to be a plugable control.
        private final TextField textField = new TextField();
    
        // Converter for converting the text in the text field to the user type, and vice-versa:
        private final StringConverter<T> converter ;
    
        public EditCell(StringConverter<T> converter) {
            this.converter = converter ;
    
            itemProperty().addListener((obx, oldItem, newItem) -> {
                if (newItem == null) {
                    setText(null);
                } else {
                    setText(converter.toString(newItem));
                }
            });
            setGraphic(textField);
            setContentDisplay(ContentDisplay.TEXT_ONLY);
    
            textField.setOnAction(evt -> {
                commitEdit(this.converter.fromString(textField.getText()));
            });
            textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
                if (! isNowFocused) {
                    commitEdit(this.converter.fromString(textField.getText()));
                }
            });
            textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
                if (event.getCode() == KeyCode.ESCAPE) {
                    textField.setText(converter.toString(getItem()));
                    cancelEdit();
                    event.consume();
                } else if (event.getCode() == KeyCode.RIGHT) {
                    getTableView().getSelectionModel().selectRightCell();
                    event.consume();
                } else if (event.getCode() == KeyCode.LEFT) {
                    getTableView().getSelectionModel().selectLeftCell();
                    event.consume();
                } else if (event.getCode() == KeyCode.UP) {
                    getTableView().getSelectionModel().selectAboveCell();
                    event.consume();
                } else if (event.getCode() == KeyCode.DOWN) {
                    getTableView().getSelectionModel().selectBelowCell();
                    event.consume();
                }
            });
        }
    
        /**
         * Convenience converter that does nothing (converts Strings to themselves and vice-versa...).
         */
        public static final StringConverter<String> IDENTITY_CONVERTER = new StringConverter<String>() {
    
            @Override
            public String toString(String object) {
                return object;
            }
    
            @Override
            public String fromString(String string) {
                return string;
            }
    
        };
    
        /**
         * Convenience method for creating an EditCell for a String value.
         * @return
         */
        public static <S> EditCell<S, String> createStringEditCell() {
            return new EditCell<S, String>(IDENTITY_CONVERTER);
        }
    
    
        // set the text of the text field and display the graphic
        @Override
        public void startEdit() {
            super.startEdit();
            textField.setText(converter.toString(getItem()));
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            textField.requestFocus();
        }
    
        // revert to text display
        @Override
        public void cancelEdit() {
            super.cancelEdit();
            setContentDisplay(ContentDisplay.TEXT_ONLY);
        }
    
        // commits the edit. Update property if possible and revert to text display
        @Override
        public void commitEdit(T item) {
    
            // This block is necessary to support commit on losing focus, because the baked-in mechanism
            // sets our editing state to false before we can intercept the loss of focus.
            // The default commitEdit(...) method simply bails if we are not editing...
            if (! isEditing() && ! item.equals(getItem())) {
                TableView<S> table = getTableView();
                if (table != null) {
                    TableColumn<S, T> column = getTableColumn();
                    TableColumn.CellEditEvent<S, T> event = new TableColumn.CellEditEvent<>(table,
                            new TablePosition<S,T>(table, getIndex(), column),
                            TableColumn.editCommitEvent(), item);
                    Event.fireEvent(column, event);
                }
            }
    
            super.commitEdit(item);
    
            setContentDisplay(ContentDisplay.TEXT_ONLY);
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    • 2014-02-22
    相关资源
    最近更新 更多