0

I am trying to set a JFrame icon. I have tried all the suggested solutions here and here , but have not yet had success.

In my method below you can see all the solutions attempted:

1 and 2 do not set an icon (I still see the coffee cup).

3 and 6 get this error:

The method setIconImage(Image) is undefined for the type Icon 

4 gets this error:

java.lang.NullPointerException

5 get:

Type mismatch: cannot convert from URL to DocFlavor.URL

My calling class is here:

/Users/lawrence/eclipse-workspace/COA_Application/src/main/java/misc/Icon

My image is here:

/Users/lawrence/eclipse-workspace/COA_Application/Logo.png 

(I have also tried COA_Application/src/main/resources/Logo.png)

I am a beginner so apologies if I am being slow. Note also I am using a mac.

package misc;

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;

import javax.imageio.ImageIO;
import javax.print.DocFlavor.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.google.api.services.sheets.v4.model.Color;

public class Icon {
    
    static String filepath = "/Logo.png";
    
    public void showFrame() throws IOException {
        
        JFrame frame = new JFrame("Icon frame");
        
        //method 4
    frame.setIconImage(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(filepath)));
        
         //method 1
        //BufferedImage myPicture = ImageIO.read(new File(filepath));
        //frame.setIconImage(myPicture);
        
        //method 2
        //frame.setIconImage(ImageIO.read(new File(filepath)));
        
        //method 3
        //setIconImage(new ImageIcon(filepath).getImage());
        
        //method 5
        //URL url = getClass().getResource(filepath);
        //frame.setIconImage(imgicon.getImage());
        
        //method 6
        //ImageIcon img = new ImageIcon(getClass().getClassLoader().getResource("./icon.png"));
        //setIconImage(img.getImage());
        
        JPanel panel = new JPanel();
        frame.add(panel);
        
        frame.pack();
        frame.setSize(new Dimension(600,600));
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    public static void main(String[] args) throws Exception {
        
        Icon obj = new Icon();
        obj.showFrame();
    }
}

Image: My icon

R.Donohoe
  • 59
  • 8
  • The folder holding the image has to be on the classpath for some of these methods to work. – Gilbert Le Blanc Feb 24 '21 at 15:00
  • Step 1 should work. ImageIO will generate an I/O Exception message if the image can't be found. Also, make sure the image is a proper size. I think it should be 16x16 or maybe 32x32. See if the image can be displayed as an Icon on a JLabel. If it displays on the label but not the frame icon then the size is probably the issue. – camickr Feb 24 '21 at 15:28
  • Gilbert - the image is in my application/target/classes, which I understand to be the classpath, but the methods don't work. Camickr - I have resized the image to 16x16 pixels (also smaller), but still not working. It does display on a JLabel – R.Donohoe Feb 24 '21 at 17:05
  • 1
    If you're aware of `getClass().getResource(filepath)` you must have also stumbled across the fact that an embedded resource (not available as a `File`) need to be referenced from either the root of the class-path or a location relative to the package of the calling class. We don't know that the directory / package structure of the locations of the image **or** the class, so I don't see how you think we can help. – Andrew Thompson Feb 25 '21 at 09:14
  • My calling class is here: /Users/lawrence/eclipse-workspace/COA_Application/src/main/java/misc/Icon . My image is here: /Users/lawrence/eclipse-workspace/COA_Application/Logo.png (I have also tried COA_Application/src/main/resources/Logo.png . Does that answer your question? – R.Donohoe Feb 25 '21 at 14:12
  • *"Does that answer your question?"* [edit] the information into the question. I'm not clear what the root of the class-path is. Providing the `package ..` line of the class should help clarify that (the first part of the `..` should be in the root of the class-path. To have `getResource` presume the path should be found from the root of the class-path, prefix it with `/`. I find it a lot more reliable to go from the root, than use a path relative to the class. – Andrew Thompson Feb 25 '21 at 14:17
  • I have tried "../Logo.png" and still no icon. Note: In order to get past the 'static reference' error blocking the getResource method, I have moved everything into the main method, created an object of the class ('obj') and changed the line to frame.setIconImage(Toolkit.getDefaultToolkit().getImage(obj.getClass().getResource(filepath))); Hope this is correct – R.Donohoe Feb 25 '21 at 15:25
  • 1
    I went through the question and edited to use code formatting on both the paths and compilation errors. Only now do I realise how much you've been trying anything you see / can think of, yet not understanding the problem or knowing how to fix it. Part of the problems described are because of `static` declarations. That stuffs up trying to get access to resources, as well as other things. It's the first thing that should be fixed, by removing the `static` keyword and creating an instance of the class to use for calling the `showFrame` method, then within the method.. – Andrew Thompson Feb 25 '21 at 16:16
  • 1
    .. we can use something like `this.getClass()..` without compilation problems (and in a form where it might work, subject to the correct path). But here is where I get stuck, you did not provide the `package` statement so I am still not sure where the root of the class-path is. I *suspect* the the image is located outside the class-path, never built into the Jar, and therefore unavailable via `getResource`.. – Andrew Thompson Feb 25 '21 at 16:18
  • Thanks for your patience; clearly I need to do some homework! The package statement is: package miscPackage; . The first part of the output of System.out.println(System.getProperty ("java.class.path")); is /Users/lawrence/eclipse-workspace/COA_Application/target/classes , my png file is in there – R.Donohoe Feb 25 '21 at 16:45
  • *"The package statement is: package miscPackage;"* Wait .. *what?* I expected the package to be (assuming the class name is `Icon`) something like `package misc;` or `package main.java.misc;`. Please post a [mre] of code. It should include the `package` statement and class name. – Andrew Thompson Feb 25 '21 at 17:32
  • Sorry for confusion - I'd renamed the package in an attempt to fix. I've changed it back to 'misc' now and updated the code above – R.Donohoe Feb 26 '21 at 09:08
  • Apologies, I'll be more accurate in future. I'm aware of the time I am taking you, and don't want to ask too much, so perhaps we should leave this unresolved. The first fix did not work. I have not packaged anything in jars as yet, I am running my application from eclipse – R.Donohoe Feb 26 '21 at 10:49
  • 1
    *"I am running my application from eclipse"* Are you certain that Eclipse is not making a Jar? Then check the place (directory) it puts 'classes and resources'. I suggested that because IDE's will only include resources (copy them) onto the run-time class-path if they are in particular starting directories. `resources` is a typical directory name for such to happen, but I'm not positive Eclipse uses it. – Andrew Thompson Feb 26 '21 at 11:56
  • It could well be making a jar, not sure where I would find that however. I'm using Maven so I think the paths are src/main/java for classes and src/main/resources for resources. My icon file is in the latter – R.Donohoe Feb 26 '21 at 15:11
  • *"I think the paths are src/main/java"* An IDE typically has source code in one path, but classes in another. Use the desktop file manager to go in there and have a look around. – Andrew Thompson Feb 26 '21 at 15:59
  • I can see a 'classes' folder in eclipse-workspace > COA_Application (my project) > target > classes. Could that be it? My png is already in there, however. There is no 'resources' folder there, or anywhere else in my project other than 'src'. – R.Donohoe Feb 26 '21 at 16:55
  • Huh.. so is the image in the root of `classes`? – Andrew Thompson Feb 26 '21 at 17:27
  • Yes. It's in 3 places actually - (1) COA_Application, (2) COA_Application > target > classes, (3) COA_Application > src > main > resources. – R.Donohoe Feb 26 '21 at 17:42
  • O...K so have you tried `"/Logo.png"`? – Andrew Thompson Feb 26 '21 at 19:29
  • Yes - when I use "Logo.png" I get a null pointer exception, when I use "/Logo.png" the program launches but with a coffee cup icon – R.Donohoe Feb 27 '21 at 07:58

1 Answers1

1

Application resources will become embedded resources by the time of deployment, so it is wise to start accessing them as if they were, right now. An must be accessed by URL rather than file. See the info page for embedded resource for how to form the URL.

Of course, the devil is in the details. The (upper / lower) case used for the path and resource name must be exactly as they are on the file system. The easiest way to make getResource(..) to works is to use a path from the root of the class-path. Specifying 'from the root' is done by prefixing the path with /.

Example using latest code (loads the icon from URL):

import java.awt.*;
import javax.swing.*;
import java.net.*;

public class Icon {
    
    public void showFrame() throws Exception {
        JFrame frame = new JFrame("Icon frame");
        
        URL url = new URL("https://i.stack.imgur.com/bQ8fP.png");
        frame.setIconImage(Toolkit.getDefaultToolkit().getImage(url));
        
        frame.pack();
        frame.setSize(new Dimension(400,100));
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    public static void main(String[] args) throws Exception {
        Icon obj = new Icon();
        obj.showFrame();
    }
}

enter image description here

Edit:

Given it works perfectly here, I'm starting to think the problem is the particular JRE being used.

I have just built and installed my application and it has the correct icon!

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Andrew - no sorry, not sorted yet. There's no null pointer exception, but I still have the default icon (not the one I'm trying to set). The embedded resource solution seems to refer to method 5 above, for which I get this error: 'Type mismatch: cannot convert from URL to DocFlavor.URL' – R.Donohoe Mar 01 '21 at 11:44
  • Ugh.. that seems obvious when I read what I quoted, again. My bad. OK .. can you create a new MRE, and upload this image to the question? I've not before seen a problem with loading a PNG image in Java (once there is a valid URL to it), but there is always a first time. – Andrew Thompson Mar 01 '21 at 12:37
  • No worries. I think you're saying to update my MRE above and attach my icon, which I've now done. Let me know if you meant to create a fresh post or something else – R.Donohoe Mar 01 '21 at 15:36
  • Report back the result you get when running the code after *"Example using latest code (loads the icon from URL):"* at the end of my answer.. – Andrew Thompson Mar 01 '21 at 16:47
  • Seriously? Given it works perfectly here, I'm starting to think the problem is the particular JRE being used. – Andrew Thompson Mar 01 '21 at 17:32
  • You were right - I have just built and installed my application and it has the correct icon! Not a problem that it doesn't show in Eclipse. Thanks for all your help Andrew, really appreciate it – R.Donohoe Mar 02 '21 at 14:20
  • *"I have just built and installed my application and it has the correct icon!"* Congrats! I've edited the solution into my answer (just quoting your comment). *"Thanks for all your help Andrew"* A great way to show gratitude, as well as make the question & answer more prominent to others searching later, is to accept the answer (as noted above in my first comment on the answer). – Andrew Thompson Mar 02 '21 at 14:59