While Jasper is on vacation I thought I’d take a moment and outline the multi-level architectural approach we’ve taken with skinning Controls, and give some rough outline as to when the different levels will be fully supported in JavaFX.
There are basically three different levels of support for skinning in JavaFX.
At the most basic level, which is also the most powerful and flexible, you have the ability to completely replace the Skin for any Control. The Skin is responsible for the entire visual appearance and, ultimately, the visual interaction for a Control. There are not explicit “ButtonSkin” or “RadioButtonSkin” or “ListViewSkin” types that must be extended. There are simply Skins. So for example, you could completely replace the Skin for a Button using your own implementation that, for instance, simply used an image for the button.
While it is the most powerful mechanism for skinning a Control, it is also the most tedious as there are many details to pay attention to, such as overriding the functions to provide meaningful preferred size information for the Control with this Skin, wiring everything up to the model information in the Control, and handling all the mouse input and preferably forwarding the input on to a Behavior (which you also must providing in JavaFX 1.2 since the skin and behavior implementations for our default look, Caspian, have not been made public in this release).
The next level up restricts a bit what you can do, but also makes it a lot easier to style. This is to use the JavaFX Production Suite to produce skins for your Controls. As of the time of this writing, this support is still in prototype form (Martin Brehovsky demo’d this at JavaOne and it is definitely something I’d like to see released this year, but we’ll see how the schedules work out). The basic idea is pretty simple: the tool would provide its own basic Skin base classes. Vector or Image artwork produced by Illustrator or Photoshop and exported via the Production Suite could then get wired up on top of these Skin base classes to form a complete Skin for a Control.
There are several great things about this approach. First, visual designers can create nice graphics and use these directly. We lowly developer types don’t have to worry about taking a designer’s design and replicating it in code (which is good, ’cause mostly we’re lousy at it). Also, it opens up the opportunity to allow your company to contract out to designers and have them produce skins. It also allows designers to create suites of prebuilt custom skins fairly easily and sell these “themes” for the basic controls. Creating custom skins for custom controls is likewise also not terribly difficult for a designer.
However, as mentioned above, this isn’t released yet, so for the moment you would have to manually wire up the output of an FXD file to the skins. This is actually not very difficult, and could be achieved in a matter of an hour or so by somebody skilled at writing skins.
The third approach is to use CSS for styling the Controls. This is by far the most accessible method and, hopefully, will accommodate the 60-80% use case of simply wanting to style the prebuilt skins. In the 1.2 release, styling Controls with CSS is only just supported. In the next release we’ll both document and declare “stable” the attributes which can be styled from CSS. We’re pretty excited about the range of options we’re going to support, because our hope is that we’ll be able to address the vast majority of uses with just simple CSS.
And remember in JavaFX, CSS attributes can be specified in stylesheets, or directly on Nodes in the scenegraph by specifying the “style” property, much like in HTML. This makes it really easy to style a specific Control (which is a Node in the scenegraph) directly, or indirectly in a stylesheet.
In CSS you can easily specify attributes for a Control when it is in different states. For example, you can specify the a Button should have a base color of “red”, and a Button which has the mouse over it (hover) is “blue”. This is done by specifying the base and/or accent Color in CSS like this:
Button { style: "base: red" text: "Red Button" }
There are a whole host of additional attributes which we’d like to expose in the next release, such as cornerRadius, padding, margins, shadowFill, textFill, and so forth (actually, I think we have committed to textFill already, I’ll let Jasper verify). One idea we’ve been kicking around is that of having a TexturePaint where, from CSS, you could specify an image file and also a set of insets and then we’d do the 9-square resizing technique for you. This would make it trivial then to build skins from CSS based on either Colors, Gradients, or Images. If we then expose some information for animations so you could control simple animation transitions from CSS too, then CSS becomes a very compelling proposition.
I hope this outline helps understand a bit better where we are now, and where we’re headed in the next release. Today, the best supported option is to create completely custom Skins. The second best option is to do some basic styling from CSS. In a few months time we plan to release complete CSS customizability which will give probably 80% use case coverage. We should also have basic support in the Production Suite to produce skins for Controls (though there may be some hand coding involved, we’ll try to make it pretty trivial).
Thanks for clarifying, it’s even better then what I was hoping for.
The CSS animated 9-patch styling would be something most designers would use, quite similar to what they use in the web world.
Support for skinning the individual control states in the ProductionSuite would be a big plus, even if we’d have to assemble the pieces manually. You’d have to do it only once for every component, and the IDE could probably help with this task like Netbeans did with generating UIStubs from FXDs in the 1.1 release.
Keep the good stuff comming!
Jo, what we have shown at J1 this year was this:
Button { skin: FXDSkin { url: “{__DIR__}myskin.fxz” }}. The fxz file contained graphics for all states supported by the skin (disabled, enabled, armed and hover in our case). It worked reasonably well, although I believe we need to add more support to allow tweaking the state transitions (we used simple crossfade).
Also one idea is the designer would be able to mark graphics as a button directly in AI, thus the exported FXD would already contain the skinned button.
Hi,
thanks so much for the interesting article. I like to use the style attribute to change the CSS, but I cannot find the caspian css anywhere.
Where to I find a description / the caspian style sheet with an overview of the tags that are available, i.e. where do I find out about the tags such as “base: red” and “border-width:0” ?
Thanks a lot in advance
Frank
Thanks for the info! Helped me a lot.
hendrik
All fair points apart from the bit about XML. The widespread use of XML alongside Java is precisely because Java is so bad for programming in a declarative style. JavaFX fixes that. Why would you use an irritatingly verbose document format to write programs in lieu of a purpose-built declarative programming language? His trivial example looks fine but doesn’t contain any code to perform actions, only declarative layout code. How would they propose to encode that in XML? XML makes a bad programming language as someone who is worked on a moderately compliated Ant build will testify.