title: Programmatically change the TableView row appearance
body: <p>After doing a <a href="http://docs.oracle.com/javafx/2/ui_controls/table-view.htm" rel="nofollow noreferrer">Oracle tutorial about the TableView</a>, I was wondering if there's a way to programmatically apply different CSS style to the selected TableView row. For example, user selects a certain row, clicks the "Highlight" button and the selected row gets brown background, white text fill, etc. I've read the <a href="https://stackoverflow.com/questions/13697115/javafx-tableview-colors">JavaFX tableview colors</a>, <a href="https://stackoverflow.com/questions/16153838/updating-tableview-row-appearance?lq=1">Updating TableView row appearance</a> and <a href="https://stackoverflow.com/questions/16200901/background-with-2-colors-in-javafx">Background with 2 colors in JavaFX?</a>, but to no avail =/</p>
  
  <p>Here's the source:</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.beans.property.SimpleStringProperty;
  import javafx.collections.FXCollections;
  import javafx.collections.ObservableList;
  import javafx.event.ActionEvent;
  import javafx.event.EventHandler;
  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.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;
  
  public class TableViewSample extends Application {
  
      private TableView&lt;Person&gt; table = new TableView&lt;Person&gt;();
      private final ObservableList&lt;Person&gt; 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")
          );
  
      public static void main(String[] args) {
          launch(args);
      }
  
      @Override
      public void start(Stage stage) {
          Scene scene = new Scene(new Group());
          stage.setTitle("Table View Sample");
          stage.setWidth(450);
          stage.setHeight(600);
  
          final Label label = new Label("Address Book");
          label.setFont(new Font("Arial", 20));
  
          TableColumn firstNameCol = new TableColumn("First Name");
          firstNameCol.setMinWidth(100);
          firstNameCol.setCellValueFactory(
                  new PropertyValueFactory&lt;Person, String&gt;("firstName"));
  
          TableColumn lastNameCol = new TableColumn("Last Name");
          lastNameCol.setMinWidth(100);
          lastNameCol.setCellValueFactory(
                  new PropertyValueFactory&lt;Person, String&gt;("lastName"));
  
          TableColumn emailCol = new TableColumn("Email");
          emailCol.setMinWidth(200);
          emailCol.setCellValueFactory(
                  new PropertyValueFactory&lt;Person, String&gt;("email"));
  
          table.setItems(data);
          table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
  
          final Button btnHighlight = new Button("Highlight selected row");
          btnHighlight.setMaxWidth(Double.MAX_VALUE);
          btnHighlight.setPrefHeight(30);
  
          btnHighlight.setOnAction(new EventHandler&lt;ActionEvent&gt;(){
              public void handle(ActionEvent e){
                  // this is where the CSS should be applied
              }
          });
  
          final VBox vbox = new VBox();
          vbox.setSpacing(5);
          vbox.setPadding(new Insets(10, 0, 0, 10));
          vbox.getChildren().addAll(label, table, btnHighlight);
  
          ((Group) scene.getRoot()).getChildren().addAll(vbox);
  
          stage.setScene(scene);
          stage.show();
      }
  
      public static class Person {
  
          private final SimpleStringProperty firstName;
          private final SimpleStringProperty lastName;
          private final SimpleStringProperty email;
  
          private Person(String fName, String lName, String email) {
              this.firstName = new SimpleStringProperty(fName);
              this.lastName = new SimpleStringProperty(lName);
              this.email = new SimpleStringProperty(email);
          }
  
          public String getFirstName() {
              return firstName.get();
          }
  
          public void setFirstName(String fName) {
              firstName.set(fName);
          }
  
          public String getLastName() {
              return lastName.get();
          }
  
          public void setLastName(String fName) {
              lastName.set(fName);
          }
  
          public String getEmail() {
              return email.get();
          }
  
          public void setEmail(String fName) {
              email.set(fName);
          }
      }
  } 
  </code></pre>
  
  <p>And the <strong>application.css</strong> from which the "Highlight selected row" button applies the highlightedRow class to the selected table row:</p>
  
  <pre><code>.highlightedRow {
      -fx-background-color: brown;
      -fx-background-insets: 0, 1, 2;
      -fx-background: -fx-accent;
      -fx-text-fill: -fx-selection-bar-text;
  }
  </code></pre>
  
  <h3>Edit:</h3>
  
  <p>After several hours of trying, the best thing I could come up is <a href="https://dl.dropboxusercontent.com/u/34696560/KoBSON/PDFDownloader/abook.jpg" rel="nofollow noreferrer">this</a> using the code below:</p>
  
  <pre><code>firstNameCol.setCellFactory(new Callback&lt;TableColumn&lt;Person, String&gt;, TableCell&lt;Person, String&gt;&gt;() {
      @Override
      public TableCell&lt;Person, String&gt; call(TableColumn&lt;Person, String&gt; personStringTableColumn) {
          return new TableCell&lt;Person, String&gt;() {
              @Override
              protected void updateItem(String name, boolean empty) {
                  super.updateItem(name, empty);
                  if (!empty) {
                      if (name.toLowerCase().startsWith("e") || name.toLowerCase().startsWith("i")) {
                          getStyleClass().add("highlightedRow");
                      }
                      setText(name);
                  } else {
                      setText("empty");  // for debugging purposes
                  }
              }
          };
      }
  });
  </code></pre>
  
  <p>The part I don't really understand is why I can't do that from inside the <code>setOnAction</code> method of the <code>btnHighlight</code>? I also tried refreshing the table afterwards (<a href="https://stackoverflow.com/a/12708349/1219226">described here</a>), but it didn't seem to work. Also, my "solution" only works for the <code>firstNameCol</code> column, so does one have to set new cell factory for each column in order to apply a certain style, or is there a smarter solution?</p>