Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

CSS styles

The look of JavaFX controls is set with cascading style sheets: the same CSS as on the web, but with its own property names, all starting with -fx-. The standard theme is called Modena; your stylesheet is applied on top of it and changes only what it mentions. This keeps the styling separate from both the markup and the code.

The stylesheet

Create a file next to the FXML:

/* src/main/resources/com/example/notes/styles.css */
.root {
    -fx-font-family: "Segoe UI", sans-serif;
    -fx-font-size: 14px;
    -fx-background-color: #f7f7fb;
}
 
.header {
    -fx-font-size: 22px;
    -fx-font-weight: bold;
    -fx-text-fill: #2d3a8c;
}
 
.button {
    -fx-background-color: #4f6bed;
    -fx-text-fill: white;
    -fx-background-radius: 6;
    -fx-padding: 6 14;
}
 
.button:hover {
    -fx-background-color: #3b55d1;
}
 
.button:disabled {
    -fx-opacity: 0.5;
}
 
.danger {
    -fx-background-color: #d9534f;
}
 
.danger:hover {
    -fx-background-color: #c9302c;
}
 
#countLabel {
    -fx-text-fill: #777777;
}

.root is the root of the scene: the font and background set here are inherited by every control. Each standard control has its own class: .button, .label, .text-field, .table-view. #countLabel selects a node by its fx:id.

Attaching it to the scene

The file is added to the scene's list of stylesheets in App:

// src/main/java/com/example/notes/App.java — part of start()
Scene scene = new Scene(loader.load(), 800, 480);
scene.getStylesheets().add(App.class.getResource("styles.css").toExternalForm());

toExternalForm() turns the resource address into a string JavaFX understands. Another way is an attribute on the FXML root tag: stylesheets="@styles.css", where @ means a path relative to the FXML file.

Your own classes

Let's add classes to the header and the delete button in the markup:

<!-- src/main/resources/com/example/notes/main-view.fxml — changed lines -->
<Label text="My notes" styleClass="header">
 
<Button fx:id="deleteButton" text="Delete" onAction="#deleteNote"
        styleClass="danger"/>

The styleClass attribute adds a class to the standard one: the button gets both, button and danger. The .danger rule comes after .button in the file, so its background color wins. In code, deleteButton.getStyleClass().add("danger") does the same.

Common properties

PropertyWhat it sets
-fx-background-colorThe background color
-fx-text-fillThe text color of a Label or Button
-fx-font-size, -fx-font-weightFont size and weight
-fx-paddingInner spacing
-fx-background-radiusRounded background corners
-fx-border-color, -fx-border-widthA border
-fx-opacityTransparency

Pseudo-classes: :hover under the cursor, :pressed being pressed, :focused in focus, :disabled unavailable, :selected a selected row or a ticked check box.

Trying it out

Run the application. The window background is now a light grey with a blue tint, and "My notes" is a large bold blue header. "Add" is a blue button with rounded corners and white text, and "Delete" is red. While nothing is selected, "Delete" is semi-transparent. "Notes: 2" is grey.

Common mistake

If the file name in getResource is wrong, for example style.css instead of styles.css, the window does not open: java.lang.NullPointerException: Cannot invoke "java.net.URL.toExternalForm()" because the return value of "java.lang.Class.getResource(String)" is null. And a property without the prefix, for example background-color: red;, is silently skipped by JavaFX; if a style does not apply, check the -fx- first.

Thanks for reading!

Donate to the site — we work hard for you.