首页 > 解决方案 > Source not found importing CSS to JavaFX

问题描述

I'm working on a project where I'd like to use an external CSS file with JavaFX to style the VBox and panes and such.

I've used the line below to try to add the style sheet to the respective scene:

scene.getStylesheets().add(getClass().getResource("/style.css").toExternalForm());

This gave me null pointers, I read some other posts on this issue and found that this is often due to the stylesheet not being in the class path that it is trying to be accessed from. Here is a screenshot that allows you to see that this is not the case:

You'll notice there is Styles.css and style.css, I tried both for different troubleshooting purposes

I also found suggestions from people saying that if it is in the class path, that it should be accessed as such:

scene.getStylesheets().add("style.css");

However doing so is giving me

Nov 04, 2018 9:24:10 PM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "Styles.css" not found.

I'm open to any suggestions, I'm working in IntelliJ using maven.

EDIT: Here is the pom file for further investigation -

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.almasb</groupId>
<artifactId>CashMachine</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <source.version>1.8</source.version>

    <!-- plugins -->
    <maven.compiler.version>3.3</maven.compiler.version>
    <maven.shade.version>2.4.2</maven.shade.version>

    <!-- dependencies -->
</properties>

<build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.version}</version>
            <configuration>
                <source>${source.version}</source>
                <target>${source.version}</target>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>${maven.shade.version}</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.almasb.atm.CashMachineApp</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

标签: javacssjavafxstylesheet

解决方案


Maven convention uses a standard directory layout and, unless otherwise configured, requires that you follow it. One of the things the standard directory layout does is separate Java source files (.java) from resource files (everything not .java). It looks like this:

|--projectDir/
|  |--src/
|  |  |--main/
|  |  |  |--java/
|  |  |  |--resources/

The source files go in src/main/java and the resource files go in src/main/resources.

When you build your project Maven will compile the source files and put the .class files in projectDir/target/classes. It will also copy any resource files from src/main/resources into target/classes as well. By default, any non-source files in src/main/java will be ignored. You mention you had put your styles.css file in src/main/java and thus it is not in target/classes when you run your project.

When you execute the project the directory target/classes (as well as any dependencies) is put on the classpath. But because your styles.css file wasn't copied into target/classes it is not included in the classpath and you end up getting NullPointerExceptions when trying to reference it.

The solution is to move the styles.css file into the src/main/resources directory. It looks like you currently have it under src/main/java/rocks/zipcode/atm. If you want to keep the resource file in the same "package" move it to src/main/resources/rocks/zipcode/atm. Then it should be copied to the target/classes directory when you rebuild your project.

Then you can reference it a couple of ways.

The first way is using getClass().getResource(...). If you pass an absolute path (starts with a /) it will look for the resource from the root of the classpath. If you don't pass an absolute path (doesn't start with a /) it will look for the resource relative to the Class's location (in this case, the Class is the one returned by getClass()). This means, since you're getting the resource from within rocks.zipcode.atm.CacheMachineApp, you could either do:

  • getClass().getResource("/rocks/zipcode/atm/styles.css"), or
  • getClass().getResource("styles.css")

The other option is to use the behavior defined in the documentation of getStylesheets():

Gets an observable list of string URLs linking to the stylesheets to use with this scene's contents.

The URL is a hierarchical URI of the form [scheme:][//authority][path]. If the URL does not have a [scheme:] component, the URL is considered to be the [path] component only. Any leading '/' character of the [path] is ignored and the [path] is treated as a path relative to the root of the application's classpath.

As you can see, when there is no scheme (e.g. file:, https:, etc.) it will look for the resource relative to the root of the the classpath. Since it is always relative to the root you need to pass the absolute path (but in this case it doesn't require a leading /).

getStylesheets().add("rocks/zipcode/atm/styles.css");

Important Note: Make sure you get the path completely correct. It is case sensitive when packaged in a JAR file. It may or may not be case sensitive when not packaged in a JAR file, but that is dependent on the underlying file system. Either way, it is best to match the case of the actual path in order to avoid any problems.


推荐阅读