JavaFX CSS 动态样式

Phi*_*ghn 1 css java javafx

在提问之前,我在网上搜索并搜索了我的问题的答案,但找不到类似的内容。

我希望我的应用程序用户能够从 JavaFX ColorPicker 中选择颜色,并根据他们的选择更新整个应用程序窗口颜色、按钮颜色、字体等。我的应用程序中有很多屏幕,我真的不想在每个窗格上 setStyle() 以确保颜色发生变化我想要某种类型的 CSS 文件,其中的颜色可以根据所选颜色进行更改在颜色选择器中。这可能吗?我的意思是我意识到你可以通过 Java 代码编写一个文本文件并给它一个“.css”扩展名,但是还有其他方法可以实现这一点吗?

外汇中此类事情的“最佳实践”是什么?

Jam*_*s_D 5

摩德纳的一切都以几种颜色为基础。我在某个地方有一个例子,我现在找不到,但基本上

  • -fx-base
  • -fx-accent
  • -fx-default-button
  • -fx-focus-color
  • -fx-faint-focus-color(与不透明度相同-fx-focus-color但不透明度为 0x22)

因此,在根节点上设置这些基本上将主题化整个根及其后代。

最后,当用户在每个根节点上更改它们时,您将不得不以某种方式更新它们,并且您需要提供连接来执行此操作,这是无法回避的事实。使用 CSS 文件可能不是一个好方法,因为很难确保根据需要重新加载更新的文件。我可能会将其连接起来,以便当styleProperty()用户更改它们时根节点的更改以定义这些颜色。

您可以考虑创建一个Theme封装这些的类:

public class Theme {

    private final ObjectProperty<Color> base = new SimpleObjectProperty<>(Color.web("#ececec"));
    private final ObjectProperty<Color> accent = new SimpleObjectProperty<>(Color.web("#0096c9"));
    private final ObjectProperty<Color> defaultButton = new SimpleObjectProperty<>(Color.web("#abd8ed"));
    private final ObjectProperty<Color> focusColor = new SimpleObjectProperty<>(Color.web("#039ed3"));
    private final ObjectProperty<Color> faintFocusColor = new SimpleObjectProperty<>(Color.web("039ed322"));

    public ObjectProperty<Color> baseProperty() {
        return base ;
    }

    public final Color getBase() {
        return baseProperty().get();
    }

    public final void setBase(Color base) {
        baseProperty().set(base);
    }

    // etc etc

    private final ReadOnlyStringWrapper css = new ReadOnlyStringWrapper() ;

    public Theme() {
        css.bind(Bindings.createStringBinding(() -> String.format(
             "-fx-base: %s; "
            +"-fx-accent: %s; "
            +"-fx-default-button: %s; "
            +"-fx-focus-color: %s ; "
            +"-fx-faint-focus-color: %s ;",
            toRgba(getBase()),
            toRgba(getAccent()),
            toRgba(getDefaultButton()),
            toRgba(getFocusColor()),
            toRgba(getFaintFocusColor())),
            base, accent, defaultButton, focusColor, faintFocusColor));
    }

    private String toRgba(Color color) {
        int r = (int) (255 * color.getRed());
        int g = (int) (255 * color.getGreen());
        int b = (int) (255 * color.getBlue());
        int a = (int) (255 * color.getOpacity());
        return String.format("#%02x%02x%02x%02x", r, g, b, a);
    }

    public ReadOnlyStringProperty cssProperty() {
        return css.getReadOnlyProperty();
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建一个Theme可供应用程序使用的单个实例,并将所有根节点绑定stylePropertycssProperty. 或者,您可以添加一个工厂方法Theme来生成根节点:

public <T extends Parent> T createThemedNode(Supplier<T> factory) {
    T node = factory.get();
    node.styleProperty().bind(cssProperty());
    return node ;
}
Run Code Online (Sandbox Code Playgroud)

例如,您可以将其用作

BorderPane root = theme.createThemedNode(BorderPane::new);
Run Code Online (Sandbox Code Playgroud)

如果您使用 FXML,您可以创建类似类型的工厂方法来加载 FXML 文档并绑定结果节点的样式。

最后,当然,你会做类似的事情

ColorPicker baseColorPicker = new ColorPicker();
baseColorPicker.valueProperty().bindBidirectional(theme.baseProperty());
Run Code Online (Sandbox Code Playgroud)

等等,当用户选择新颜色时,所有内容都会更新。