понедельник, 23 августа 2010 г.

Creating Pseudo-class in JavaFx (TabPanel control)

Before reading this article I suggest to read Advanced JavaFX Control Styling by Dean Iverson.
After JavaFx 1.3 has been published we've got a new bunch of controls and a new way to produce our own ones and, of course, don't forget about new CSS support in this release. So, today I'm going to show you how to create your own JavaFx controls with CSS support.

Specification

Currently there are no tabs in JavaFx, and that's a good reason to start having them :). At the end I expect to get such a result:

Specification itself:

  • TabPanel has TabButtons
  • You are able to select only one TabButton in TabPanel
  • You are able to set styles for TabButtons and TabPanel
  • TabButtons can be aligned inside TabPanel
  • TabButtons can fit TabPanel by width, height or both
  • TabPanel can set common width or height for TabButtons

Implementation

I'm not going to explain all the code, but I'll stop in most interesting parts:

Creating your own pseudo-class

Each TabButton should have a status selected in order to display the button as selected and not to perform a click action on it.
public class TabButton extends ButtonBase, Labeled {
    
    override var skin = SkinAdapter {
        rootRegion:ButtonSkin{}
    }

    public var selected:Boolean = false on replace {
        impl_pseudoClassStateChanged("selected");
    }

    override function impl_getPseudoClassState():String[] {
        return [
            if (selected) "selected" else null,
            super.impl_getPseudoClassState()
        ]
    }
}
This is just a piece of the TabButton class. As you can see, I use two functions impl_pseudoClassStateChanged and impl_getPseudoClassState that will help me to organize my pseudo-class &quote;selected&quote; for this control.
Now let's take a look at the CSS file:
.tab-button {
    -fx-padding: 3 10 2 10;
    -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
    -fx-background-radius: 10 10 0 0;
    -fx-background-insets: 0 0 -1 0, 0, 1, 2;
    -fx-border-radius: 10 10 0 0;
    -fx-border-color: -fx-outer-border, -fx-inner-border;
    -fx-border-style: solid;
    -fx-text-fill: -fx-text-base-color;
    -fx-vpos: CENTER;
    -fx-graphic-vpos: CENTER;
}

.tab-button:hover {
    -fx-color: -fx-hover-base;
}

.tab-button:selected {
    -fx-color: -fx-pressed-base;
}
Please pay attention, that now I can use keyword selected as a name of the new pseudo-class for my control. Also I can use standard pseudo-classes of Button and Labeled controls cause I invoke a super.impl_getPseudoClassState() highlighted on line 14.
Now look at line 4, in order not to write my own Skin class, for this control, I'm using an existing one.

Source

To download a full source code press here

Have a nice code :)