1

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>

Jonathan Hinds
  • 305
  • 2
  • 13
  • Can you please let us know where is your class sitting in the heirarcy. Is it CashMachineApp ? – Sai Dandem Nov 05 '18 at 02:31
  • How are you building your app? Are you using a build tool such as Maven or Gradle? If so, resources should go in `src/main/resources` not `src/main/java`. Most build tools will ignore non `.java` files in the `src/main/java` directory by default. – Slaw Nov 05 '18 at 03:02
  • 1
    Also, if you pass a `String` with no protocol to `getStylesheets().add(...)` it will look for it on the classpath—but it requires the _absolute path_. – Slaw Nov 05 '18 at 03:03
  • @Slaw Yes I am using Maven, and the package is arranged the way I received it from my school. The class which is trying to use the stylesheet is CashMachineApp. – Jonathan Hinds Nov 05 '18 at 03:33
  • 1
    Check the `target/classes` directory to see if your CSS file(s) was copied there when you built the project. – Slaw Nov 05 '18 at 03:35
  • I just checked and found it is not there, though I'm not really sure what this means? also, thank you for the quick response @Slaw – Jonathan Hinds Nov 05 '18 at 03:36
  • Can you post your POM file (`pom.xml`)? I'm thinking your school/class made a mistake putting the CSS files under `src/main/java`. Are other students having this problem? – Slaw Nov 05 '18 at 03:41
  • I don't believe this to a mistake of the school, they essentially gave us an already created javaFX project and asked us to improve it somehow, I put the files in the java directory as I thought that is where it would be easiest to access. I've updated with the pom.xml I believe you are speaking of. – Jonathan Hinds Nov 05 '18 at 03:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183100/discussion-between-jonathan-hinds-and-slaw). – Jonathan Hinds Nov 05 '18 at 04:03

3 Answers3

5

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.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • You are a life saver @Slaw, your detailed explanation along with this post here https://stackoverflow.com/questions/18717038/adding-resources-in-intellij-for-maven-project where exactly what I needed. Thank you so much for such a detailed response, I truly appreciate it mate. – Jonathan Hinds Nov 05 '18 at 05:33
0

If your css file is sitting in the same package of your class:

scene.getStylesheets().add(getClass().getResource("style.css").toString());
Sai Dandem
  • 8,229
  • 11
  • 26
-1

What worked for me was adding "//" at the beginning of the 'path from content' Like this:"//src/practice/Viper.css"

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31152642) – Halo Mar 01 '22 at 15:35