JavaFX CSS动态样式

时间:2017-03-01 20:14:28

标签: java css javafx

我在询问之前在网上搜索并搜索了我的问题的答案,但是找不到这样的内容。

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

"最佳做法是什么"对于FX中的这类事情?

1 个答案:

答案 0 :(得分:3)

有一些颜色,影像中的一切都基于这些颜色。我在某个地方有一个例子,我现在找不到,但基本上是

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

}

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

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文档并绑定结果节点的样式。

最后,当然,你会做一些像

这样的事情
ColorPicker baseColorPicker = new ColorPicker();
baseColorPicker.valueProperty().bindBidirectional(theme.baseProperty());

等,当用户选择新颜色时,一切都会更新。