如何解析/映射JavaFX CSS文件以检索其属性和值? [英] How to parse/map JavaFX CSS file to retrieve its properties and values?

查看:67
本文介绍了如何解析/映射JavaFX CSS文件以检索其属性和值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

示例CSS:

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

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

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

基本程序流程

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)用应用的StyleSheet中的值更新3个ColorPicker控件:

cpBackground.setValue(Color.valueOf(cssFileBackground));
cpBase.setValue(Color.valueOf(cssFileBase));
cpDefaultButton.setValue(Color.valueOf(cssFileDefaultButton));

虽然我对第1步和第2步没有问题. 2,我不知道如何处理步骤3.

我看过其他CSS解析器库(谢谢Google),但它们似乎更适合站立式CSS,并且不支持FX属性. StackExchange问​​题编辑或以编程方式解析FX-CSS文件似乎在问同样的问题,但从未成功回答.

一个答案建议使用 CSS解析器来完成此操作,但是由于很少了解文档(还有什么超出我目前的理解水平),我不知道从哪里开始.

我知道目前可能没有标准的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

此处 .它使用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,那么好消息是它将成为

其中style.css是您的CSS文件:

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

My application allows users to use custom CSS themes to style the interface. I have several pre-built "themes" available to choose from that are very simple, with only 3 properties.

Sample CSS:

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

The application has 3 ColorPicker controls that need to allow users to select a color for each of those properties and save back to the CSS file.

I have no problem with actually writing the CSS file, but I cannot find a way to parse the .css file in order to set the values of the ColorPicker controls with the values from the .css file.

Basic Program Flow

1) User selects a premade theme from ComboBox:

cboPresetTheme.valueProperty().addListener((observable, priorTheme, newTheme) -> {
                Utility.applyTheme(cboPresetTheme.getScene(), newTheme);
            });

2) The associated .css file is loaded and applied to the current 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) The 3 ColorPicker controls are updated with the values from the applied StyleSheet:

cpBackground.setValue(Color.valueOf(cssFileBackground));
cpBase.setValue(Color.valueOf(cssFileBase));
cpDefaultButton.setValue(Color.valueOf(cssFileDefaultButton));

While I have no problem with steps 1 & 2, I do not know how to process step 3.

I have looked at other CSS Parser libraries (thank you, Google) but they seem more geared toward stand CSS and don't support FX properties. The StackExchange question edit or parse FX-CSS file programmatically appears to be asking the same question but it was never successfully answered.

One answer suggests using CSS Parser to accomplish this, but as there is little to know documentation (and what is there is beyond my current comprehension level), I don't know where to begin.

I understand there may not be a standard API currently available to accomplish this, but I was hoping there may be a simple library or solution out there that I have been unable to find.

解决方案

There are several ways you can tackle the conversion of a CSS declaration into a Color.

Style an auxiliar node

This is quite simple, but effective: The idea is that you could just style the background color of a node with the same css, and then set the colorPicker value with that color.

The only thing you need to take into account in this case is that the node is styled only when is added to a scene.

So you have to add the node to the scene. Adding a node with 0x0 size won't cause any issue, but maybe you don't want it to be there, so you can use an auxiliar scene.

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

}

where style.css is:

.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;
}

Use StylableProperties

A similar, more elegant solution is found here. It uses StylableProperties to create a node, that you can style with a custom -named-color property, and then adds this helper node to the main scene.

Basically it is the same idea as the one above, maybe more clean, as you don't need to modify your css file.

Using CssToColorHelper, your code will be like this:

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

where style.css is your css file:

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

Use JavaFX CSSParser

If you are looking for a CSSParser, why don't you just use the one included in JavaFX, the one you actually use to apply styling to your app?

It is under com.sun.javafx.css.parser.CSSParser, and if the answer is you don't want to use private API, the good news is that it will be public API in JavaFX 9.

With it you can parse the css file and retrieve any parsed value easily.

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

where style.css is your css file:

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

这篇关于如何解析/映射JavaFX CSS文件以检索其属性和值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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