是否可以在运行时更改 JavaFX 应用程序的 css?
我正在寻找的效果是单击按钮即可更改皮肤或主题。
FXML
如果这有什么不同,则UI 位于文件中。
我努力了
Scene.getStylesheets()
.add(getClass().getResource(skinFileName).toExternalForm());
这没有效果。
谢谢
它应该有效果。试试这个完整的演示代码:
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);
}
}
主题1 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;
}
主题2 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;
}
注意 theme1 和 theme2 css 文件中的同名 CSS 选择器。
您也可以尝试这段代码(简单且真正说明性):
- 一个容器:我选择了 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 调用此代码。
现在,您可以在应用程序运行时在两个主题之间切换。