我的应用程序允许用户使用自定义CSS主题来设置界面样式。我有几个预构建的“主题”可供选择,它们非常简单,只有3个属性。

CSS示例:

.root{
    -fx-background: #325c81;
    -fx-default-button: #77a3ca;
    -fx-base: #a7c4dd;
}

该应用程序具有3个ColorPicker控件,这些控件需要允许用户为每个属性选择一种颜色并将其保存回CSS文件。

我实际上写CSS文件没有问题,但是我找不到解析.css文件的方法,以便用ColorPicker文件中的值设置.css控件的值。

基本程序流程

1)用户从ComboBox中选择一个预制主题:
cboPresetTheme.valueProperty().addListener((observable, priorTheme, newTheme) -> {
                Utility.applyTheme(cboPresetTheme.getScene(), newTheme);
            });

2)关联的.css文件被加载并应用于当前Scene:
public static void applyTheme(Scene scene, Theme theme) {
    scene.getStylesheets().clear();

    File css = new File("themes/" + theme.getFileName());
    File fontFile = new File("themes/Font.css");

    scene.getStylesheets().addAll(
            css.toURI().toString(),
            fontFile.toURI().toString());
}

3)3个ColorPicker控件将使用应用的StyleSheet中的值进行更新:
cpBackground.setValue(Color.valueOf(cssFileBackground));
cpBase.setValue(Color.valueOf(cssFileBase));
cpDefaultButton.setValue(Color.valueOf(cssFileDefaultButton));

虽然我对步骤1和2没问题,但是我不知道如何处理步骤3。

我看过其他CSS解析器库(谢谢Google),但它们似乎更适合站立式CSS,并且不支持FX属性。 StackExchange问​​题edit or parse FX-CSS file programmatically似乎在问相同的问题,但从未成功回答。

一个答案建议使用CSS Parser来完成此操作,但是由于几乎不了解文档(而且超出了我目前的理解水平),所以我不知道从哪里开始。

我知道目前可能没有标准的API可以完成此任务,但是我希望那里可能有一个我找不到的简单库或解决方案。

最佳答案

有几种方法可以解决将CSS声明转换为Color的问题。

为辅助节点设置样式

这很简单,但是很有效:想法是您可以使用相同的CSS设置节点的背景颜色样式,然后使用该颜色设置colorPicker值。

在这种情况下,您唯一需要考虑的是,仅当将节点添加到场景时才设置其样式。

因此,您必须将节点添加到场景中。添加大小为0x0的节点不会引起任何问题,但是也许您不希望它出现在其中,因此可以使用辅助场景。

public class CSSParsingApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        ColorPicker cpBackground = new ColorPicker(retrieveColor("value1"));
        ColorPicker cpBase = new ColorPicker(retrieveColor("value2"));
        ColorPicker cpDefaultButton = new ColorPicker(retrieveColor("value3"));

        VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase);
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 300, 250);
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Color retrieveColor(String value) {
        Pane pane = new Pane();
        pane.getStyleClass().add(value);

        Scene sceneAux = new Scene(pane);
        sceneAux.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
        pane.applyCss();
        return (Color) pane.getBackground().getFills().get(0).getFill();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

其中style.css是:
.root {
    -fx-background: #325c81;
    -fx-default-button: #77a3ca;
    -fx-base: #a7c4dd;
}

.value1 {
    -fx-background-color: -fx-background;
}
.value2 {
    -fx-background-color: -fx-default-button;
}
.value3 {
    -fx-background-color: -fx-base;
}

使用StylableProperties

找到了一个类似的,更优雅的解决方案here。它使用StylableProperties创建一个节点,您可以使用自定义-named-color属性对其进行样式设置,然后将该helper节点添加到主场景中。

基本上,它与上面的想法相同,也许更简洁,因为您不需要修改css文件。

使用CssToColorHelper,您的代码将如下所示:
public class CSSParsingApp extends Application {

    private CssToColorHelper helper = new CssToColorHelper();

    @Override
    public void start(Stage primaryStage) {
        ColorPicker cpBackground = new ColorPicker();
        ColorPicker cpBase = new ColorPicker();
        ColorPicker cpDefaultButton = new ColorPicker();

        VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase, helper);
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 300, 250);
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());

        cpBackground.setValue(getNamedColor("-fx-background"));
        cpDefaultButton.setValue(getNamedColor("-fx-default-button"));
        cpBase.setValue(getNamedColor("-fx-base"));

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Color getNamedColor(String name) {
        helper.setStyle("-named-color: " + name + ";");
        helper.applyCss();

        return helper.getNamedColor();
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

其中style.css是您的CSS文件:
.root {
    -fx-background: #325c81;
    -fx-default-button: #77a3ca;
    -fx-base: #a7c4dd;
}

使用JavaFX CSSParser

如果您正在寻找CSSParser,为什么不只使用JavaFX中包含的那个,即您实际用于将样式应用于应用程序的那个呢?

它位于com.sun.javafx.css.parser.CSSParser下,如果答案是您不想使用私有API,那么好消息是它将成为JavaFX 9中的公共API。

使用它,您可以解析css文件并轻松检索任何解析后的值。
 public class CSSParsingApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        ColorPicker cpBackground = new ColorPicker();
        ColorPicker cpBase = new ColorPicker();
        ColorPicker cpDefaultButton = new ColorPicker();

        VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase);
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 300, 250);
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());

        cpBackground.setValue(parseColor("-fx-background"));
        cpDefaultButton.setValue(parseColor("-fx-default-button"));
        cpBase.setValue(parseColor("-fx-base"));

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Color parseColor(String property) {
        CSSParser parser = new CSSParser();
        try {
            Stylesheet css = parser.parse(getClass().getResource("style.css").toURI().toURL());
            final Rule rootRule = css.getRules().get(0); // .root
            return (Color) rootRule.getDeclarations().stream()
                .filter(d -> d.getProperty().equals(property))
                .findFirst()
                .map(d -> ColorConverter.getInstance().convert(d.getParsedValue(), null))
                .get();
        } catch (URISyntaxException | IOException ex) { }
        return Color.WHITE;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

其中style.css是您的CSS文件:
.root {
    -fx-background: #325c81;
    -fx-default-button: #77a3ca;
    -fx-base: #a7c4dd;
}

10-07 19:06
查看更多