Reputation: 893
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:
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:
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.
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.
Same issue as the basic approach above
Example CSS:
*.tree-cell:mystatus > HBox > .text {
-fx-font-style: italic;
}
Same issue as the basic approach above
Example CSS:
.text:mystatus {
-fx-font-style: italic;
}
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.
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.
Upvotes: 5
Views: 1462
Reputation: 11134
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:
And after collapsing:
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.
Upvotes: 1