JavaFX-CSS: How to “move” style of parent to a child?


Tags: java,javafx-8,treecell,javafx-css

Problem :

The trigger for this was a quick experiment to solve TreeItem selection width: the requirement is to highlight only the text, not the whole tree cell. Nothing easier than that (said Frederik :)

  • implement a custom TreeCell with a Label as graphic (and configure the label with the item as needed)
  • remove the selection style (mostly the highlight background from the cell
  • add the highlight style to the label

Something like (a runnable example using this is at the end):

public static class MyTreeCell extends TreeCell<String> {

    private Label label;

    public MyTreeCell() {
        getStyleClass().add("tree-text-only");
    }
    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            if (label == null) {
                label = new Label();
            }
            label.setText(item);
            setGraphic(label);
        }
    }
}

The css:

/* remove the highlight from cell as a whole, 
   c&p'd the unselected style from modena */
.tree-text-only:filled:selected {
    -fx-background: -fx-control-inner-background; 
    -fx-background-color: -fx-background;
}
/* c&p'd selected style */
/* using > doesn't make a different to the behaviour */ 
/* .tree-text-only:filled:selected > .label { */

.tree-text-only:filled:selected .label {
    /* following is the selection color from themes, doesn't show */
    -fx-background: -fx-selection-bar; 
    /* hard-coded color does show */
    /*   -fx-background-color: -fx-accent ; */
    /* auto-adjust text fill */
    /* no effect for hard-coded color, showing nothing for selection bar */
    -fx-text-fill: -fx-text-background-color;
}

Expected behaviour

  • label has highlighted background when using selection-bar
  • text auto-adjusts its fill

Actual behaviour:

  • using the "semantic" (?) highlight color selection-bar, the background color of the label is not changed to the highlight color but the text fill is changed to the "white", so the text doesn't show
  • using a hard-coded color (any, even the accent as above) changes the label's background but the text fill isn't updated

The obvious question: How to make it work as expected?

For convenience, a runnable example:

public class TreeCellExample extends Application {

    public static class MyTreeCell extends TreeCell<String> {

        private Label label;

        public MyTreeCell() {
            getStyleClass().add("tree-text-only");
        }
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (label == null) {
                    label = new Label();
                }
                label.setText(item);
                setGraphic(label);
            }
        }
    }

    private Parent getContent() {
        TreeItem root = createSubTree("root");
        root.setExpanded(true);
        TreeView tree = new TreeView(root);
        tree.getStylesheets().add(
                getClass().getResource("treetextonly.css").toExternalForm());
        tree.setCellFactory(p -> new MyTreeCell());
        BorderPane pane = new BorderPane(tree);
        return pane;
    }

    ObservableList rawItems = FXCollections.observableArrayList(
            "9-item", "8-item", "7-item", "6-item", 
            "5-item", "4-item", "3-item", "2-item", "1-item");

    protected TreeItem createSubTree(Object value) {
        TreeItem child = new TreeItem(value);
        child.getChildren().setAll((List<TreeItem>) rawItems.stream()
                .map(TreeItem::new)
                .collect(Collectors.toList()));
        return child;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Scene scene = new Scene(getContent());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}


Solution :

The reason why it doesn't work is because .label doesn't have a rule where -fx-background is applied, so any value assigned to it won't affect any of the Label properties.

What's more, Label doesn't use a -fx-background-color property.

So an easy solution would be adding it:

.tree-text-only > .label {
    -fx-background-color: -fx-background; 
}

Now you can apply all the style using only this "semantic" colors.

Note I've added also the case where the control doesn't have the focus:

/* 
 * remove the highlight from cell as a whole 
 */

/* Selected rows */
.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-text-only:filled:selected {
    -fx-background: -fx-control-inner-background; 
}
/* Selected when control is not focused */
.tree-text-only:filled:selected {
    -fx-background: -fx-control-inner-background; 
}
/* focused cell (keyboard navigation) */
.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-text-only:focused {
    -fx-cell-focus-inner-border: -fx-control-inner-background; 
}

/* 
 * highlight only the label
 */

// Add background color rule
.tree-text-only > .label {
    -fx-background-color: -fx-background; 
}
/* Selected rows */
.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-text-only:filled:selected > .label {
    -fx-background: -fx-selection-bar; 
}
/* Selected when control is not focused */
.tree-text-only:filled:selected > .label {
    -fx-background: -fx-selection-bar-non-focused;
}
/* focused cell (keyboard navigation) */
.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-text-only:focused > .label {
    -fx-background: -fx-selection-bar; 
}

    CSS Howto..

    I have a video background on my bootstrap page - how can I make it “fixed”?

    IE8 Not showing divs with floats

    Ionic 2.0.0-beta.24 how can i import node_module css files without ionic.config.js

    How to use vertical menus in HTML and css?

    How can I make my container transparent without making the whole site transparent too?

    how to remove resize in text area tag

    How to give shadow to a border

    How to make selected file name visible?

    CSS, borders: How do I prevent a border added to a table cell from displacing neighboring cells?
    I think you'll either need to size all non border cells wider and higher by the width of the line around it. or you given them all borders and set...
    Read more

    How to create a sticky footer in CSS inside an absolutely positioned div?

    How to fit a dynamic PHP form in a div (to be able to fit fullpage.js)?

    How to make a progress bar like this in CSS

    How can I make one item with its own class a different colour from others?

    How to debug HTML/CSS for iPhone/iPad performance?

    How to remove simple text from HTML/HAML

    How to change extjs grid single cell background color depending on value changes?

    How to change order of table td for responsive?

    How to add css to my page via Git Hub raw?

    How put div element to bottom of another div element

    css, how to stop an element being squashed by container

    How to change a defined value to a unspecified value by css?

    CSS Button Animation - How to Accomplish?

    How does content CSS property define the icon in bootstrap

    CSS- how to prevent the original title info to be displayed

    How do I make images interactive?

    How to make a css compatible by all browser

    How to fix redefinition warnings from CSS Validator?

    How to get rid of spaces between images in CSS?

    How to control the text inside DIV tag by not allowing the text to be increased?

    How to make responsive text that isn't too large or too small