JavaFx css用于整个应用程序

时间:2015-03-05 10:53:51

标签: java css javafx stylesheet

我们正在努力解决我们的应用程序的自定义css问题。到目前为止,我们使用了解决方法来应用我们的自定义css,但保留了其余的Modena样式。

StyleManager.getInstance().addUserAgentStylesheet(css);

在8u40 java update中,此行为受到限制,不再有效。将样式表分别设置为所有场景是疯狂的,通过

设置自定义样式表
Application.setUserAgentStylesheet(css);

工作但不是我们想要的 - 模式样式表被自定义替换,所以很多控件都没有样式。 我们找到了另一种解决方法:将整个modena文件夹复制到我们的项目中,将我们的自定义css样式添加到modena.css和(非常重要!)将modena.css重命名为其他内容,例如modenaB.css。在JavaFx源代码样式表中进行比较,如果名称保持不变,则使用原始模型,尽管提供了不同的URL。

我的问题是,在应用程序初始化时是否有更好的方法来应用一个自定义样式表,这将在所有场景中通过整个应用程序使用,同时保留所有未覆盖控件的默认模式样式?

4 个答案:

答案 0 :(得分:2)

最简单的方法是在用户代理样式表中添加css文件。

@Override
public void start(Stage primaryStage) {
    // ...
    Application.setUserAgentStylesheet(Application.STYLESHEET_MODENA);
    StyleManager.getInstance().addUserAgentStylesheet("example.css");
    // ...
}

答案受到GuiGarage的启发。

答案 1 :(得分:0)

如何将与构建场景或控件(视图)相关的所有逻辑放在单独的类中,并将其用于构建和分配适当的样式表?

例如在我的情况下,我创建了FXMLBuilder类。它只是在控制器类上加载FXML,然后遍历控制器的层次结构并应用与层次结构中相应控制器相关的样式表。在文件系统中,我有以下层次结构:

|
+- controllers
|  |
|  +- BaseController.java
|  +- BaseController.fxml
|  +- BaseController.css
|
...
|
+- MyController.java (inherited from BaseController)
+- MyController.fxml
+- MyController.css

所以,当我构建MyController的实例时,

MyController myController = new MyController(...);
Parent myControllerRootNode = FXMLBuilder.build(myController);
...

它适用于MyController.css和BaseController.css文件中的样式表。

这是我的FXMLBuilder

public class FXMLBuilder {

    public static final String FXML_EXTENSION = "fxml";
    public static final String CSS_EXTENSION = "css";

    public static Parent build(Object controller) throws IOException {
        Class<?> controllerClass = controller.getClass();

        URL fxmlURL = getResourceURL(controllerClass, FXML_EXTENSION);

        FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL);
        fxmlLoader.setControllerFactory(param -> controller);

        Parent rootNode = fxmlLoader.load();

        loadStylesheets(rootNode, controllerClass);

        return rootNode;
    }

    private static void loadStylesheets(Parent rootNode, Class<?> controllerClass) {
        Class<?> currentControllerClass = controllerClass;
        while (!currentControllerClass.equals(Object.class)) {
            if (getResourceURL(currentControllerClass, CSS_EXTENSION) != null) {
                rootNode.getStylesheets().add(getResourcePath(currentControllerClass, CSS_EXTENSION));
            }
            currentControllerClass = currentControllerClass.getSuperclass();
        }
    }

    public static String getResourcePath(Class<?> resourceClass, String extension) {
        return String.format("/%s.%s", resourceClass.getCanonicalName().replace(".", "/"), extension);
    }

    public static URL getResourceURL(Class<?> resourceClass, String extension) {
        return resourceClass.getResource(getResourcePath(resourceClass, extension));
    }

}

我认为您可以编写类似这样的内容,它将加载适用于所有视图的基本样式表,然后加载为视图指定的自定义样式表。

P.S。最好从基本控制器开始迭代层次结构。

答案 2 :(得分:0)

根据我的经验,最简单的方法是在顶部父节点中使用SceneBuilder设置CSS。此节点的所有子节点都将继承此CSS。然后,对于单个案例,您可以加载另一个案例以覆盖您想要的视图。我不知道它是否在代码中以相同的方式工作,但它与SceneBuilder一样!

答案 3 :(得分:0)

如果您是相关css文件的作者,则始终可以在CSS文件顶部添加导入。这样,您可以将其用作userAgentStyleSheet的替代品。例如

@import "com/sun/javafx/scene/control/skin/modena/modena.css";
/* rest of CSS code */

如果您无法控制所涉及的css文件,则始终可以创建一个“包装” css文件,该文件随后相互导入modena和其他css文件。例如

@import "com/sun/javafx/scene/control/skin/modena/modena.css";
@import "the/extra/file.css";

在您的应用程序中,您可以使用以下命令设置userAgentStyleSheet:

Application.setUserAgentStylesheet(css);