Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JavaFX TableView row highlighting sample using css lookup functions.
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 DebtCollectionTable extends Application {
public static void main(String[] args) throws Exception { launch(args); }
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);
table.setPrefHeight(250);
stage.setScene(new Scene(table));
stage.getScene().getStylesheets().add(getClass().getResource("reaper.css").toExternalForm());
stage.show();
// highlight the table rows depending upon whether we expect to get paid.
int i = 0;
for (Node n: table.lookupAll("TableRow")) {
if (n instanceof TableRow) {
TableRow row = (TableRow) n;
if (table.getItems().get(i).getWillPay()) {
row.getStyleClass().add("willPayRow");
} else {
row.getStyleClass().add("wontPayRow");
}
i++;
if (i == table.getItems().size())
break;
}
}
}
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);
column.setSortable(false);
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);
if (item != null) {
setText(item.toString());
this.getStyleClass().add(item ? "willPayCell" : "wontPayCell");
}
}
};
}
});
column.setPrefWidth(prefWidth);
column.setSortable(false);
return column;
}
}
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; }
}
/** 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; }
@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented May 23, 2012

https://forums.oracle.com/forums/thread.jspa?threadID=2392197 "Thread: Change TableView row appearance based on the data values"

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Feb 23, 2013

https://forums.oracle.com/forums/thread.jspa?threadID=2503046 "Thread: Setting the font color of data inside tablecell"

@PoussinBleu

This comment has been minimized.

Copy link

@PoussinBleu PoussinBleu commented Apr 22, 2013

Hi,
I wanted to use your solution to override the css apply to a row in function of the data it contains but unfortunately, the set that is returned by tableview.lookupAll("TableRow") is empty :-(
Can you help we to understand why it is empty ?

Thanks for your help.

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Apr 24, 2013

A lookup won't work until the respective cells have been displayed on an active scene and a rendering pulse has occurred. The stage.show() method in the example ensures that this has occurred for the initial data display. If you dynamically modify the data after this, then you need to wait for a rendering pulse to have occurred and updated the scene. You can use an AnimationTimer for that, but it is pretty messy. In general, it is best to use css style sheets and style class manipulation for css tasks rather than lookups as those mechanisms don't suffer from timing related issues that you get for lookups. However, when I was coding this particular sample the only way I could get at the data involved at the time was to use a lookup.

Perhaps there is a better mechanism which would allow you to directly manipulate the style classes for the rows and hence avoid the lookup in the code.

An alternate solution is to provide your own row factory, where you set custom style classes within the rows returned by the factory - but I believe that is a bit complicated, though I haven't tried it. Maybe if you tried that approach you may find it easy.

@jewelsea

This comment has been minimized.

Copy link
Owner Author

@jewelsea jewelsea commented Apr 26, 2013

I worked out a way to use the table row api to color rows in the table and avoid the lookup mechanism used in this gist.

I posted a new sample using the table row api rather than the lookup mechanism.

Using the table row api is a preferred solution to using a lookup.

@RMilies

This comment has been minimized.

Copy link

@RMilies RMilies commented Jul 16, 2016

Thank you so much! You helped me a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.