CSS on javaFX
richard.bair at oracle.com
Mon Apr 16 07:36:49 PDT 2012
I think some of what you are asking for we simply cannot provide without making our Skin implementations public API. Let me explain.
One of the key design principles for the JavaFX UI controls was a clear and strong separation between the View and the Model of the control. There is a design tension there where, for convenience, people want more visual state available on the Control class, but for flexibility, it is a bad choice to do so. For example, the Swing JButton specified different icons for different states that the button might be in, as public API on the JButton class. Carried to its logical extreme you would have literally hundreds of such APIs.
But even more so, a single control might have radically different views. One use case we used to talk about was a slider. In the normal case there is a track and a knob and you slide the knob within the track. However what if I were doing an application for a Chiropractor, and I wanted the slider to be curved in the shape of the back and the knob to be a vertebra? Or perhaps I will want my slider to be represented as a spinning knob as in A/V equipment, where there isn't a track at all?
We have also noted that a ToggleButton and RadioButton are both actually the same control, but with different skins. The TabPane and the "dot pagination" control (like you might see on an iPhone home screen) are actually the same control, just with different visual representation.
So we wanted to make sure we kept the View/Model separation as strict as possible. In some places we fudged it, such as the "font" on a Label. Some things like the "graphic text gap", "content display" and so forth also made compromises. Whenever such state is added to the control, it restricts the range of choices available to a Skin provider. All skin implementations of a Label (that are meant for a wider audience than just yourself!) have to deal with all the various content display settings and alignment and so forth. In the most strict sense those variables shouldn't have been on our Labeled, but should have been part of the skin and set via CSS (or some other mechanism for styling the skins). So we did make compromises.
So when you are styling things from CSS, sometimes you are styling the control, and sometimes the Skin. And of course from CSS you can also specify the skin!
Our default skin implementations are all designed to be styled from CSS. So here are two options for being able to set the style on a skin from Java code. One is type-safe, one is not.
Option A: Make the Skin APIs public and specify the skin manually
In this option, we would move our default skin implementations to javafx.scene.control.skin.caspian, for example. When you wanted to change the background fills of a button, you could do something like this:
Button button = new Button("Hi");
ButtonSkin skin = new ButtonSkin(button);
This approach you can do today, except that ButtonSkin isn't public API so it can (and most likely will) change in incompatible ways as time goes on and the ability to set backgrounds / borders / etc is functionality in Region that doesn't have public API yet. But from an architectural perspective this is doable today. This is the only real way to have what you ultimately want -- the type-safe code friendly way to style things. Now, some designer can come along and still override your settings from CSS, so later on if you assume that this skin is actually set up the way you think it is and somebody has styled it differently from CSS it will break, but that's actually intended behavior -- you the developer might be off working on some other project and some poor designer has to spruce up the UI. So best practice would be not to make assumptions on the view (even what skin is being used!). So if you follow this pattern the best practice would be to set it up and then afterwards make no assumption as to what it actually looks like. But that's up to you, if you make such assumptions, then somebody cannot come later and style it without potentially breaking the app. That's your choice.
Option B: Modify CSS Styles from Java
Button button = new Button("Hi");
Style style = button.getStyle();
Or something like that. Such that you can hang any known CSS variables on the style for a single node, and then have some string based implementation for styles that we don't know about (since our CSS allows you to create new "variables" in the CSS just by declaring them). So for example:
Or whatnot. This API has not yet been designed, I'm just making this up as I go. But you get the idea -- there would be some kind of API for dealing with common things in a type-safe way (that also allows us to avoid having to do conversions and such) but also some fallback onto essentially a string-based CSS syntax that we can parse and deal with for those things that we cannot anticipate and provide predefined API for.
I'm not sure which of these alternatives is something that you prefer, but I'm guessing it is more Option A. The problem with Option A is that it introduces a *lot* of new public API and so we need to be careful about it and it takes time to vet it. Once released, we live with it forever. Of course anybody could take our existing skins and spruce them up, put them in another package, license as GPL (with classpath extension) and publish their own set of Skins which allow you to set everything via a public API, you don't have to wait for us to do it and include it in the platform.
On Apr 15, 2012, at 10:03 AM, Pedro Duque Vieira wrote:
> I should have elaborated more on that sentence.
> Yes CSS is not a "programming language" nor is it intended to be, it tries
> to be a language to describe the visual part of interfaces separating the
> structure of a document (HTML) from its appearance (the CSS part). Problem
> is that for more elaborated interfaces, the looks start to have a logic,
> which CSS fails to provide. That's when HTML web developers start to use
> I think CSS is a reasonable language to describe visual interfaces, but I
> think we can do much better. We have to remind ourselves of its origins, it
> appeared in the context of HTML to solve problems caused by its model, it
> didn't come up as a language on its own.
> One thing we can not naturally do today, that we would be able to do if we
> had an object model of the css properties is animating those properties. We
> will be able to do it eventually when CSS3 animations come to JavaFX, but
> on the meantime we can't, at least not on a natural, straight forward way.
> In conclusion I think CSS should not THE way to describe visual interfaces
> on JavaFX, rather I think it should be one more way of doing it, that is,
> we should also be able to accomplish the same by using Java or some other
> language without having to parse CSS strings.
> On Sun, Apr 15, 2012 at 2:15 PM, Stephen Winnall <steve at winnall.ch> wrote:
>> On 14 Apr 2012, at 02:20, Pedro Duque Vieira wrote:
>> CSS isn't even a language it lacks lots of common language constructs.
>> That depends on what you understand as a "language".
>> I would agree that CSS is not a programming language, but it is not
>> intended to be. Nor is XML for that matter. Both CSS and XML are data
>> description languages and - as such - capture the state of the described
>> data at the point where the CSS or XML is loaded (by
>> Scene.getStylesheets.add() or FXMLLoader.load() etc).
>> The provision of "common language constructs" is what scripting languages
>> provide. We have enough of those already without adding scripting
>> constructs to CSS and XML. In the context of JavaFX, it may make more sense
>> to use Java itself.
>> I agree that Zonski's proposal is interesting. In the XML world there is
>> data binding, which allows you to create mapping from XML schemas to Java
>> Beans. Something similar for CSS would be very useful.
> Pedro Duque Vieira
More information about the openjfx-dev