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"));
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());