2 Replies Latest reply: Jul 11, 2013 2:21 AM by Bobby1878 RSS

    TableView containing format-table TextFieldTableCells




      I have a TableView made up of columns of TextFieldTableCells and I would like to format a cell based on another cell value in the same row. As the CellFactory is being set for each of the TableColumns to use a TextFieldTableCell.forColumn(), how can I achieve both formatting the cell and accessing the row object in the same updateItem call?


      Im really stuck with this and would appreciate any pointers.




        • 1. Re: TableView containing format-table TextFieldTableCells

          This has quite a lot in common with TableView cell coloring on updates - noticing if sorting happened: you might want to have a look at the answer to that first.


          how can I achieve both formatting the cell

          Subclass TextFieldTableCell and override the updateItem() method to perform the formatting. If you are formatting conditionally on other properties (eg from other columns) that may change, you need to listen to those properties for changes. You need to manage the listener carefully as the cell may be reused for different items in the table. This part is similar to the thread described above.


          and accessing the row object in the same updateItem call

          Use getTableRow().getItem() to access the value for the table row. You can also use table.getItems().get(getIndex). Both require some checking: that getTableRow() doesn't return null, and the getIndex() returns a value in range.


          My canonical example, refactored for this question:



          import java.util.Arrays;
          import java.util.List;
          import javafx.application.Application;
          import javafx.beans.property.BooleanProperty;
          import javafx.beans.property.SimpleBooleanProperty;
          import javafx.beans.property.SimpleStringProperty;
          import javafx.beans.property.StringProperty;
          import javafx.beans.value.ChangeListener;
          import javafx.beans.value.ObservableValue;
          import javafx.collections.FXCollections;
          import javafx.collections.ObservableList;
          import javafx.event.ActionEvent;
          import javafx.event.EventHandler;
          import javafx.scene.Scene;
          import javafx.scene.control.Button;
          import javafx.scene.control.TableCell;
          import javafx.scene.control.TableColumn;
          import javafx.scene.control.TableRow;
          import javafx.scene.control.TableView;
          import javafx.scene.control.cell.CheckBoxTableCell;
          import javafx.scene.control.cell.PropertyValueFactory;
          import javafx.scene.control.cell.TextFieldTableCell;
          import javafx.scene.layout.BorderPane;
          import javafx.stage.Stage;
          import javafx.util.Callback;
          import javafx.util.StringConverter;
          public class FormattedTableWithTextFields extends Application {
            public void start(Stage primaryStage) {
              final BorderPane root = new BorderPane();
              final TableView<Player> table = new TableView<Player>();
              final TableColumn<Player, String> firstNameColumn = new TableColumn<>("First Name");    
              final TableColumn<Player, String> lastNameColumn = new TableColumn<>("Last Name");
              final TableColumn<Player, Boolean> injuredColumn = new TableColumn<>("Injured");
              firstNameColumn.setCellValueFactory(new PropertyValueFactory<Player, String>("firstName"));
              lastNameColumn.setCellValueFactory(new PropertyValueFactory<Player, String>("lastName"));
              injuredColumn.setCellValueFactory(new PropertyValueFactory<Player, Boolean>("injured"));
              table.getColumns().addAll(firstNameColumn, lastNameColumn, injuredColumn);
              Button button = new Button("Dump info");
              button.setOnAction(new EventHandler<ActionEvent>() {
                public void handle(ActionEvent event) {
                  for (Player p : table.getItems()) {
              final Scene scene = new Scene(root, 400, 600);
            private void installCustomTextFieldCellFactory(TableColumn<Player, String> column) {
              column.setCellFactory(new Callback<TableColumn<Player, String>, TableCell<Player, String>>() {
                public TableCell<Player, String> call(TableColumn<Player, String> column) {
                  return new StyledTextFieldTableCell();
            public static void main(String[] args) {
            private ObservableList<Player> createData() {
              List<Player> players = Arrays.asList(
                  new Player("Hugo" ,"Lloris", false),
                  new Player("Brad", "Friedel", false),
                  new Player("Kyle", "Naughton", false),
                  new Player("Younes", "Kaboul", true),
                  new Player("Benoit", "Assou-Ekotto", false),
                  new Player("Jan", "Vertonghen", false),
                  new Player("Michael", "Dawson", false),
                  new Player("William", "Gallas", true),
                  new Player("Kyle", "Walker", false),
                  new Player("Scott", "Parker", false),
                  new Player("Mousa", "Dembele", false),
                  new Player("Sandro", "Cordeiro", true),
                  new Player("Tom", "Huddlestone", false),
                  new Player("Gylfi","Sigurdsson", false),
                  new Player("Gareth", "Bale", false),
                  new Player("Aaron", "Lennon", false),
                  new Player("Paulinho", "Maciel", false),
                  new Player("Jermane", "Defoe", false),
                  new Player("Emmanuel", "Adebayor", true)
              return FXCollections.observableArrayList(players);
            private static class StyledTextFieldTableCell extends TextFieldTableCell<Player, String> {
              private final ChangeListener<Boolean> injuredListener ;
              private Player previousPlayer ;
              StyledTextFieldTableCell() {
                // Seems we have to set a trivial string converter:
                super(new StringConverter<String>() {
                  public String fromString(String string) {
                    return string;
                  public String toString(String object) {
                    return object;
                injuredListener = new ChangeListener<Boolean>() {
                  public void changed(ObservableValue<? extends Boolean> observable,
                      Boolean oldValue, Boolean newValue) {
                    if (newValue) {
                    } else {
              public void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                Player currentPlayer = null ;
                TableRow<Player> tableRow = getTableRow();
                if (tableRow != null) {
                  currentPlayer = tableRow.getItem();
                if (previousPlayer != currentPlayer) {
                  if (previousPlayer != null) {
                  if (currentPlayer != null) {
                    if (currentPlayer.isInjured() ) {
                    } else if (! currentPlayer.isInjured()) {
                  previousPlayer = currentPlayer ;
              private void ensureNoInjuredStyleClass() {
                while (getStyleClass().contains("injured")) {
              private void ensureInjuredStyleClass() {
                if (! getStyleClass().contains("injured")) {
            public static class Player {
              private final StringProperty firstName ;
              private final StringProperty lastName ;
              private final BooleanProperty injured ;
              Player(String firstName, String lastName, boolean international) {
                this.firstName = new SimpleStringProperty(this, "firstName", firstName);
                this.lastName = new SimpleStringProperty(this, "lastName", lastName);
                this.injured = new SimpleBooleanProperty(this, "injured", international);
              public String getFirstName() { return firstName.get(); }
              public void setFirstName(String firstName) { this.firstName.set(firstName);}
              public StringProperty firstNameProperty() { return firstName ; }
              public String getLastName() { return lastName.get(); }
              public void setLastName(String lastName) { this.lastName.set(lastName); }
              public StringProperty lastNameProperty() { return lastName ; }    
              public boolean isInjured() { return injured.get(); }
              public void setInjured(boolean international) { this.injured.set(international); }
              public BooleanProperty injuredProperty() { return injured ; }
              public String toString() {
                return firstName.get() + " " + lastName.get() + (injured.get()?" (injured)":"");



          And the css (formattedTableWithTextFields.css):

          @CHARSET "US-ASCII";
          .table-cell.injured .text-field, .table-cell.injured .label {
           -fx-text-fill: red ; 
          .table-cell.injured .text {
            -fx-fill: red ;


          Message was edited by: James_D (Slight refactor of code, added css)

          • 2. Re: TableView containing format-table TextFieldTableCells

            Thanks very much James, you've hit the nail on head - this is exactly what I need.


            Thanks again for your time, its much appreciated!