Home > Net >  Java: how to add image references properly from a non-src folder
Java: how to add image references properly from a non-src folder

Time:07-29

it's again about VSCode and Java (I start learning it). I have a little test program that loads images and works fine when started in the VSCode IDE. I have also seen here that I must somehow load the pics from a "classpath" - so I added a classpath for the "pics" folder shown in the screenshot.

I see that the pics are loaded into the jar, but they are not found at runtime (maybe because of the sub-folder or because they are not in src - but I want to have them in a separate folder of course). See the source code also in the screenshot - how should I do better to have the jar working, but also can test the code in the IDE? At the moment i do like this:

PicLabel pl1 = new PicLabel(new File(
                "./pics/Screenshot from 2022-07-20 15-40-16.png"));

my folder setup

CodePudding user response:

new File is literal. It means file. Physically, on disk. Also, . means 'current working dir', which is whatever the dir is where the user starts your java process, i.e. who knows - you cannot rely on it being anything specific, thus, this code is doomed. It can't ever work. (Or rather, it only works if the user is following instructions to the letter and users don't work like that).

Given that java apps are distributed as jars, you want images to be entries in those jars. They aren't files, thus new File means you've lost.

The right move is to use MyClass.class.getResource("/pics/Screenshot.png").

This gets you a URL which you can pass to e.g. ImageIcon and the like. I have no idea what PicLabel is, but it'll probably take a URL. If it does not, there's:

try (InputStream in = MyClass.class.getResource("/pics/Screenshot.png") {
  // use 'in' here
}
  • if it doesn't take a URL, it takes an InputStream. And if that's not possible either, it's a silly API; stop using it, find a non-broken library instead.

This will look in the same place as where YourClass.class lives. Even if it is in a jar. Even if the current working dir isn't what you thought it was. Stick /pics/Screenshot.png inside the jar and the above line will 'find' it.

CodePudding user response:

Ok thank you, I did some tests following your example (PicLabel is just my own helper class giving me back a formatted JLabel with a pic and a frame in it):

when I create a folder "picccs" under src, I can access a resource pic there (b.png). But the question still is - is it also possible to have it in the pics folder (see screenshot above) beside src, where a.png is in? (there I get null as URL):

try {
    URL in_b = Gui.class.getResource("/picccs/b.png");  
    URL in_a = Gui.class.getResource("/pics/a.png");  
} catch (Exception e) {
    //TODO: handle exception
}

CodePudding user response:

I like to put the .png files in the resources folder and then load them with getResource as already mentioned. The project structure should use the standard Maven/Gradle configuration:

-- root/
  -- app/
    -- src/
      -- main/
        -- java/
          -- my.package.name/ (java files go here)
        -- resources/
          -- image/ (image files go here)

when the project builds, the contents of the resources directory will get added to the classpath and become available for loading.

Personally, I like to create a java class that implements the singleton pattern so I can reference the images multiple times but they only get loaded once (expensive operation). Lets assume I have three images, image_one.png, image_two.png, image_three.png, in the resources/image folder that I plan to use with JLabel objects. Then my class might look like this:

public class ImageLib {

    // single reference to ImageLib
    private ImageLib INSTANCE;

    // member for each image I want to use
    private ImageIcon imageOne;
    private ImageIcon imageTwo;
    private ImageIcon imageThree;

    // private constructor for singleton pattern
    private ImageLib() {
        imageOne = loadImageIcon("image/image_one.png"
        imageTwo = loadImageIcon("image/image_two.png"
        imageThree = loadImageIcon("image/image_three.png"
    }

    // static method to get the single instance
    public static ImageLib getInstance() {
        if (Objects.isNull(INSTANCE) {
            INSTANCE = new ImageLib();
        }
        return INSTANCE;
    }

    public ImageIcon getImageOne() {
        return imageOne;
    }

    public ImageIcon getImageTwo() {
        return imageTwo;
    }

    public ImageIcon getImageThree() {
        return imageThree;
    }

    // helper method to load .png into ImageIcon
    private ImageIcon loadImageIcon(String path) throws RuntimeException {
        try {
            URL url = getClass().getClassLoader().getResource(path);
            return new ImageIcon(url);
        } catch (NullPointerException e) {
            throw new RuntimeException(String.format("Failed to load image: %s", path));
        }
    {
}

Now we can get the .png as an ImageIcon from the ImageLib class multiple times, but it will only load once. For example, we can create multiple JLabel objects and set the icon:

ImageLib images = new ImageLib.getInstance();

JLabel labelOne = new JLabel("some message");
labelOne.setIcon(images.getImageOne());

JLabel labelTwo = new JLabel("some message");
labelTwo.setIcon(images.getImageOne());
  • Related