收到一只叮咚
如果您只想更改颜色而不修改 CSS 的其余部分,您也可以遵循以下方法。如果您有一个非常大的 css 文件需要主题化,这会非常有用。基本思想是让所有 css 都是一个基本 css 文件。将所有颜色定义为该基本文件中 .root 类中的变量。对于每个主题 css,您只需要覆盖颜色变量即可。并在基本文件之上加载主题 css 文件。这样您就不会遇到任何可能的复制粘贴问题或缺少 css 问题:)一个完整的工作示例如下: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); }}基本.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;}类型1.css:.root{ -fx-window-border: red; -fx-window-color: yellow; -fx-window-text: brown; -fx-button-color: pink;}类型2.css:.root{ -fx-window-border: green; -fx-window-color: lightblue; -fx-window-text: white; -fx-button-color: grey;}类型3.css:.root{ -fx-window-border: brown; -fx-window-color: lightgreen; -fx-window-text: blue; -fx-button-color: yellow;}
牧羊人nacy
以下是动态设置给定组件主题颜色的几个具体示例:费边对查找颜色的建议。以编程方式创建的 CSS 样式表写入临时文件。使用查找颜色的示例该示例正在做的是设置一些标准查找颜色,这些颜色可以为modena.css您想要设置样式的三件事设置样式:背景颜色 ( -fx-background-color)。这是从该类派生的类中使用的标准背景Pane。文本的颜色 ( -fx-text-background-color)。是的,我知道这个名字很令人困惑,但无论出于什么原因,它似乎就是这样。按钮的颜色 ( -fx-base)。在示例应用程序中,用户可以使用 JavaFXColorPicker控件动态选择颜色来修改预览窗格中显示的项目的颜色。import javafx.application.Application;import javafx.geometry.Insets;import javafx.scene.Scene;import javafx.scene.control.*;import javafx.scene.layout.*;import javafx.scene.paint.Color;import javafx.stage.Stage;public class ThemeMaker extends Application { @Override public void start(Stage stage) throws Exception { Pane previewPane = createPreviewPane(); Pane controlPane = createControlPane(previewPane); Pane layout = new VBox( 20, controlPane, previewPane ); layout.setPadding(new Insets(10)); stage.setScene(new Scene(layout)); stage.show(); } private Pane createControlPane(Pane previewPane) { ColorPicker backgroundColorPicker = new ColorPicker(Color.web("#b3ccff")); ColorPicker textColorPicker = new ColorPicker(Color.web("#4d804d")); ColorPicker controlColorPicker = new ColorPicker(Color.web("#ffe6cc")); GridPane controlPane = new GridPane(); controlPane.setHgap(5); controlPane.setVgap(5); controlPane.addRow(0, new Label("Background color:"), backgroundColorPicker); controlPane.addRow(1, new Label("Text color:"), textColorPicker); controlPane.addRow(2, new Label("Control color:"), controlColorPicker); backgroundColorPicker.valueProperty().addListener((observable, oldColor, newColor) -> setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue()) ); textColorPicker.valueProperty().addListener((observable, oldColor, newColor) -> setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue()) ); controlColorPicker.valueProperty().addListener((observable, oldColor, newColor) -> setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue()) ); setThemeColors(previewPane, backgroundColorPicker.getValue(), textColorPicker.getValue(), controlColorPicker.getValue()); return controlPane; } private void setThemeColors(Pane previewPane, Color backgroundColor, Color textColor, Color controlColor) { previewPane.setStyle( "-fx-background-color: " + toHexString(backgroundColor) + ";" + "-fx-text-background-color: " + toHexString(textColor) + ";" + "-fx-base: " + toHexString(controlColor) + ";" ); } private Pane createPreviewPane() { 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); Button btn = new Button("Sample Button"); Pane previewPane = new VBox(10, label, btn); previewPane.setPadding(new Insets(5)); previewPane.setPrefWidth(200); return previewPane; } // from https://stackoverflow.com/a/56733608/1155209 "How to get hex web String from JavaFX ColorPicker color?" private String toHexString(Color value) { return "#" + (format(value.getRed()) + format(value.getGreen()) + format(value.getBlue()) + format(value.getOpacity())) .toUpperCase(); } private String format(double val) { String in = Integer.toHexString((int) Math.round(val * 255)); return in.length() == 1 ? "0" + in : in; } public static void main(String[] args) { launch(args); }}使用动态样式表的示例更新JavaFX 17 添加了从数据 URI 加载样式表的功能。这将是下面示例中演示的另一种方法,该方法使用文件 IO 动态创建 CSS 文件。因此,查找颜色解决方案非常强大,因为您可以动态设置场景中所有项目的颜色样式。然而,CSS 一般来说比颜色设置更强大。如果您的动态样式需要的不仅仅是颜色设置,或者您需要非常具体的规则来设置场景中特定项目的样式,那么您将需要自己的自定义样式表。stylesheets节点和场景的属性是一个动态的可观察列表。因此,如果更改样式表,您将重新设置节点或场景的样式。每个样式表都由一个 URL 引用。因此,要动态创建样式表,您需要做的就是在代码中构造样式表内容并将其写入临时文件,获取对临时文件的 URL 引用,然后将其设置为您想要的样式表风格。要提供此方法的示例,只需使用上一个示例中使用查找颜色的代码,并将 setThemeColors 方法替换为以下方法。然后,这将使用动态创建的 CSS 文件而不是查找的颜色来完成预览窗格的动态样式。注意:在创建动态样式表时,我尝试使用选择.root器来定义样式(类似于 Sai 的答案),但是,无论出于何种原因,它都不起作用(也许它不适用于我的 JavaFX (v13) 版本) 。因此,我使用特定的 CSS 选择器来设置项目的样式(例如label{-fx-text-fill:<custom-color>})。这工作得很好,而且作为奖励,它展示了通过定义自己的样式表可以获得的额外控制级别。private void setThemeColors(Pane previewPane, Color backgroundColor, Color textColor, Color controlColor) { try { Path cssPath = Files.createTempFile("fx-theme-", ".css"); Files.writeString( cssPath, ".themed{-fx-background-color:"+ toHexString(backgroundColor) +";}" + ".label{-fx-text-fill:"+ toHexString(textColor) +";}" + ".button{-fx-base:" + toHexString(controlColor) + ";}" ); cssPath.toFile().deleteOnExit(); System.out.println("Wrote " + cssPath); System.out.println("URL " + cssPath.toUri().toURL().toExternalForm()); previewPane.getStyleClass().setAll("themed"); previewPane.getStylesheets().setAll( cssPath.toUri().toURL().toExternalForm() ); } catch (IOException e) { e.printStackTrace(); }}查找颜色的背景以下文档是从有关查找颜色的链接 JavaFX CSS 参考部分复制的。这是一种实现您愿望的强大技术,并且该概念(据我所知)是 JavaFX CSS 处理所特有的,并且在基于标准 HTML 的 CSS 中不存在。通过查找颜色,您可以引用在当前节点或其任何父节点上设置的任何其他颜色属性。这是一个非常强大的功能,因为它允许在场景上指定通用颜色调色板,然后在整个应用程序中使用。如果您想更改其中一种调色板颜色,您可以在场景树中的任何级别执行此操作,这将影响该节点及其所有后代。查找到的颜色在应用之前不会被查找,因此它们是实时的,并对可能发生的任何样式更改做出反应,例如在运行时用节点上的“样式”属性替换调色板颜色。如果您在您正在使用的 JavaFX SDK 附带的 jar 文件中进行搜索,您将找到一个名为modena.css. 该文件预定义了许多查找的颜色,您可以覆盖这些颜色,以便更轻松地为应用程序设置主题。这些没有在任何地方记录,您需要查看 modena.css 文件以了解它们是什么(最有用的文件位于.root文件的 部分)。最重要的颜色-fx-base将为整个 JavaFX 控制系统设置基色。查找的颜色通常与其他一些 JavaFX CSS 概念(例如派生和阶梯)结合起来,以创建一致的主题,当基本查找颜色发生变化时,这些主题仍然可读。这允许您更改基色,例如从白色更改为黑色,并且基于基色的控件中显示的文本将自动从回更改为白色,以便仍然可读。什么是-fx-base?fx-base是所有控件的基色,因此设置它会更改场景中所有控件的颜色,这可能也是您想要的,但也许不是。如果您只想更改按钮而不是场景中的所有内容,只需直接在每个按钮上而不是在封闭的窗格上设置 -fx-base 颜色即可。实现这一目标的一种棘手方法是,您可以为按钮定义自己的 CSS 样式,然后在程序中将样式-fx-base: my-custom-color设置为动态值,如 fabian 的答案所示。my-custom-color请注意,设置基色优于尝试设置实际按钮颜色。因为,当您仔细观察时,按钮本身包括从基色派生的各种渐变和阴影,因此在渲染时它实际上是由多种颜色组成的,而不仅仅是单一颜色。