java - 如何解析/映射 JavaFX CSS 文件以检索其属性和值?

标签 java css parsing javafx

我的应用程序允许用户使用自定义 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 声明转换为颜色的问题。

设置辅助节点的样式

这非常简单,但很有效:这个想法是您可以使用相同的 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 下,如果答案是您不想使用私有(private) API,那么好消息是它将成为公共(public) API在 JavaFX 9 .

有了它,您可以解析 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;
}

关于java - 如何解析/映射 JavaFX CSS 文件以检索其属性和值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42609756/

相关文章:

java - HttpServlet请求: How to determine Content-Type of requested asset

java - 如何为 REST Web 服务创建 JUnit 测试?

jquery - 如何在 Bootstrap 中将这些图像居中?

parsing - 有没有办法在解析后使用关联性和优先级表来修复其中包含运算符的表达式?

html - 将我的 HTML 从一种形式转换为另一种形式

java - org.hibernate.hql.internal.ast.QuerySyntaxException : table is not mapped

java - 如何将 JAXB 运行时库与 OpenJDK 11 捆绑在一起?

python - 如何在 Python 中解析简单的内联标记(即 *bold*)?

javascript - 如何使用 Angular js 将事件类放入 html 页面的特定 id/页脚?

html - Codecademy - HTML, CSS 练习