Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to style TreeCell children?

First, some context: I have a TreeView in my JavaFX application, with a custom TreeCell implementation. This implementation adds a HBox to display a label (using LabeledText) and one (or more) icons / status indicators to the right. The label and icons also get tooltips attached to them. When inspected with Scenic View, the result is something like this:

Scenic View of my TreeView

As you can see in the image above, a cell contains a HBox with the label (LabeledText), spacing region, and in this example one icon (using a font hence the Glyph+LabeledText). More icons might be added using either a font or at some point maybe images.

Depending on the status of the item represented, I want to style the label differently (eg different text color, italics, ...). The resulting TreeView currently looks like this:

TreeView as displayed in application

Actual question: I have tried a couple of variants of my approach, but the logical solution doesn't work properly even though it seems it should. Am I missing something? Have I perhaps discovered a bug in JavaFX CSS handling?

I have a workaround which currently works (but may cease to do so if I add certain features to my TreeView) so I would still like to know why this doesn't work as expected.

Basic approach

Depending on the item displayed and it's status, apply relevant CSS classes to the TreeCell. Using CSS selectors, style the inner label. For example:

.mystatus > HBox > .text {
    -fx-font-style: italic;
}

/* the following variants give mostly the same result */
.mystatus > HBox > LabeledText {
    -fx-font-style: italic;
}
.mystatus .text { /* only difference: this messes up my icons */
    -fx-font-style: italic;
}

The issue I have is that the CSS selection of children of a TreeCell seems not to work reliably once the user starts manipulating the TreeView in the UI. CSS gets applied to nodes which do not match the given CSS rules. For example, after expanding/collapsing some items, labels which do not match the CSS selectors get italicised anyway.

So, if you look at the image above and suppose that is a correct display for my items. Collapsing/reopening the Item 1-node might result in, say Item 3 suddenly becoming italicised even though no such CSS was ever added to that node.

I verified the applied classes using Scenic View to ensure I was setting/clearing classes properly: there are LabeledText nodes inside a CustomTreeCellImpl without the mystatus class that still get italicised.

Alternative 1: using pseudoclasses instead of regular classes

Same issue as the basic approach above

Example CSS:

*.tree-cell:mystatus > HBox > .text {
    -fx-font-style: italic;
}

Alternative 2: apply classes or pseudoclasses directly to LabeledText instead of TreeCell

Same issue as the basic approach above

Example CSS:

.text:mystatus {
    -fx-font-style: italic;
}

Alternative 3: directly apply CSS properties to the created label through code

Again, this runs into the same issue as before: after manipulating the tree, styles get applied where they shouldn't.

Here is the relevant part of the method that populates/updates the TreeCell:

// add label
LabeledText text = new LabeledText(this);
text.setText("Item 1");
if(someCondition) {
    text.setStyle("-fx-font-style: italic;");
}
hbox.getChildren().add(text);

The LabeledText object never has its text changed: a new one is always created. Even then I get incorrect results.

This strikes me as especially odd as this has nothing to do with CSS selectors any more - style is applied directly to the node, but the problem still persists.

The workaround

For those who are interested in how I managed to work around the problem - for now: apply classes or pseudoclasses to the entire TreeCell, and add exceptions/overrides for child elements I do not want styled to restore default layout.

This mostly works but might become cumbersome if/when I add more elements to the cells. Also, I speculate this only works because here all the child elements (aside from the label) have the exact same style applied, regardless of the status of the item they are displaying (eg all Glyphs are black normal font, etc).

If/when I want to customize the style of these (eg change Glyph color depending on context, instead of just using different Glyph characters), I speculate I may again run into this issue - this time with no clue how to solve it as my workaround will no longer be applicable.


Update: I put a project on GitHub which demonstrates the issue.

The demo data in the project is supposed to put items 1.1 and 1.3 in italics, with all others shown normal. When expanding/collapsing item 1, items which shouldn't get italicised anyway (on Windows).

Also, when creating this example I noticed that on OS X none of the items get italicised (the CSS itself gets loaded properly, a different style I added temporarily to test did get applied). On Windows, the issue as described above happens.

like image 300
brain99 Avatar asked Nov 08 '22 16:11

brain99


1 Answers

The mistake was to use the com.sun.javafx.scene.control.skin.LabeledText for displaying your item text.

If you use the normal javafx.scene.control.Label.Label or javafx.scene.text.Text instead everything works fine in your example.

The LabeledText internally uses a StyleablePropertyMirror that attaches itself as a listener to various properties of the TreeItem and applies these style changes to itself (the LabeledText).

To explain: The TreeView is basically just a customized ListView with some indenting. Note that both rely on the concept of recycling cells as much as possible.


And if we look at your structure before collapsing:

  • (1) Item 1
    • (2) Item 1.1 (highlighted)
    • (3) Item 1.2
    • (4) Item 1.3 (highlighted)
    • (5) Item 1.4
  • (6) Item 2

And after collapsing:

  • (1) Item 1
  • (2) Item 2 (highlighted)

Now it shouldnt surprise you that Item 2 now has the same highlighting that Item 1.1 had before because it is basically the same cell (at the same index position) now displaying a different item.

like image 174
eckig Avatar answered Nov 15 '22 00:11

eckig