Wednesday, February 6, 2019

Style it baby...


The people that know me know that I first was not a big fan of CSS in JavaFX and a year after that I was THE big fan of CSS but another year later I switched back to code only. There are several reasons for that but mainly it was about the performance of the CSS implementation and about missing features in CSS that made me mix up code and CSS which I did not like.
So I switched to code only in my Medusa and TilesFX library where I also use JavaFX Canvas which content is not styleable by CSS in the way the other nodes are.
Well don't get me wrong, I'm not completely against CSS in JavaFX, esp. for application level stuff it is great and fast enough. But when it comes to controls I do not really like it.
I knew that someday someone will ask me how to style a Medusa gauge or a TilesFX tile and here we go...

So if you really need to style a Medusa gauge by using CSS here is an example on how to do it.
In principle you need to create a new skin that makes use of CSS, in this example let's create a styleable version of the new PlainAmpSkin. It is simply a copy of the existing skin class where I removed the code that directly sets the colors and gradients and added some style classes.
The idea is to extend the Gauge class and in this new class add some styleable properties for the things that cannot be styled directly (e.g. the tickmarks and ticklabels because they are drawn in a Canvas node).
The styleable properties will be triggered by loading a css stylesheet that contains the defined style classes. So we simply add listeners to the styleable properties and trigger the appropriate properties in the Gauge class with the values from the styleable properties.
I hope you understand what I'm talking about :)
So the example is as follows:

1. We create a StyleableGauge class that has a styleable property named styleableTickmarkColor as follows:

public class StyleableGauge extends Gauge {

    private static final StyleablePropertyFactory<StyleableGauge> FACTORY = 
        new StyleablePropertyFactory<>(Control.getClassCssMetaData());
    private static final CssMetaData<StyleableGauge, Color> TICKMARK_COLOR = 
        g -> g.styleableTickmarkColor, Color.rgb(220, 220, 220), false);
    private final StyleableProperty<Color> styleableTickmarkColor;

    public StyleableGauge() {
    public StyleableGauge(@NamedArg("SKIN_TYPE") final SkinType SKIN_TYPE) {
        styleableTickmarkColor = 
            new SimpleStyleableObjectProperty<>(TICKMARK_COLOR, 

    public Color getStyleableTickmarkColor() { 
        return styleableTickmarkColor.getValue(); 
    public void setStyleableTickmarkColor(final Color COLOR) { 
    public ObjectProperty<Color> styleableTickmarkColorProperty() { 
        return (ObjectProperty<Color>) styleableTickmarkColor; 

    @Override public String getUserAgentStylesheet() {
        return StyleableGauge.class.getResource("custom-plain-amp.css").toExternalForm();

    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
        return FACTORY.getCssMetaData(); }
    @Override public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { 
        return FACTORY.getCssMetaData(); 

2. We create a css file named "custom-plain-amp.css" that looks as follows:

.gauge {
    BRIGHT_COLOR   : rgb(220, 220, 220);

    -tickmark-color: BRIGHT_COLOR;

3. Now we need to create our custom skin named "CustomPlainAmpSkin".
In this skin we make use of the css style classes. Because the skin file simply is too long to show it here.
The complete example can be found in the medusademo project on github.

With this you can style even canvas node content indirectly by triggering "standard" properties in the control by making use of "styleable" properties. 
I would not recommend to use this approach as the standard approach but it is good enough to make use of CSS even if the controls do not support CSS styling directly.

I hope that was more or less clear for you to understand...otherwise just let me know :)

Oh and do not forget to keep coding... ;)

No comments:

Post a Comment