Skip to content

Instantly share code, notes, and snippets.

@jewelsea
Created June 7, 2012 05:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jewelsea/2886805 to your computer and use it in GitHub Desktop.
Save jewelsea/2886805 to your computer and use it in GitHub Desktop.
JavaFX sample of styling various rows of a table using node lookups.
/** 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 RowStyledTable.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; }
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
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.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 RowStyledTable 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");
row.setDisable(false);
} else {
row.getStyleClass().add("wontPayRow");
row.setDisable(true);
}
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;
}
}
@jewelsea
Copy link
Author

jewelsea commented May 1, 2016

Answer to StackOverflow question Disable TableRow based on data

@jewelsea
Copy link
Author

jewelsea commented May 1, 2016

Note that although this lookup based solution will work, it is probably not the best solution to this problem. Lookups in JavaFX are quite fragile constructs due to their reliance on CSS application passes having occurred, and those CSS layout passes sometimes need to be triggered manually in order for the lookup to function. Also lookups do not provide typing information, so they require explicit casts, so you lose some of the goodness of strongly typed languages such as Java.

Instead of using the lookup based approach demonstrated here, I advise you use a custom cell factory approach as demonstrated by james-d in his gist: Example of a row factory wrapper for TableViews which manages adding and removing a style class from a list of row indexes..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment