JavaFX CSS动态样式 [英] JavaFX CSS Dynamic Styling

查看:83
本文介绍了JavaFX CSS动态样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在询问之前,我在网上搜索并搜索了问题的答案,但找不到类似的东西.

I searched and searched for an answer to my question online before asking but couldn't find anything like this.

我希望我的应用程序用户能够从JavaFX ColorPicker中选择一种颜色,并根据他们的选择来更新整个应用程序窗口颜色,按钮颜色,字体等.我的应用程序中有很多屏幕,我并不是真的想在每个窗格上都设置setStyle()来确保颜色发生变化.我想要某种类型的CSS文件,其中的颜色可以根据所选颜色发生变化在ColorPicker中.这可能吗?我的意思是,我知道您可以通过Java代码编写文本文件,并为其提供".css"扩展名,但是还有其他方法可以做到这一点吗?

I want my application user to be able to pick a color from the JavaFX ColorPicker and the entire application window colors, button colors, font etc. updates based off their choice. There are a LOT of screens in my application and I don't really want to setStyle() on every pane to make sure the colors change I want to have some type of CSS file where the colors in it can change based on the color chosen in the ColorPicker. Is this possible? I mean I realize you can write a text file through Java Code and give it a ".css" extension but is there any other way to accomplish this?

在FX中,这种事情的最佳实践"是什么?

What are the "best practices" for this sort of thing in FX?

推荐答案

modena中的所有内容都基于几种颜色.我在某个地方有一个示例,目前无法找到,但基本上是

There are a handful of colors on which everything in modena is based. I had an example somewhere, which I can't find right now, but basically

  • -fx-base
  • -fx-accent
  • -fx-default-button
  • -fx-focus-color
  • -fx-faint-focus-color (与 -fx-focus-color 相同,但不透明度为0x22)
  • -fx-base
  • -fx-accent
  • -fx-default-button
  • -fx-focus-color
  • -fx-faint-focus-color (same as -fx-focus-color but with opacity of 0x22)

因此,在根节点上设置这些元素基本上将使整个根及其后代成为主题.

So setting these on a root node will basically theme the entire root and its descendants.

最后,无法绕开一个事实,即当用户在每个根节点上更改它们时,都必须以某种方式更新它们,而您需要提供接线来做到这一点.使用CSS文件可能不是一个可行的方法,因为要确保按需重新加载更新的文件将很困难.我可能会进行整理,以使根节点的 styleProperty()发生变化,以便在用户更改颜色时定义这些颜色.

In the end, there's no way around the fact that you will have to somehow update these when the user changes them on each root node, and you need to provide the wiring to do that. Using a CSS file is probably not a way to go, as it's going to be difficult to ensure that an updated file is reloaded as needed. I would probably wire things up so that the styleProperty() of the root node changes to define these colors when the user changes them.

您可以考虑创建一个封装以下内容的 Theme 类:

You could consider creating a Theme class that encapsulates these:

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

}

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

Then you can create a single Theme instance that you make available to you app, and bind all the root node's styleProperty to the cssProperty. Alternatively you could add a factory method to Theme for generating root nodes:

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

例如用作

BorderPane root = theme.createThemedNode(BorderPane::new);

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

If you use FXML you could create similar types of factory methods for loading a FXML document and binding the style of the resulting node.

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

Finally, of course, you would just do something like

ColorPicker baseColorPicker = new ColorPicker();
baseColorPicker.valueProperty().bindBidirectional(theme.baseProperty());

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

etc, and when the user chooses a new color, everything is updated.

这篇关于JavaFX CSS动态样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆