Issue
I am attempting to create a Pane object with JavaFX that has three different colors: A color for the background, a color for the text, and a color for the buttons. Each of these three colors is determined dynamically at run-time, based on the values of a custom object passed into the method. I figured out how to implement this behavior directly in my code fairly easily, and it seems like I could make use of a controller and an initialize method to set it up with FXML. But I'm wondering if it would be possible or advisable to set something like this up with CSS.
As far as I can tell, CSS doesn't really make use of variables from the code, just hardcoded values to be set beforehand. Given the sheer number of potential combinations, it doesn't seem like it would be of much worth to make a different sheet for each one. Still, I heard that making use of CSS is modern practice, so I'm wondering if it's possible to use a single sheet to make multiple different types of Panes or if every possible Pane would have to be uniquely defined with its own sheet, even with everything else about the Pane being identical.
Solution
I agree with the approach of what @Sedrick has mentioned in the comments.
If you want to change only colors without modifying the rest of CSS, you can follow the below approach as well. This can be quite useful if you have a very large css file that needs to be themed.
The basic idea is to have all your css is one base css file. Define all your colors as variables in .root class in that base file. And for each of your theme css, you just need to override the color variables only. And load the theme css file on top of base file. This way you will not encounter any possible copy-paste issues or missing css issues :)
A complete working example is below:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.stream.Stream;
public class DynamicStyling_Demo extends Application {
@Override
public void start(Stage stage) throws Exception {
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.setSpacing(10);
Stream.of("Default", "Type1", "Type2", "Type3").forEach(type -> {
Button button = new Button("Open " + type);
button.setOnAction(e -> {
Stage subStage = buildStage(type);
subStage.initOwner(stage);
if (!type.equalsIgnoreCase("default")) {
subStage.getScene().getStylesheets().add(this.getClass().getResource(type.toLowerCase() + ".css").toExternalForm());
}
subStage.show();
});
root.getChildren().add(button);
});
Scene sc = new Scene(root, 400, 400);
sc.getStylesheets().add(this.getClass().getResource("base.css").toExternalForm());
stage.setScene(sc);
stage.show();
}
private Stage buildStage(String title) {
Label label = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
label.setWrapText(true);
VBox.setVgrow(label, Priority.ALWAYS);
Button btn = new Button("Sample Button");
VBox pane = new VBox(label, btn);
pane.getStyleClass().add("my-pane");
StackPane subRoot = new StackPane(pane);
subRoot.setPadding(new Insets(10));
Stage subStage = new Stage();
subStage.setTitle(title);
subStage.setScene(new Scene(subRoot, 300, 300));
subStage.getScene().getStylesheets().add(this.getClass().getResource("base.css").toExternalForm());
return subStage;
}
public static void main(String[] args) {
Application.launch(args);
}
}
base.css:
.root{
-fx-window-border: #444444;
-fx-window-color: #999999;
-fx-window-text: #111111;
-fx-button-color: #555555;
}
.my-pane{
-fx-border-width: 2px;
-fx-border-color: -fx-window-border;
-fx-background-color: -fx-window-color;
-fx-padding: 10px;
-fx-spacing: 10px;
}
.my-pane .label{
-fx-text-fill: -fx-window-text;
-fx-font-size: 16px;
}
.my-pane .button{
-fx-base: -fx-button-color;
}
type1.css:
.root{
-fx-window-border: red;
-fx-window-color: yellow;
-fx-window-text: brown;
-fx-button-color: pink;
}
type2.css:
.root{
-fx-window-border: green;
-fx-window-color: lightblue;
-fx-window-text: white;
-fx-button-color: grey;
}
type3.css:
.root{
-fx-window-border: brown;
-fx-window-color: lightgreen;
-fx-window-text: blue;
-fx-button-color: yellow;
}
Answered By - Sai Dandem
Answer Checked By - David Marino (JavaFixing Volunteer)