当前位置: 首页 > 知识库问答 >
问题:

焦点改变为不同填充单元格的JavaFX可编辑单元格

姚向晨
2023-03-14

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

  1. 单击选择单元格并
  2. 在选定的单元格中单击另一个单元格,或回车,开始编辑。
  3. 双击单元格开始编辑。
  4. 按enter提交对单元格的更改
  5. 在单元格之外的任何地方更改鼠标焦点都将向单元格提交更改

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

共有1个答案

公冶高义
2023-03-14

我可能来晚了一点,但现在开始了。

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

但是,用户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);
    }

}
 类似资料:
  • 一个javafx初学者,我需要一些帮助。我遵循了这里的示例,并使单元格编辑工作得很好。我启用了TableViewSelectionModel中TableViewsetCellSelectionEnabled true的单元格选择。但是当我完成编辑单元格时,TableView失去焦点,焦点转到场景中的第一个节点。我尝试获取当前选定的单元格并使用getFocusModel()的focus(),即使在P

  • 问题内容: 我正在尝试用Java编写程序来管理我的Bookie帐户。我是java的新手,所以我认为我会选择一些简单的方法来了解事情的原理。我决定使用表格视图并使各个单元格可编辑。我一直在关注本教程http://java- buddy.blogspot.co.uk/2012/04/javafx-2-editable-tableview.html 。它详细说明了如何使用Java代码执行此操作,并将其复

  • 我有一个表视图,其中很少有列是可编辑的,也很少有不可编辑的。当我在第一列中输入一些值并按tab键时,将调用一个服务,返回的对象将映射到表行。我的要求是根据返回对象中的标志将不可编辑列设置为可编辑(仅在我编辑过的行中)。下面是调用服务并将返回的对象设置为行的代码。 请建议如何在运行时根据标志将不可编辑的列转换为可编辑的列。

  • 我有一系列基于用户选择的EditText单元格,其中一些单元格将自动填充,然后我通过执行“myCell[x].setEnabled(false)”将这些EditText单元格更改为不可编辑。在这种情况下,字体颜色变为灰色,可读性不好。有没有一种方法可以改变EditText字体的颜色。setEnabled(false)或是否有其他方法通过对字体类型和颜色的更多控制来禁用单元格的可编辑性?我可以改变背

  • 问题内容: 有什么办法可以在jtable中动态制作不可编辑的单元格吗?每当用户提供类似false的输入时,我都想创建不可编辑的单元格…我已经在DefaultTableModel isCellEditable方法中看到过,但是如果我想使用它,则每次创建新对象时都会创建它,因此我想动态更改它为不可编辑。有人可以帮我吗?。谢谢 问题答案: 其他班级 然后,您可以通过使用存储的myModel变量并在其上调

  • 问题内容: 嗨,我正在使用GXT 2.2.3创建可编辑网格。我创建了如下列: 现在,我想根据eventCombo框值的值,将checkinDate,CheckIntime,CheckOutDate和CheckOutTime列单元格设置为不可编辑或禁用。 如何在eventCombo的侦听器框中进行此操作。请提出建议。 我是GXT的新手。 更新 我尝试了下面的代码来禁用和启用单元格,但是它禁用了单元格