javafx change css at runtime

若如初见. 提交于 2019-12-30 08:19:52

问题


Is it possible to change css for a JavaFX application while it is running?

The effect I am looking for is changing skins or themes at the click of a button.

The UI is in an FXML file if that makes any difference.

I have tried

Scene.getStylesheets()
  .add(getClass().getResource(skinFileName).toExternalForm()); 

which has no effect.

thanks


回答1:


It should have the effect. Try this full demo code:

public class CssThemeDemo extends Application {

    private String theme1Url = getClass().getResource("theme1.css").toExternalForm();
    private String theme2Url = getClass().getResource("theme2.css").toExternalForm();

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        final Scene scene = new Scene(root, 300, 250);
        System.out.println("scene stylesheets: " + scene.getStylesheets());
        scene.getStylesheets().add(theme1Url);
        System.out.println("scene stylesheets: " + scene.getStylesheets());

        final Button btn = new Button("Load Theme 1");
        btn.getStyleClass().add("buttonStyle");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                scene.getStylesheets().remove(theme2Url);
                System.out.println("scene stylesheets on button 1 click: " + scene.getStylesheets());
                if(!scene.getStylesheets().contains(theme1Url)) scene.getStylesheets().add(theme1Url);
                System.out.println("scene stylesheets on button 1 click: " + scene.getStylesheets());
            }
        });

        final Button btn2 = new Button("Load Theme 2");
        btn2.getStyleClass().add("buttonStyle");
        btn2.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                scene.getStylesheets().remove(theme1Url);
                System.out.println("scene stylesheets on button 2 click: " + scene.getStylesheets());
                if(!scene.getStylesheets().contains(theme2Url)) scene.getStylesheets().add(theme2Url);
                System.out.println("scene stylesheets on button 2 click: " + scene.getStylesheets());
            }
        });

        ComboBox<String> comboBox = new ComboBox<String>(FXCollections.observableArrayList("Just", "another", "control"));
        root.getChildren().add(VBoxBuilder.create().spacing(10).children(btn, btn2, comboBox).build());

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

theme1 css:

.root{
    -fx-font-size: 14pt;
    -fx-font-family: "Tahoma";
    -fx-base: #DFB951;
    -fx-background: #A78732;
    -fx-focus-color: #B6A678;
}

.buttonStyle {
    -fx-text-fill: #006464;
    -fx-background-color: #DFB951;
    -fx-border-radius: 20;
    -fx-background-radius: 20;
    -fx-padding: 5;
}

theme2 css:

.root{
    -fx-font-size: 16pt;
    -fx-font-family: "Courier New";
    -fx-base: rgb(132, 145, 47);
    -fx-background: rgb(225, 228, 203);
}

.buttonStyle {
    -fx-text-fill: red;
    -fx-background-color: lightcyan;
    -fx-border-color: green;
    -fx-border-radius: 5;
    -fx-padding: 3 6 6 6;
}

Note the same named CSS selectors in both theme1 and theme2 css files.




回答2:


You can also try this piece of code(simple and truly illustrative) :

  • A Container for it: I chose BorderPane.
  • Add a main Scene for your application.
  • A Menu Bar with a set of items depending on the look of your application.
  • And item on the Menu bar.
BorderPane rootPane = new BorderPane();
Parent content = FXMLLoader.load(getClass().getResource("sample.fxml"));
rootPane.setCenter(content);
Scene scene = new Scene(root, 650, 550, Color.WHITE);
// Menu bar
MenuBar menuBar = new MenuBar();

// file menu
Menu fileMenu = new Menu("_File");
MenuItem exitItem = new MenuItem("Exit");
exitItem.setAccelerator(new KeyCodeCombination(KeyCode.X, KeyCombination.SHORTCUT_DOWN));
exitItem.setOnAction(ae -> Platform.exit());

fileMenu.getItems().add(exitItem);
menuBar.getMenus().add(fileMenu);

// Look and feel menu
Menu themeMenu = new Menu("_Theme");
themeMenu.setMnemonicParsing(true);
menuBar.getMenus().add(themeMenu);
rootPane.setTop(menuBar);


MenuItem theme1 = new MenuItem("Theme 1");
theme1.setOnAction(ae -> {
            scene.getStylesheets().clear();
            setUserAgentStylesheet(null);
            scene.getStylesheets()
                    .add(getClass()
                            .getResource("theme1.css")
                            .toExternalForm());
});

MenuItem theme2 = new MenuItem("Theme 2");
        theme2.setOnAction(ae -> {
            scene.getStylesheets().clear();
            setUserAgentStylesheet(null);
            scene.getStylesheets()
                    .add(getClass()
                            .getResource("theme2.css")
                            .toExternalForm());
});


themeMenu.getItems()
                .addAll(theme1,
                        theme2);

primaryStage.setScene(scene);
primaryStage.show();

Supposed that you have your two CSS files in the folder of the class where you will call this code with the corresponding name theme1.css and theme2.css.

Now you can switch between two themes while your application is running.



来源:https://stackoverflow.com/questions/17769388/javafx-change-css-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!