title: Binding JavaFX 2 TableView elements
body: <p>I was working on a small application using a simple binding in JavaFx 2.1 using java 1.7.0_04-b21 on MacOSX. Actually I currently compare the bind mechanisms of Cocoa on Mac OSX to the JavaFx and face several problems:</p>
  
  <p>The application uses a model holding an observableArrayList (called messageList) which is set as the items of a TableView. Adding a new Entry to the list works. The entry appears in the TableView. </p>
  
  <p><strong>Issue 1:</strong> Deleting a selected item does not work. When I remove an item from the observable list it does not disappear.</p>
  
  <p><strong>Issue 2:</strong> I want to fill a textField with the value stored in one field of the object that is selected in the TableView. 
  Actually for this in Cocoa one can define a binding to a selection even if this is empty (so nothing is selected) at the point in time of the definition of the binding. This is actually a very useful concept and I did not find how this could be possible in JavaFX. </p>
  
  <p><strong>Issue 3:</strong> Only if already an object is selected a binding can be established so that i finally wrote an EventHandler reacting on a changing selection and re-establishing always a correct binding of my textfield to the models field.  But also for this approach my application destroys the model for some reason which i do not understand by now. </p>
  
  <p>Simply click three or four times the add Button, then select the entries and see the updates of the textField. The data in the model get destroyed and overwritten - and the entries normally get shorter... Explanations of the effect are welcome. </p>
  
  <p>Till now I could not find a binding example on a TableView so any input is welcome.</p>
  
  <p>The code of my demo project is included in the following files. All are in the same package com.es.javaFxTest.</p>
  
  <p>MainWindowController.java:</p>
  
  <pre><code>/*
   * Created on 19.05.2012
   */
  package com.es.javaFxTest;
  
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.ResourceBundle;
  
  import javafx.beans.property.SimpleObjectProperty;
  import javafx.beans.value.ChangeListener;
  import javafx.beans.value.ObservableValue;
  import javafx.collections.ObservableList;
  import javafx.event.ActionEvent;
  import javafx.event.EventHandler;
  import javafx.fxml.Initializable;
  import javafx.scene.control.Button;
  import javafx.scene.control.TableColumn;
  import javafx.scene.control.TableView;
  import javafx.scene.control.TextField;
  import javafx.scene.control.cell.PropertyValueFactory;
  
  public class MainWindowController implements Initializable
  {
  
    public Model                         model;
  
    public TableView&lt;Message&gt;            messageListTableView;
  
    public TableColumn&lt;Message, String&gt;  messageTableMessageNameColumn;
  
    public Button                        addMessageButton;
  
    public Button                        deleteMessageButton;
  
    public TextField                     messageNameTextField;
  
    public SimpleObjectProperty&lt;Message&gt; selectedMessage;
  
    /* (non-Javadoc)
     * @see javafx.fxml.Initializable#initialize(java.net.URL, java.util.ResourceBundle)
     */
    @Override
    public void initialize(URL arg0, ResourceBundle arg1)
    {
      model = new Model();
  
      messageTableMessageNameColumn.setCellValueFactory(new PropertyValueFactory&lt;Message, String&gt;("messageName"));
      messageListTableView.setItems(model.getMessageList());
  
      addMessageButton.setOnAction(new EventHandler&lt;ActionEvent&gt;() {
        StringBuffer str = new StringBuffer("a"); // to fill some dummy data
  
        @Override
        public void handle(ActionEvent e)
        {
          // adding an object to the observed list works and the result is shown in the tableView
          model.getMessageList().add(new Message(str.toString()));
          str.append("x");
        }
      });
      deleteMessageButton.setOnAction(new EventHandler&lt;ActionEvent&gt;() {
        @Override
        public void handle(ActionEvent event)
        { // observation does not work here; also the following code does not work. 
          ObservableList&lt;Integer&gt; selectedIndices = messageListTableView.getSelectionModel().getSelectedIndices();
          ArrayList&lt;Integer&gt; selectedIndices2 = new ArrayList&lt;Integer&gt;(selectedIndices);
          Collections.sort(selectedIndices2);
          for (int i = selectedIndices2.size() - 1; i &gt;= 0; i--)
          {
            model.getMessageList().remove(selectedIndices2.get(i));
          }
        }
      });
  
      selectedMessage = new SimpleObjectProperty&lt;Message&gt;();
      selectedMessage.bind(messageListTableView.getSelectionModel().selectedItemProperty());
  
      selectedMessage.addListener(new ChangeListener&lt;Message&gt;() {
  
        @Override
        public void changed(ObservableValue&lt; ? extends Message&gt; observable, Message oldValue, Message newValue)
        {
          System.out.format("ObservableValue %s, \n  oldValue %s\n  newValue %s\n\n", observable, oldValue, newValue);
          if (oldValue != null)
          {
            messageNameTextField.textProperty().unbind();
            oldValue.messageName.unbind();
          }
          if (newValue != null)
          {
            messageNameTextField.textProperty().set(newValue.getMessageName());
            newValue.messageName.bindBidirectional(messageNameTextField.textProperty());
          }
        }
      });
    }
  }
  </code></pre>
  
  <p>MainWindowLayout.java</p>
  
  <pre><code>package com.es.javaFxTest;
  
  /*
   * Created on 18.05.2012
   */
  import java.io.IOException;
  
  import javafx.application.Application;
  import javafx.fxml.FXMLLoader;
  import javafx.scene.Scene;
  import javafx.scene.layout.Pane;
  import javafx.stage.Stage;
  
  public class MainWindowLayout extends Application
  {
  
    @Override
    public void start(Stage stage)
    {
  
      try
      {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainWindowLayout.fxml"));
        Pane root = (Pane) fxmlLoader.load();
        MainWindowController controller = (MainWindowController) fxmlLoader.getController();
  
        Scene scene = new Scene(root);
        stage.setTitle("Config");
        stage.setScene(scene);
        stage.show();
  
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    }
  
    public static void main(String[] args)
    {
      launch(args);
    }
  
  }
  </code></pre>
  
  <p>Message.java</p>
  
  <pre><code>/*
   * Created on 19.05.2012
   *
   */
  package com.es.javaFxTest;
  
  import javafx.beans.property.SimpleStringProperty;
  
  public class Message 
  {
  
  
  
    /**
     * @param canId
     * @param messageName
     */
    public Message(String messageName)
    {
      this.messageName = new SimpleStringProperty(messageName);
    }
  
  
    SimpleStringProperty messageName;
    /**
     * @return the messageName
     */
    public String getMessageName()
    {
      return messageName.getValue();
    }
    /**
     * @param messageName the messageName to set
     */
    public void setMessageName(String messageName)
    {
      this.messageName.set(messageName);
    }
  
    public String toString ()
    {
      return String.format("Name:%s",messageName); 
    }
  
  }
  </code></pre>
  
  <p>Model.java</p>
  
  <pre><code>/*
   * Created on 20.05.2012
   */
  package com.es.javaFxTest;
  
  import javafx.beans.property.SimpleListProperty;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  
  public class Model
  {
    ObservableList&lt;Message&gt;     messageList;
  
    SimpleListProperty&lt;Message&gt; messageListProperty;
  
    public Model()
    {
      messageList = FXCollections.observableArrayList();
      messageListProperty = new SimpleListProperty&lt;Message&gt;(this,"messageList",messageList);
    }
  
    public final SimpleListProperty&lt;Message&gt; messageListProperty()
    {
      return messageListProperty;
    }
  
    public ObservableList&lt;Message&gt; getMessageList()
    {
      return messageListProperty.get();
    }
  
    public void setMessageList(ObservableList&lt;Message&gt; l)
    {
      messageListProperty.set(l);
    }
  }
  </code></pre>
  
  <p>MainWindowLayout.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  
  &lt;?import java.lang.*?&gt;
  &lt;?import java.util.*?&gt;
  &lt;?import javafx.collections.*?&gt;
  &lt;?import javafx.geometry.*?&gt;
  &lt;?import javafx.scene.control.*?&gt;
  &lt;?import javafx.scene.layout.*?&gt;
  &lt;?import javafx.scene.paint.*?&gt;
  
  &lt;AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="com.es.javaFxTest.MainWindowController"&gt;
    &lt;children&gt;
      &lt;SplitPane id="splitPaneHorizontal1" dividerPositions="0.3614457831325301" focusTraversable="true" prefHeight="600.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"&gt;
        &lt;items&gt;
          &lt;AnchorPane id="anchorPane1" minHeight="0.0" minWidth="0.0" prefHeight="598.0" prefWidth="390.0"&gt;
            &lt;children&gt;
              &lt;VBox id="VBox" alignment="CENTER" prefHeight="598.0" prefWidth="177.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"&gt;
                &lt;children&gt;
                  &lt;TableView id="tableView1" fx:id="messageListTableView" editable="true" prefHeight="598.0" prefWidth="406.0"&gt;
                    &lt;columns&gt;
                      &lt;TableColumn prefWidth="75.0" text="Name" fx:id="messageTableMessageNameColumn" /&gt;
                    &lt;/columns&gt;
                  &lt;/TableView&gt;
                  &lt;HBox id="HBox" alignment="CENTER" spacing="5.0"&gt;
                    &lt;children&gt;
                      &lt;Button id="button2" fx:id="addMessageButton" text="Add"&gt;
                        &lt;HBox.margin&gt;
                          &lt;Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /&gt;
                        &lt;/HBox.margin&gt;
                      &lt;/Button&gt;
                      &lt;Button id="button1" fx:id="deleteMessageButton" text="Delete"&gt;
                        &lt;HBox.margin&gt;
                          &lt;Insets bottom="5.0" right="5.0" top="5.0" /&gt;
                        &lt;/HBox.margin&gt;
                      &lt;/Button&gt;
                    &lt;/children&gt;
                  &lt;/HBox&gt;
                &lt;/children&gt;
              &lt;/VBox&gt;
            &lt;/children&gt;
          &lt;/AnchorPane&gt;
          &lt;AnchorPane id="anchorPane2" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"&gt;
            &lt;children&gt;
              &lt;HBox id="HBox" alignment="CENTER" layoutX="44.0" layoutY="177.0" spacing="5.0"&gt;
                &lt;children&gt;
                  &lt;Label id="label2" text="Name:" /&gt;
                  &lt;TextField id="textField2" fx:id="messageNameTextField" prefWidth="200.0" text="TextField" /&gt;
                &lt;/children&gt;
              &lt;/HBox&gt;
            &lt;/children&gt;
          &lt;/AnchorPane&gt;
        &lt;/items&gt;
      &lt;/SplitPane&gt;
    &lt;/children&gt;
  &lt;/AnchorPane&gt;
  </code></pre>