Issue
In TreeTableView I need to find and setStyle rows with NO children. In below code example, problematic code is in method: markRows.
public class Controller {
public TreeTableView<MyTreeObject> fuses_ttv;
private ArrayList<MyTreeObject> data = new ArrayList<>();
private void createTreeTableView(){}
private void markRows(){
fuses_ttv.setRowFactory(row -> new TreeTableRow<MyTreeObject>(){
@Override
protected void updateItem(MyTreeObject item, boolean empty) {
super.updateItem(item, empty);
if (item==null){
setStyle(null);
} else if (item.getType().equals("FRC")){
setStyle("-fx-background-color: lightslategray;");
} else if(item.getType().equals("wire")){
setStyle("-fx-background-color: lightyellow;");
} //***** else if (ROW HAS NOW CHILDREN) - HOW TO DO IT????? ******
}
});
}
}
Like in picture below - rows with SLOT "A1" and "A2" have no children. How to identify such rows? Thanks in advance for any help.
Solution
In JavaFX 19 and later you can do:
fuses_ttv.setRowFactory(row -> new TreeTableRow<MyTreeObject>(){
{
treeItemProperty().flatMap(TreeItem::leafProperty)
.orElse(false)
.addListener((obs, wasLeaf, isLeaf) -> {
if (isLeaf) {
// set style for leaf (no children)
} else {
// set style for non-leaf (has children)
}
});
}
@Override
protected void updateItem(MyTreeObject item, boolean empty) {
super.updateItem(item, empty);
if (item==null){
setStyle(null);
} else if (item.getType().equals("FRC")){
setStyle("-fx-background-color: lightslategray;");
} else if(item.getType().equals("wire")){
setStyle("-fx-background-color: lightyellow;");
} //***** else if (ROW HAS NOW CHILDREN) - HOW TO DO IT????? ******
}
});
I would actually recommend setting custom PseudoClass
es, and an external style sheet, instead of using inline styles.
Here is a complete working example:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TreeTableStyleExample extends Application {
private int itemCount ;
@Override
public void start(Stage stage) throws IOException {
TreeTableView<Integer> table = new TreeTableView<>();
TreeTableColumn<Integer, Number> column = new TreeTableColumn<>("Item");
table.getColumns().add(column);
column.setCellValueFactory(data -> new SimpleIntegerProperty(data.getValue().getValue()));
column.setCellFactory(ttv -> new TreeTableCell<>() {
@Override
protected void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
setText("Item "+item);
}
}
});
PseudoClass leaf = PseudoClass.getPseudoClass("leaf");
PseudoClass odd = PseudoClass.getPseudoClass("odd-value");
PseudoClass even = PseudoClass.getPseudoClass("even-value");
table.setRowFactory( ttv -> new TreeTableRow<>() {
{
treeItemProperty().flatMap(TreeItem::leafProperty).orElse(false)
.addListener((obs, wasLeaf, isNowLeaf) -> pseudoClassStateChanged(leaf, isNowLeaf));
}
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
pseudoClassStateChanged(odd, false);
pseudoClassStateChanged(even, false);
} else {
pseudoClassStateChanged(odd, item % 2 == 1);
pseudoClassStateChanged(even, item % 2 == 0);
}
}
});
table.setRoot(buildTable(20));
Button add = new Button("Add item");
add.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedItems()));
add.setOnAction(e -> {
TreeItem<Integer> treeItem = new TreeItem<>(++itemCount);
treeItem.setExpanded(true);
table.getSelectionModel().getSelectedItem().getChildren().add(treeItem);
});
Button remove = new Button("Remove");
remove.disableProperty().bind(Bindings.isEmpty(table.getSelectionModel().getSelectedItems())
.or(Bindings.equal(table.getSelectionModel().selectedItemProperty(), table.getRoot())));
remove.setOnAction(e -> {
TreeItem<Integer> selection = table.getSelectionModel().getSelectedItem();
selection.getParent().getChildren().remove(selection);
});
HBox controls = new HBox(5, add, remove);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(table);
root.setBottom(controls);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
private TreeItem<Integer> buildTable(int numItems) {
Random rng = new Random();
TreeItem<Integer> root = new TreeItem<>(1);
root.setExpanded(true);
List<TreeItem> items = new ArrayList<>();
items.add(root);
for (itemCount = 2; itemCount <= numItems ; itemCount++) {
TreeItem<Integer> item = new TreeItem<>(itemCount);
item.setExpanded(true);
items.get(rng.nextInt(items.size())).getChildren().add(item);
items.add(item);
}
return root ;
}
public static void main(String[] args) {
launch();
}
}
with style.css
:
.tree-table-row-cell:odd-value {
-fx-background: lightslategray ;
}
.tree-table-row-cell:even-value {
-fx-background: lightyellow;
}
.tree-table-row-cell:leaf {
-fx-background: lightgreen ;
}
Sample output:
Answered By - James_D
Answer Checked By - Pedro (JavaFixing Volunteer)