title: Insert row in JavaFX TableView and start editing is not working correctly
body: <p>We are running a JavaFX application that contains some editable table views. A new requested feature is: a button that adds a new row below the currently selected one and immediately starts to edit the first cell of the row.</p>
  
  <p>We implemented this feature, which was not so complicated, but we experience a very strange behavior and after a couple of days investigating the issue we still have no idea what goes wrong.</p>
  
  <p>What happens is that when one clicks the button it adds a new row but starts to edit to first cell not of the newly created row but on an arbitrary other row. Unfortunately, this issue is not 100% reproduceable. Sometimes it's working as expected but most often the row below the newly added row gets edited, but sometimes even completely different rows before and after the currently selected one.</p>
  
  <p>Below you can find the source code of a stripped down version of a JavaFX TableView that can be used to see the issue. As already mentioned it is not 100% reproduceable. To see the issue you have to add a new row multiple times. Some times the issue occurs more often when scrolling the table up and down a couple of times.</p>
  
  <p>Any help is appreciated.</p>
  
  <p>Hint: we already played around with Platform.runlater() a lot, by placing the action implementation of the button inside a runlater(), but although the issue occurs less often then, it never disappeared completely.</p>
  
  <p>The TableView:</p>
  
  <pre><code>package tableview;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javafx.application.Application;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.event.ActionEvent;
  import javafx.geometry.Insets;
  import javafx.scene.Group;
  import javafx.scene.Scene;
  import javafx.scene.control.Button;
  import javafx.scene.control.Label;
  import javafx.scene.control.TableCell;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableView;
  import javafx.scene.control.cell.PropertyValueFactory;
  import javafx.scene.layout.VBox;
  import javafx.scene.text.Font;
  import javafx.stage.Stage;
  import javafx.util.Callback;
  
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public class SimpleTableViewTest extends Application {
  
      private final ObservableList&lt;Person&gt; data = FXCollections.observableArrayList(createData());
  
      private final TableView table = new TableView();
  
      public static void main(String[] args) {
          launch(args);
      }
  
      private static List&lt;Person&gt; createData() {
          List&lt;Person&gt; data = new ArrayList&lt;&gt;();
          for (int i = 0; i &lt; 100; i++) {
              data.add(new Person("Jacob", "Smith", "jacob.smith_at_example.com", "js_at_example.com"));
          }
  
          return data;
      }
  
      @Override
      public void start(Stage stage) {
  
          Scene scene = new Scene(new Group());
          stage.setTitle("Table View Sample");
          stage.setWidth(700);
          stage.setHeight(550);
  
          final Label label = new Label("Address Book");
          label.setFont(new Font("Arial", 20));
  
          // Create a customer cell factory so that cells can support editing.
          Callback&lt;TableColumn, TableCell&gt; cellFactory = (TableColumn p) -&gt; {
              return new EditingCell();
          };
  
          // Set up the columns
          TableColumn firstNameCol = new TableColumn("First Name");
          firstNameCol.setMinWidth(100);
          firstNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("firstName"));
          firstNameCol.setCellFactory(cellFactory);
  
          TableColumn lastNameCol = new TableColumn("Last Name");
          lastNameCol.setMinWidth(100);
          lastNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("lastName"));
          lastNameCol.setCellFactory(cellFactory);
          lastNameCol.setEditable(true);
  
          TableColumn primaryEmailCol = new TableColumn("Primary Email");
          primaryEmailCol.setMinWidth(200);
          primaryEmailCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("primaryEmail"));
          primaryEmailCol.setCellFactory(cellFactory);
          primaryEmailCol.setEditable(false);
  
          TableColumn secondaryEmailCol = new TableColumn("Secondary Email");
          secondaryEmailCol.setMinWidth(200);
          secondaryEmailCol.setCellValueFactory(new PropertyValueFactory&lt;Person, String&gt;("secondaryEmail"));
          secondaryEmailCol.setCellFactory(cellFactory);
  
          // Add the columns and data to the table.
          table.setItems(data);
          table.getColumns().addAll(firstNameCol, lastNameCol, primaryEmailCol, secondaryEmailCol);
          table.setEditable(true);
  
          // --- Here comes the interesting part! ---
          //
          // A button that adds a row below the currently selected one
          // and immediatly starts editing it.
          Button addAndEdit = new Button("Add and edit");
          addAndEdit.setOnAction((ActionEvent e) -&gt; {
              int idx = table.getSelectionModel().getSelectedIndex() + 1;
  
              data.add(idx, new Person());
              table.getSelectionModel().select(idx);
              table.edit(idx, firstNameCol);
          });
  
          final VBox vbox = new VBox();
          vbox.setSpacing(5);
          vbox.getChildren().addAll(label, table, addAndEdit);
          vbox.setPadding(new Insets(10, 0, 0, 10));
          ((Group) scene.getRoot()).getChildren().addAll(vbox);
  
          stage.setScene(scene);
          stage.show();
      }
  
  }
  </code></pre>
  
  <p>The editable Table Cell:</p>
  
  <pre><code>package tableview;
  
  import javafx.event.EventHandler;
  import javafx.scene.control.ContentDisplay;
  import javafx.scene.control.TableCell;
  import javafx.scene.control.TextField;
  import javafx.scene.input.KeyCode;
  import javafx.scene.input.KeyEvent;
  
  public class EditingCell extends TableCell&lt;Person, String&gt; {
      private TextField textField;
  
      public EditingCell() {
      }
  
      @Override
      public void cancelEdit() {
          super.cancelEdit();
          setText(getItem());
          setContentDisplay(ContentDisplay.TEXT_ONLY);
      }
  
      @Override
      public void startEdit() {
          super.startEdit();
          if (textField == null) {
              createTextField();
          }
          setGraphic(textField);
          setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
      }
  
      @Override
      public void updateItem(String item, boolean empty) {
          super.updateItem(item, empty);
          if (empty) {
              setText(null);
              setGraphic(null);
          } else {
              if (isEditing()) {
                  if (textField != null) {
                      textField.setText(getString());
                  }
                  setGraphic(textField);
                  setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
              } else {
                  setText(getString());
                  setContentDisplay(ContentDisplay.TEXT_ONLY);
              }
          }
      }
  
      private void createTextField() {
          textField = new TextField(getString());
          textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
          textField.setOnKeyPressed(new EventHandler&lt;KeyEvent&gt;() {
              @Override
              public void handle(KeyEvent t) {
                  if (t.getCode() == KeyCode.ENTER) {
                      commitEdit(textField.getText());
                  } else if (t.getCode() == KeyCode.ESCAPE) {
                      cancelEdit();
                  }
              }
          });
      }
  
      private String getString() {
          return getItem() == null ? "" : getItem().toString();
      }
  }
  </code></pre>
  
  <p>A Data Bean:</p>
  
  <pre><code>package tableview;
  
  import javafx.beans.property.SimpleStringProperty;
  
  public class Person {
      private final SimpleStringProperty firstName;
      private final SimpleStringProperty lastName;
      private final SimpleStringProperty primaryEmail;
      private final SimpleStringProperty secondaryEmail;
  
      public Person() {
          this(null, null, null, null);
      }
  
      public Person(String firstName, String lastName, String primaryEmail, String secondaryEmail) {
          this.firstName = new SimpleStringProperty(firstName);
          this.lastName = new SimpleStringProperty(lastName);
          this.primaryEmail = new SimpleStringProperty(primaryEmail);
          this.secondaryEmail = new SimpleStringProperty(secondaryEmail);
      }
  
      public SimpleStringProperty firstNameProperty() {
          return firstName;
      }
  
      public String getFirstName() {
          return firstName.get();
      }
  
      public String getLastName() {
          return lastName.get();
      }
  
      public String getPrimaryEmail() {
          return primaryEmail.get();
      }
  
      public SimpleStringProperty getPrimaryEmailProperty() {
          return primaryEmail;
      }
  
      public String getSecondaryEmail() {
          return secondaryEmail.get();
      }
  
      public SimpleStringProperty getSecondaryEmailProperty() {
          return secondaryEmail;
      }
  
      public SimpleStringProperty lastNameProperty() {
          return lastName;
      }
  
      public void setFirstName(String firstName) {
          this.firstName.set(firstName);
      }
  
      public void setLastName(String lastName) {
          this.lastName.set(lastName);
      }
  
      public void setPrimaryEmail(String primaryEmail) {
          this.primaryEmail.set(primaryEmail);
      }
  
      public void setSecondaryEmail(String secondaryEmail) {
          this.secondaryEmail.set(secondaryEmail);
      }
  }
  </code></pre>