JavaFX TableView row highlighting sample using table row apis and css.

  • Download Gist
DebtCollectionTableWithRowHighlighting.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
 
// demonstrates highlighting rows in a tableview based upon the data values in the rows.
public class DebtCollectionTableWithRowHighlighting extends Application {
public static void main(String[] args) throws Exception { launch(args); }
@Override public void start(final Stage stage) throws Exception {
stage.setTitle("So called friends . . .");
 
// create a table.
TableView<Friend> table = new TableView(Friend.data);
table.getColumns().addAll(makeStringColumn("Name", "name", 150), makeStringColumn("Owes Me", "owesMe", 300), makeBooleanColumn("Will Pay Up", "willPay", 150));
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
 
stage.setScene(new Scene(table));
stage.getScene().getStylesheets().add(getClass().getResource("reaper.css").toExternalForm());
stage.show();
}
 
private TableColumn<Friend, String> makeStringColumn(String columnName, String propertyName, int prefWidth) {
TableColumn<Friend, String> column = new TableColumn<>(columnName);
column.setCellValueFactory(new PropertyValueFactory<Friend, String>(propertyName));
column.setCellFactory(new Callback<TableColumn<Friend, String>, TableCell<Friend, String>>() {
@Override public TableCell<Friend, String> call(TableColumn<Friend, String> soCalledFriendStringTableColumn) {
return new TableCell<Friend, String>() {
@Override public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
}
}
};
}
});
column.setPrefWidth(prefWidth);
 
return column;
}
private TableColumn<Friend, Boolean> makeBooleanColumn(String columnName, String propertyName, int prefWidth) {
TableColumn<Friend, Boolean> column = new TableColumn<>(columnName);
column.setCellValueFactory(new PropertyValueFactory<Friend, Boolean>(propertyName));
column.setCellFactory(new Callback<TableColumn<Friend, Boolean>, TableCell<Friend, Boolean>>() {
@Override public TableCell<Friend, Boolean> call(TableColumn<Friend, Boolean> soCalledFriendBooleanTableColumn) {
return new TableCell<Friend, Boolean>() {
@Override public void updateItem(final Boolean item, final boolean empty) {
super.updateItem(item, empty);
// clear any custom styles
this.getStyleClass().remove("willPayCell");
this.getStyleClass().remove("wontPayCell");
this.getTableRow().getStyleClass().remove("willPayRow");
this.getTableRow().getStyleClass().remove("wontPayRow");
// update the item and set a custom style if necessary
if (item != null) {
setText(item.toString());
this.getStyleClass().add(item ? "willPayCell" : "wontPayCell");
this.getTableRow().getStyleClass().add(item ? "willPayRow" : "wontPayRow");
}
}
};
}
});
column.setPrefWidth(prefWidth);
 
return column;
}
}
Friend.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
import javafx.collections.*;
 
/** Sample data for a table view */
public class Friend {
final static public ObservableList data = FXCollections.observableArrayList(
new Friend("George", "Movie Ticket", true),
new Friend("Irene", "Pay Raise", false),
new Friend("Ralph", "Return my Douglas Adams Books", false),
new Friend("Otto", "Game of Golf", true),
new Friend("Sally", "$12,045.98", false),
new Friend("Antoine", "Latte", true)
);
 
final private String name;
final private String owesMe;
final private boolean willPay;
public Friend(String name, String owesMe, boolean willPay) {
this.name = name; this.owesMe = owesMe; this.willPay = willPay;
}
public String getName() { return name; }
public String getOwesMe() { return owesMe; }
public boolean getWillPay() { return willPay; }
}
reaper.css
CSS
1 2 3 4 5 6 7 8 9 10
/** file: reaper.css
place in same directory as DebtCollectionTable.java */
.root { -fx-font: 18px "Comic Sans MS"; }
.column-header-background { -fx-background-color: azure; }
.willPayRow { -fx-background-color: palegreen; }
.wontPayRow { -fx-background-color: coral; }
.willPayCell { -fx-background-color: forestgreen; }
.wontPayCell { -fx-background-color: firebrick; }
.table-row-cell:empty { -fx-background-color: cornsilk; }
.table-row-cell:empty .table-cell { -fx-border-width: 0px; }

Updated (and greatly preferred) version of a previous table row highlighting gist which sets row style classes directly using an table row api on the row rather than using a css lookup.

Using the table row api is vastly preferred to the css lookup mechanism used in the previous example because it allows values in the item list to be changed and the list to sorted and the row style will be dynamically updated by the table's inbuilt binding mechanisms - that behavior does not occur in the case of lookups.

Also the coloring based on the table row api does not require a rendering pulse to have been run to render the table, which is required for a lookup to work - therefore the call to set the style class on the row is not time sensitive using the table row api as it is in a lookup..

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.