JavaFX CSS Tutorial
This is a JavaFX CSS tutorial. In this article we will discuss how you can define the style for a Node. You will also learn, how you can add and use StyleSheets (CSS) in JavaFX.
JavaFX allows you to define the look (or the style) of JavaFX applications using CSS. You can define UI elements using JavaFX class libraries or FXML and use CSS to define their look.
The following table shows an overview of the whole tutorial:
Table Of Contents
The following examples uses Java SE 8.
1. Introduction
CSS provides the syntax to write rules to set the visual properties. A CSS rule is also known as a style. A collection of CSS rules is known as a style sheet. Styles, skins, and themes are three related, and highly confused, concepts.
A rule consists of a selector and a set of property-value pairs. A selector is a string that identifies the UI elements to which the rules will be applied. A property-value pair consists of a property name and its corresponding value separated by a colon (:). Two property-value pairs are separated by a semicolon (;). The set of property-value pairs is enclosed within curly braces ({ }) preceded by the selector. An example of a rule in CSS is as follows:
.button { -fx-background-color: red; -fx-text-fill: white; }
In the above example, .button
is a selector, which specifies that the rule will apply to all buttons. -fx-background-color
and -fx-text-fill
are property names with their values set to red and white, respectively. When the above rule is applied, all buttons will have the red background color and white text color.
Styles provide a mechanism to separate the presentation and content of UI elements. They also facilitate grouping of visual properties and their values, so they can be shared by multiple UI elements. JavaFX lets you create styles using JavaFX CSS.
Skins are collections of application-specific styles, which define the appearance of an application. Skinning is the process of changing the appearance of an application (or the skin) on the fly. JavaFX does not provide a specific mechanism for skinning.
Themes are visual characteristics of an operating system that are reflected in the appearance of UI elements of all applications. To contrast skins and themes, skins are application specific, whereas themes are operating system specific. It is typical to base skins on themes. That is, when the current theme is changed, you would change the skin of an application to match the theme. JavaFX has no direct support for themes.
2. Naming Conventions in JavaFX CSS
JavaFX uses slightly different naming conventions for the CSS style classes and properties. CSS style class names are based on the simple names of the JavaFX classes representing the node in a Scene Graph. All style class names are lowercased. If the class name for the JavaFX node consists of multiple words, for example, TextField, a hyphen is inserted between two words to get the style class name. For example, the style classes for the TextField
and CheckBox classes are text-field
and check-box
, respectively.
Property names in JavaFX styles start with -fx-
. For example, the property name font-size in normal CSS styles becomes -fx-font-size
in JavaFX CSS style. JavaFX uses a convention to map the style property names to the instance variables. It takes an instance variable; it inserts a hyphen between two words; if the instance variable consists of multiple words, it converts the name to the lowercase and prefixes it with -fx-
.
For example, for an instance variable named textAlignment
, the style property name would be -fx-text-alignment
.
.label { -fx-background-color: red; -fx-text-fill: white; -fx-text-alignment: center; }
4. Adding Inline Styles
4.1 The Java Class
FxCSSExample1.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.VBox; public class FxCSSExample1 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple Inline Style Example"); Label message = new Label(); // Set the Style of the Labels label.setStyle ( "-fx-font-family: \"arial\";" + "-fx-font-size: 16px;" + "-fx-font-style: normal;" + "-fx-font-weight: normal;" ); message.setStyle ( "-fx-font-family: \"arial\";" + "-fx-font-size: 20px;" + "-fx-font-style: italic;" + "-fx-font-weight: bolder;" ); // Create The Button Button button = new Button("OK"); // Set the Style of the Button button.setStyle ( "-fx-font-size: 24px;" + "-fx-font-weight: bold;" + "-fx-background-color: lightgreen;" + "-fx-border-style: solid inside;" + "-fx-border-width: 2;" + "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: blue;" ); // Add an EventHandler to the OK-Button button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the Button to the VBox root.getChildren().addAll(label,button,message); // Create the Scene Scene scene = new Scene(root,350,200); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("An Inline Style Example"); // Display the Stage stage.show(); } }
CSS styles for a Node
in a Scene Graph may come from style sheets or an inline style. In the above example, you have seen how to specify an inline style for a Node
.
The Node
class has a style property that is of StringProperty type. The style property holds the inline style for a node. You can use the setStyle(String inlineStyle)
and getStyle()
methods to set and get the inline style of a node.
There is a difference between a style in a style sheet and an inline style. A style in a style sheet consists of a selector and a set of property-value pairs, and it may affect zero or more nodes in a Scene Graph. The number of nodes affected by a style in a style sheet depends on the number of nodes that match the selector of the style. An inline style does not contain a selector. It consists of only set property-value pairs. An inline style affects the Node
on which it is set.
The following example sets the style for a Label
:
// Set the Style of the Labels label.setStyle ( "-fx-font-family: \"arial\";" + "-fx-font-size: 16px;" + "-fx-font-style: normal;" + "-fx-font-weight: normal;" );
The following snippet of code uses an inline style for a Button
to display its text in bold, sets the background color to lightgreen and the border color to blue, etc.:
// Set the Style of the Button button.setStyle ( "-fx-font-size: 24px;" + "-fx-font-weight: bold;" + "-fx-background-color: lightgreen;" + "-fx-border-style: solid inside;" + "-fx-border-width: 2;" + "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: blue;" );
4.2 The GUI
The following image shows the result of the above example:
5. Adding Style Sheets
5.1 The Java Class
FxCSSExample2.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.VBox; public class FxCSSExample2 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple Stylesheet Example"); Label message = new Label(); // Create The Button Button button = new Button("OK"); // Add an EventHandler to the OK-Button button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the Button to the VBox root.getChildren().addAll(label,button,message); // Create the Scene Scene scene = new Scene(root,350,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample2.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A simple StyleSheet Example"); // Display the Stage stage.show(); } }
5.2 The Style Sheet
fxcssexample1.css
/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ .button { -fx-font-size: 24px; -fx-font-weight: bold; -fx-background-color: lightgreen; -fx-border-style: solid inside; -fx-border-width: 2; -fx-border-insets: 5; -fx-border-radius: 5; -fx-border-color: blue; } .label { -fx-font-family: "arial"; -fx-font-size: 16px; -fx-font-style: normal; -fx-font-weight: bolder; }
You can add multiple style sheets to a JavaFX application. Style sheets are added to a Scene
or parents. Scene and Parent classes maintain an observable list of string URLs linking to style sheets. Use the getStylesheets()
method in the Scene
and Parent
classes to get the reference of the observable list and add additional URLs to the list. The following code would accomplish this:
// Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample2.css").toExternalForm());
5.3 The GUI
The result of this example is the same like in the previous one. But in this example, all styles are defined in an external style sheet.
6. Priorities of Styles for a Node
6.1 The Java Class
FxCSSExample3.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample3 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a Styles Priorities Example"); Label message = new Label(); // Set the Style of the Label message.setStyle ( "-fx-font-family: \"arial\";" + "-fx-font-size: 16px;" + "-fx-font-style: italic;" ); // Create The Buttons Button ok = new Button("OK"); Button cancel = new Button("Cancel"); // Set the Style of the Button cancel.setStyle ( "-fx-background-color: red;" + "-fx-border-style: solid inside;" + "-fx-border-width: 2;" + "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: blue;" ); // Add an EventHandler to the OK-Button ok.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(ok,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,350,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample3.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A Style Priorities Example"); // Display the Stage stage.show(); } }
6.2 The Style Sheet
fxcssexample3.css
.button { -fx-font-size: 24px; -fx-font-weight: bold; } .label { -fx-font-family: "arial"; -fx-font-size: 20px; -fx-font-weight: bolder; }
In a JavaFX application, it is possible, and very common, for the visual properties of nodes to come from multiple sources. For example, the font size of a button can be set by the JavaFX runtime, style sheets can be added to the Parent
and the Scene
of the Button, an inline style can be set for the Button
, and programmatically can be added using the setFont(Font f)
method. If the value for the font size of a button is available from multiple sources, JavaFX uses a rule to decide the source whose value is to be used.
In the above example, the font style definitions for the cancel button comes from the stylesheet:
.button { -fx-font-size: 24px; -fx-font-weight: bold; }
On the other hand, the properties for the border and the background color are defined in the java source code:
cancel.setStyle ( "-fx-background-color: red;" + "-fx-border-style: solid inside;" + "-fx-border-width: 2;" + "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: blue;" );
The JavaFX runtime uses the following priority rules to set the visual properties of a node. The source with a higher priority that has a value for a property is used:
- Inline style (the highest priority)
- Parent style sheets
- Scene style sheets
- Values set in the code using JavaFX API
- User agent style sheets (the lowest priority)
The style sheet added to the parent of a node is given higher priority than the style sheets added to the Scene
. This enables developers to have custom styles for different branches of the Scene Graph. For example, you can use two style sheets that set properties of buttons differently: one for buttons in the Scene
and one for buttons in any HBox. Buttons
in a HBox
will use styles from its Parent
, whereas all other buttons will use styles from the Scene
.
The values set using the JavaFX API, for example, the setFont()
method, have the second lowest priority.
The lowest priority is given to style sheets used by the user agent. What is a user agent? A user agent, in general, is a program that interprets a document and applies style sheets to the document to format, print, or read. For example, a web browser is a user agent that applies default formatting to HTML documents. In our case, the user agent is the JavaFX runtime, which uses the caspian.css style sheet for providing the default look for all UI nodes.
6.3 The GUI
The following GUI show the result of the above example:
7. Inheriting CSS Properties
7.1 The Java Class
FxCSSExample4.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample4 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple Inherit Example"); Label message = new Label(); // Set the Style of the Label message.setStyle("-fx-font-family: \"arial\";-fx-font-size: 16px;-fx-font-style: italic;"); // Create The Buttons Button ok = new Button("OK"); Button cancel = new Button("Cancel"); // Set the Style of the Button ok.setStyle ( "-fx-border-color: red;" + "-fx-border-width: inherit;" ); // Add an EventHandler to the OK-Button ok.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(ok,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Set the Style for the Root Element root.setStyle ( "-fx-cursor: hand;" + "-fx-border-color: blue;" + "-fx-border-width: 5px;" ); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample4.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("An Inheritance Example"); // Display the Stage stage.show(); } }
7.2 The Style Sheet
fxcssexample4.css
.button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; -fx-border-width: 10; } .label { -fx-font-family: "arial"; -fx-font-size: 20px; -fx-font-weight: bolder; }
JavaFX offers two types of inheritance for CSS properties:
- Inheritance of CSS property types
- Inheritance of CSS property values
In the first type of inheritance, all CSS properties declared in a JavaFX class are inherited by all its subclasses. For example, the Node
class declares a cursor property and its corresponding CSS property is -fx-cursor
. Because the Node
class is the superclass of all JavaFX nodes, the -fx-cursor
CSS property is available for all node types.
// Set the Style for the Root Element root.setStyle ( "-fx-cursor: hand;" + "-fx-border-color: blue;" + "-fx-border-width: 5px;" );
In the second type of inheritance, a CSS property for a node may inherit its value from its parent. The parent of a node is the container of the Node
in the Scene Graph, not its JavaFX superclass. The values of some properties of a Node
are inherited from its parent by default, and for some, the node needs to specify explicitly that it wants to inherit the values of the properties from its parent. In our example the CSS properties -fx-border-color
and -fx-border-width
will be inherited to all children.
You can specify inherit as the value for a CSS property of a Node
if you want the value to be inherited from its parent. If a Node
inherits a CSS property from its parent by default, you do not need to do anything, that is, you do not even need to specify the property value as inherit. If you want to override the inherited value, you need to specify the value explicitly (overriding the parent’s value).
.button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; -fx-border-width: 10; }
In this case, the property -fx-border-width
will be overrided.
7.3 The GUI
The following image shows the effect of the inheritance:
8. Understanding Style Selectors
Each style in a style sheet has an associated selector that identifies the nodes in the Scene Graph to which the associated JavaFX CSS property values are applied. JavaFX CSS supports several types of selectors: class selectors, pseudo-class selectors, ID selectors, among others.
8.1 Using Class Selectors
8.1.1 The Java Class
FxCSSExample5.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample5 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple Class Selector Example"); Label message = new Label(); // Create The Buttons Button ok = new Button("OK"); Button cancel = new Button("Cancel"); // Add an EventHandler to the OK-Button ok.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(ok,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Set the StyleClass for the Root Element root.getStyleClass().add("hbox"); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample5.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A Class Selector Example"); // Display the Stage stage.show(); } }
8.1.2 The Style Sheet
fxcssexample5.css
.hbox { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; } .button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; } .label { -fx-font-family: "arial"; -fx-font-size: 14px; -fx-font-weight: bolder; }
The Node
class defines a styleClass
variable that is an ObservableList. Its purpose is to maintain a list of JavaFX style class names for a Node
. Note that the JavaFX class name and the style class name of a node are two different things. A JavaFX class name of a node is a Java class name, for example VBox, which is used to create objects of that class. A style class name of a Node
is a string name that is used in CSS styling.
You can assign multiple CSS class names to a Node
. The following snippet of code assigns the style class “hbox” to an HBox
:
// Set the StyleClass for the Root Element root.getStyleClass().add("hbox");
A style class selector applies the associated style to all nodes, which have the same style class name as the name of the selector. A style class selector starts with a period followed by the style class name. Note that the style class names of nodes do not start with a period.
8.1.3 The GUI
The following image shows an example using the class name as selector:
8.2 Class Selector for the root Node
8.2.1 The Java Class
FxCSSExample6.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample6 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple Root Selector Example"); Label message = new Label(); // Create The Buttons Button ok = new Button("OK"); Button cancel = new Button("Cancel"); // Add an EventHandler to the OK-Button ok.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(ok,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample6.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A Root Selector Example"); // Display the Stage stage.show(); } }
8.2.2 The Style Sheet
fxcssexample6.css
.root { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; } .button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; } .label { -fx-font-family: "arial"; -fx-font-size: 14px; -fx-font-weight: bolder; }
The root node of a Scene
is assigned a style class named “root”. You can use the root style class selector for CSS properties that are inherited by other nodes. The root node is the parent of all nodes in a Scene Graph. Storing CSS properties in the root node is preferred because they can be looked up from any node in the Scene Graph.
The style of the root node comes from the style sheet:
.root { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; }
8.2.3 The GUI
The GUI of an example using the root selector:
8.3 Using ID Selectors
8.3.1 The Java Class
FxCSSExample7.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample7 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a simple ID Selector Example"); Label message = new Label(); // Create The Buttons Button ok = new Button("OK"); Button cancel = new Button("Cancel"); cancel.setId("cancelButton"); // Add an EventHandler to the OK-Button ok.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the OK Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(ok,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample7.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("An ID Selector Example"); // Display the Stage stage.show(); } }
8.3.2 The Style Sheet
fxcssexample7.css
.root { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; } .button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; } #cancelButton { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; -fx-background-color: lightgreen; -fx-text-fill: red; } .label { -fx-font-family: "arial"; -fx-font-size: 14px; -fx-font-weight: bolder; }
The Node
class has an id
property of the StringProperty
type, which can be used to assign a unique id to each node in a Scene Graph. Maintaining the uniqueness of an id in a Scene Graph is the responsibility of the developer. It is not an error to set a duplicate id for a Node
. You do not use the id property of a node directly in your code, except when you are setting it. It is mainly used for styling nodes using ID selectors. An ID selector in a style sheet is preceded by the pound (#) sign. Note that the ID value set for a node does not include the #
sign.
The following snippet of code sets the id property of the cancel Button
to “cancelButton”:
// Create The Buttons Button cancel = new Button("Cancel"); cancel.setId("cancelButton");
8.3.3 The GUI
The following GUI shows the effect of using an ID selector:
8.4 Combining ID and Class Selectors
A selector can use the combination of a style class and an ID. In this case, the selector matches all nodes with the specified style class and ID. Consider the following style:
#cancelButton.button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; -fx-background-color: lightgreen; -fx-text-fill: red; }
The selector #cancelButton.button
matches all nodes with a cancelButton
ID and a button style class. You can also reverse the order:
.button#cancelButton { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-radius: 5; -fx-background-color: lightgreen; -fx-text-fill: red; }
Now it matches all nodes with a button style class and a cancelButton
ID.
9. Specifying Background Colors
9.1 The Java Class
FxCSSExample8.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample8 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a Background Color Example"); Label message = new Label(); // Create The Buttons Button yes = new Button("Yes"); yes.getStyleClass().add("button-style-yes"); Button no = new Button("No"); no.getStyleClass().add("button-style-no"); Button cancel = new Button("Cancel"); cancel.getStyleClass().add("button-style-cancel"); // Add an EventHandler to the YES-Button yes.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Yes Button"); } }); // Add an EventHandler to the NO-Button no.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the No Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(yes,no,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample8.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A Background Color Example"); // Display the Stage stage.show(); } }
9.2 The Style Sheet
fxcssexample8.css
.root { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; } .button-style-yes { -fx-background-color: green; -fx-background-insets: 5; -fx-background-radius: 10; } .button-style-no { -fx-background-color: red; -fx-background-insets: 0; -fx-background-radius: 0; } .button-style-cancel { -fx-background-color: yellow; -fx-background-insets: 5 10 15 20; -fx-background-radius: 0 20 10 10; } .button { -fx-font-size: 20px; -fx-border-insets: 5; -fx-border-width: 2; -fx-border-color: blue; -fx-border-radius: 5; } .label { -fx-font-family: "arial"; -fx-font-size: 14px; -fx-font-weight: bolder; }
A Node
can have multiple background fills, which are specified using three properties:
- -fx-background-color
- -fx-background-radius
- -fx-background-insets
The -fx-background-color
property is a list of comma-separated color values. The number of colors in the list determines the number of rectangles that will be painted. You need to specify the radius values for four corners and insets for four sides, for each rectangle, using the other two properties. The number of color values must match the number of radius values and inset values.
The -fx-background-radius
property is a list of a comma-separated set of four radius values for the rectangles to be filled. A set of radius values in the list may specify only one value, for example, 10, or four values separated by whitespaces, for example, 10 5 15 20. The radius values are specified for the top-left, top-right, bottom-right, and bottom-left corners in order. If only one radius value is specified, the same radius value is used for all corners.
The -fx-background-insets
property is a list of a comma-separated set of four inset values for the rectangles to be filled. A set of inset values in the list may specify only one value, for example, 10, or four values separated by whitespaces, for example, 10 5 15 20. The inset values are specified for the top, right, bottom, and left sides in order. If only one inset value is specified, the same inset value is used for all sides.
In our example, we have defined three different style for the buttons in the style sheet:
.button-style-yes { -fx-background-color: green; -fx-background-insets: 5; -fx-background-radius: 10; } .button-style-no { -fx-background-color: red; -fx-background-insets: 0; -fx-background-radius: 0; } .button-style-cancel { -fx-background-color: yellow; -fx-background-insets: 5 10 15 20; -fx-background-radius: 0 20 10 10; }
In the Java class, the style will be supplied to the buttons:
// Create The Buttons Button yes = new Button("Yes"); yes.getStyleClass().add("button-style-yes"); Button no = new Button("No"); no.getStyleClass().add("button-style-no"); Button cancel = new Button("Cancel"); cancel.getStyleClass().add("button-style-cancel");
9.3 The GUI
The following GUI shows an example with three buttons, where each button has an own background style:
10. Specifying Borders
10.1 The Java Class
FxCSSExample9.java
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; public class FxCSSExample9 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Create the Labels Label label = new Label("This is a Border Example"); Label message = new Label(); // Create The Buttons Button yes = new Button("Yes"); yes.getStyleClass().add("button-style-yes"); Button no = new Button("No"); no.getStyleClass().add("button-style-no"); Button cancel = new Button("Cancel"); cancel.getStyleClass().add("button-style-cancel"); // Add an EventHandler to the YES-Button yes.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Yes Button"); } }); // Add an EventHandler to the NO-Button no.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the No Button"); } }); // Add an EventHandler to the OK-Button cancel.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { message.setText("You have pressed the Cancel Button"); } }); // Create the HBox HBox hbox = new HBox(); // Set the vertical spacing between children to 20px hbox.setSpacing(20); // Add the Buttons to the HBox hbox.getChildren().addAll(yes,no,cancel); // Create the VBox VBox root = new VBox(); // Set the vertical spacing between children to 20px root.setSpacing(20); // Set the padding of the VBox root.setPadding(new Insets(10, 10, 10, 10)); // Add the Labels and the HBox to the VBox root.getChildren().addAll(label,hbox,message); // Create the Scene Scene scene = new Scene(root,400,200); // Add the StyleSheet to the Scene scene.getStylesheets().add(getClass().getResource("fxcssexample9.css").toExternalForm()); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("A Border Example"); // Display the Stage stage.show(); } }
10.2 The Style Sheet
fxcssexample9.css
.root { -fx-border-color: blue; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-border-insets: 5px; -fx-padding: 10px; -fx-spacing: 5px; -fx-background-color: lightgray; -fx-background-insets: 5px; } .button-style-yes { -fx-border-color: black; -fx-border-width: 5; -fx-border-radius: 0; -fx-border-insets: 0; -fx-border-style: solid line-join bevel line-cap square; } .button-style-no { -fx-border-color: red, black; -fx-border-width: 5, 5; -fx-border-radius: 0, 0; -fx-border-insets: 0, 5; -fx-border-style: solid inside, dotted outside; } .button-style-cancel { -fx-border-color: red black red black; -fx-border-width: 5; -fx-border-radius: 0; -fx-border-insets: 0; -fx-border-style: solid line-join bevel line-cap round; } .button { -fx-font-size: 20px; -fx-font-weight: bold; -fx-background-color: gray; -fx-background-insets: 5; -fx-background-radius: 10; } .label { -fx-font-family: "arial"; -fx-font-size: 14px; -fx-font-weight: bolder; }
A Node
can have multiple borders through CSS. A border is specified using five properties:
- -fx-border-color
- -fx-border-width
- -fx-border-radius
- -fx-border-insets
- -fx-border-style
Each property consists of a comma-separated list of items. Each item may consist of a set of values, which are separated by whitespaces.
10.3 Border Colors
The number of items in the list for the -fx-border-color
property determines the number of borders that are painted. The following style will paint one border with the black color:
-fx-border-color: black;
10.4 Border Widths
You can specify the width for borders using the -fx-border-width
property. You have an option to specify different widths for all four sides of a border. Different border widths are specified for top, right, bottom, and left sides in order. If the unit for the width value is not specified, pixel is used.
The following style specifies one border with all sides painted in black in 2px width:
-fx-border-color: black; -fx-border-width: 5;
10.5 Border Radii
You can specify the radius values for four corners of a border using the -fx-border-radius
property. You can specify the same radius value for all corners. Different radius values are specified for top-left, top-right, bottom-right, and bottom-left corners in order. If the unit for the radius value is not specified, pixel is used.
You can specify the inset values for four sides of a border using the -fx-border-insets
property. You can specify the same inset value for all sides. Different inset values are specified for top, right, bottom, and left sides in order. If the unit for the inset value is not specified, pixel is used.
The following style specifies a border with a radius value of 0px for all corners:
-fx-border-radius: 0;
10.6 Border Insets
You can specify the inset values for four sides of a border using the -fx-border-insets
property. You can specify the same inset value for all sides. Different inset values are specified for top, right, bottom, and left sides in order. If the unit for the inset value is not specified, pixel is used.
The following style specifies three borders with insets 0px and 5px on all sides:
-fx-border-insets: 0, 5;
10.7 Border Styles
The -fx-border-style
property defines the style of a border. Its value may contain several parts as follows:
-fx-border-style: <dash-style> [phase <number>] [<stroke-type>] [line-join <line-join-value>] [line-cap <line-cap-value>]
The value for <dash-style>
can be none, solid, dotted, dashed, or segments(<number>, <number>...)
. The value for <stroke-type>
can be centered, inside, or outside. The value for <line-join-value>
can be miter <number>
, bevel, or round. The value for <line-cap-value>
can be square, butt, or round. The segments()
function is used to have a border with a pattern using alternate dashes and gaps:
-fx-border-style: segments(dash-length, gap-length, dash-length, ...);
The first argument to the function is the length of the dash; the second argument is the length of the gap, and so on. After the last argument, the pattern repeats itself from the beginning. The following style will paint a border with a pattern of a 10px dash, a 5px gap, a 10px dash, and so on:
-fx-border-style: segments(10px, 5px);
You can pass as many dashes and gap segments to the function as you want. The function expects you to pass an even number of values. If you pass an odd number of values, this will result in values that are concatenated to make them even in number. For example, if you use segments(20px, 10px, 5px)
, it is the same as if you passed segments(20px, 10px, 5px, 20px, 10px, 5px)
.
In our example the styles are defined as follows:
.button-style-yes { -fx-border-color: black; -fx-border-width: 5; -fx-border-radius: 0; -fx-border-insets: 0; -fx-border-style: solid line-join bevel line-cap square; } .button-style-no { -fx-border-color: red, black; -fx-border-width: 5, 5; -fx-border-radius: 0, 0; -fx-border-insets: 0, 5; -fx-border-style: solid inside, dotted outside; } .button-style-cancel { -fx-border-color: red black red black; -fx-border-width: 5; -fx-border-radius: 0; -fx-border-insets: 0; -fx-border-style: solid line-join bevel line-cap round; }
Notice that the second style achieves overlapping of two borders, one in solid red and one in dotted black, by specifying the appropriate insets and stroke type (inside and outside). Borders are drawn in the order they are specified. It is important that you draw the solid border first in this case; otherwise, you would not see the dotted border.
The following snippet of code sets the id property of all buttons:
// Create The Buttons Button yes = new Button("Yes"); yes.getStyleClass().add("button-style-yes"); Button no = new Button("No"); no.getStyleClass().add("button-style-no"); Button cancel = new Button("Cancel"); cancel.getStyleClass().add("button-style-cancel");
10.8 The GUI
The following GUI shows an example with three buttons, where each button has an own unique border style:
11. Download Java Source Code
This was an JavaFX CSS Tutorial
You can download the full source code of this example here: JavaFxCSSExample.zip