pawchi
pawchi

Reputation: 143

JavaFx treetableview setStyle for rows with NO children

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.

Need setStyle rows with "A1" and "A2" - no children rows.

Upvotes: 0

Views: 94

Answers (1)

James_D
James_D

Reputation: 209724

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 PseudoClasses, 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:

enter image description here

Upvotes: 4

Related Questions