Update: This post has been edited to show you how to use a gradient as the background of a ScrollView.
The new and improved support for CSS in JavaFX 1.3 includes a .scene style class which is a convenient place to initialize all sorts of application settings such as fonts and colors. Therefore, you would also think that the .scene class is the place to specify the background color for the scene, right? If you do, you're in good company. And just like the rest of us, you would be wrong.
It turns out that the only place to set the fill property of the Scene is in your JavaFX code. But there are some tricks you can use if you want the ability to control the background of your scene from a CSS file.
ScrollViews and Rectangles
The simplest way to create a background that can be styled is to use a ScrollView as the background node in your scene. The advantage of using a ScrollView is that if the window is resized to be smaller than the content, scrollbars will automatically appear. This is a handy feature to have in a main window. The following code demonstrates the technique.
Stage { var sceneRef: Scene; title: "ScrollView Background" scene: sceneRef = Scene { width: 400 height: 300 stylesheets: "{__DIR__}scrollViewBackground.css" content: [ ScrollView { width: bind sceneRef.width height: bind sceneRef.height node: // Rest of your content goes here } ] } }
Here I simply placed the ScrollView first in the Scene's content and bound its width and height to the size of the Scene. Instant background.
If you then create a style sheet that sets the -fx-background property on the .scene selector, the ScrollView will pick it up automatically.
.scene { -fx-background: skyblue; }
The results are pictured below.
Using a gradient as a background for the ScrollView is also possible, although it requires a little more work in your style sheet. You need to add two new styles that redefine the default background of the ScrollView so that it incorporates a gradient rather than a solid color.
.scene { -fx-background: skyblue; -my-scene-background: linear (0%, 0%) to (0%, 100%) stops (0%, derive(-fx-background, 25%)) (100%, derive(-fx-background, -35%)); } #sceneBackground { -fx-background-color: -fx-box-border, -my-scene-background; } #sceneBackground:focused { -fx-background-color: -fx-focus-color, -fx-box-border, -my-scene-background; }
Note that I have used an ID selector for these new styles so that it overrides only the -fx-background-color of the single ScrollView that I have designated as my scene's background. I was careful to preserve the -fx-box-border and -fx-focus-color settings of the default ScrollView styles (from caspian.css) so that, other than the gradient, the background will look exactly like a standard ScrollView.
I have also defined my background gradient in the .scene section of the style sheet so that it can be reused in both of the #sceneBackground styles. Declaring CSS "variables" like this is a feature of the JavaFX CSS support.
Once these additions to the application's style sheet have been made, you just need to add the proper ID to the ScrollView being used as the scene's background and you are done. This is what the JavaFX code and our window look like now.
Stage { var sceneRef: Scene; title: "ScrollView Background" scene: sceneRef = Scene { width: 400 height: 300 stylesheets: "{__DIR__}scrollViewBackground.css" content: [ ScrollView { id: "sceneBackground" width: bind sceneRef.width height: bind sceneRef.height node: // Your content goes here... } ] } }
Rectangle Backgrounds
Another lightweight option for creating a styled background is to use a simple Rectangle.
Stage { var sceneRef: Scene; title: "Rectangle Background" scene: sceneRef = Scene { width: 400 height: 300 stylesheets: "{__DIR__}rectangleBackground.css" content: [ Rectangle { styleClass: "background" width: bind sceneRef.width height: bind sceneRef.height } // Rest of your content goes here ] } }
This is similar to the ScrollView version except that a Rectangle is inserted as the first node in the Scene and its width and height are bound to the Scene's size. Note that I assigned a styleClass of "background" to the Rectangle. The style sheet now looks like this:
.scene { -my-scene-background: linear (0%, 0%) to (0%, 100%) stops (0%, derive(skyblue, 25%)) (100%, derive(skyblue,-25%)); } .background { -fx-fill: -my-scene-background; }
In the style sheet above, I've assigned a gradient to the -my-scene-background property in the .scene section and then used it to set the Rectangle's fill (-fx-fill) in the .background section which was the styleClass for the background Rectangle. Of course, I could have just assigned the gradient to the -fx-fill property directly, but as was pointed out above, doing it this way makes that gradient available for use by other styles in the style sheet.
Regions: Imagine the Possibilities
For the more adventurous, you can also use a Region for your background. This gives you the ability to have background colors, borders, and even images!
Warning! Non-public APIs in use beyond this point. Proceed at your own risk! (It's really not that risky)
All of the core controls in JavaFX 1.3 are made of Regions. Because of this, Regions are heavily tied into the new CSS support and have a lot more styling options than any other type of node. You can assign background colors and images, style borders, and even change the shape of the Region all from a style sheet.
But you don't have to write a control to make use of a Region. Regions are a subclass of the public Stack container and therefore can be used anywhere in the scene graph. Which means that a Region makes a great background for a Scene.
The top image shows a window with a gray gradient background that is typical of a default Caspian color scheme. The bottom image shows a combination of a background color and a background image that is positioned along the bottom of the window and repeated in the x-direction to fill the window with flowers in a celebration of Spring (with apologies to all of our friends in the Southern Hemisphere).
The code and the stylesheet are shown below in their entirety.
Stage { var sceneRef: Scene; var backgroundRef: Node; title: "Region Background" scene: sceneRef = Scene { width: 600 height: 300 stylesheets: ["{__DIR__}jfxtras.css", "{__DIR__}sceneStyles.css"] content: [ backgroundRef = Region { styleClass: "background1" width: bind sceneRef.width height: bind sceneRef.height } VBox { var fillWidth = LayoutInfo { hfill: true } spacing: 10 padding: Insets { top: 10, right: 10, bottom: 10, left: 10 } content: [ XEtchedButton { text: "Business As Usual" layoutInfo: fillWidth action: function () { backgroundRef.styleClass = "background1" } } XEtchedButton { text: "Yay, It's Spring!" layoutInfo: fillWidth action: function () { backgroundRef.styleClass = "background2" } } ] } ] } }
.scene { -fx-font: 24pt "Amble Condensed" }
.background1 { -fx-color: lightgray; -fx-background-color: -fx-body-color; -fx-background-image: null; }
.background2 { -fx-background-color: #81E2F7; -fx-background-image: "flowersbluesky.png"; -fx-background-position: left bottom; -fx-background-repeat: repeat-x; }