Javafx change css во время выполнения

Можно ли изменить css для приложения JavaFX во время его работы?

Эффект, который я искал, - это изменение скинов или тем одним нажатием кнопки.

Пользовательский интерфейс находится в файле FXML, если это имеет значение.

Я пробовал

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

который не имеет эффекта.

спасибо

Ответ 1

Он должен иметь эффект. Попробуйте этот полный демо-код:

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;
}

Обратите внимание на те же именованные селекторы CSS как в файлах theme1, так и в файле theme2 css.

Ответ 2

Вы также можете попробовать этот кусок кода (простой и по-настоящему иллюстративный):

  • Контейнер для него: я выбрал BorderPane.
  • Добавить основную сцену для вашего приложения.
  • Панель меню с набором элементов в зависимости от внешнего вида вашего приложения.
  • И пункт в строке меню.
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();

Предположим, что у вас есть два файла CSS в папке класса где вы будете называть этот код с соответствующим именем theme1.css и theme2.css.

Теперь вы можете переключаться между двумя темами, пока приложение работает.