0

In JavaFX 8 I'm trying to get a cell to edit after a new row has been added to the table, to optimize the experience for the user.

    hourTableView.getSelectionModel().select(newHour);
    int row = hourTableView.getSelectionModel().getSelectedIndex();
    hourTableView.edit(row, hourTableAmountTableColumn);

The correct row is selected, but the cell does not go into edit mode. Well, I have seen it happen very incidentally, but hardly reproducable. What am I doing wrong?

tbeernot
  • 2,473
  • 4
  • 24
  • 31
  • Is the column editable? Is the table editable? Does the column have a `CellFactory` that supports editing and correctly implements `startEdit`? An [MCVE](https://stackoverflow.com/help/mcve) would be immensely helpful. – Itai Jun 11 '17 at 14:41
  • Yes, the cell is editable by clicking on it with the mouse (the column uses PropertyValueFactory). The whole application is fully functional, this is one of those UX improvement where you click in a tree and then the focus + edit should be placed, so you can start typing a value immediately. I'll try and see about that MCVE (I hoped for a quick hint of course). – tbeernot Jun 11 '17 at 15:12

2 Answers2

2

The table behaves strange if you want to start editing on a just inserted row. I could start editing any row without problem. But the newly added row wasn't working like expected. I delayed the edit call with a thread, then it worked... See the following example code:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class jfxtest extends Application {

    private ObservableList<Person> data;
    private TableView<Person> tableView;
    private TableColumn<Person, String> firstNameCol;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Button addButton = new Button("add new row");
        addButton.setOnMouseClicked(event -> addRow());
        VBox vbox = new VBox(addButton, createContent());
        primaryStage.setScene(new Scene(vbox));
        primaryStage.show();
    }

    private void addRow() {
        data.add(new Person("peter", "parker", "spiderman@aol.com"));
        new Thread(() -> {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Platform.runLater(() -> {
                int row = data.size() - 1;
                tableView.getSelectionModel().select(row);
                tableView.getSelectionModel().focus(row);
                tableView.edit(row, firstNameCol);
            });
        }).start();
    }

    private TableView createContent() {
        data = FXCollections.observableArrayList(
            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")
        );
        firstNameCol = new TableColumn<>("First");
        firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
        firstNameCol.setEditable(true);
        firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        firstNameCol.setOnEditCommit(
            t -> t.getTableView().getItems().get(
                t.getTablePosition().getRow()).firstNameProperty().setValue(t.getNewValue())
        );

        TableColumn<Person, String> lastNameCol = new TableColumn<>("Last");
        lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));

        TableColumn<Person, String> emailCol = new TableColumn<>("Email");
        emailCol.setCellValueFactory(new PropertyValueFactory<>("email"));

        tableView = new TableView<>();
        tableView.setEditable(true);
        tableView.setItems(data);
        tableView.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
        return tableView;
    }


    public class Person {
        private StringProperty firstName;
        private StringProperty lastName;
        private StringProperty email;

        Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

        public StringProperty emailProperty() {
            return email;
        }
    }
}
Phil
  • 306
  • 1
  • 8
  • After some more research it turned out that a "refresh" call on the TableView was causing the problem. Adding a new entry to the observable list underlying the TableView of course already triggered the refreshing of the UI, so the explicit refresh call was not necessary. After removing it, the cell is edited, even if it was just added. Except when the row is the first row in the view, then the focus is present on the cell, but the cursor is not placed. The suggestion above is not fixing that. The search continues. – tbeernot Jul 03 '17 at 13:43
  • Using a `java.util.Timer` is preferred over using a `Thread` like this; not that I prefer it, but simply better practice. – Tech Expert Wizard Dec 10 '20 at 23:24
1

found the solution in Insert row in JavaFX TableView and start editing is not working correctly

you need to call hourTableView.layout() before calling hourTableView.edit(). It gets more complicated when the new row is not visible, I found that hourTableView.scrollTo() helps if it is called before hourTableView.layout().

Ralf Reddin
  • 117
  • 5