2

I am trying to add a icon to a toolbar but what is the best place to put it in? My desktop or should I make a new file in the project file or add all the pictures in because it is not showing and this is my code:

 JToolBar toolBar = new JToolBar();
     String[] iconFiles = {"pen-icon","",""};
     String[] buttonLabels = {"New","Open","Save"};
     icon = new ImageIcon[iconFiles.length];
     Obutton = new JButton[buttonLabels.length];

     for (int i = 0; i < buttonLabels.length; ++i) {
      icon[i] = new ImageIcon(iconFiles[i]);
      Obutton[i] = new JButton(icon[i]);
      Obutton[i].setToolTipText(buttonLabels[i]);
      if (i == 3)
        toolBar.addSeparator();
         toolBar.add(Obutton[i]);
    }
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
isslam akkilah
  • 418
  • 1
  • 11
  • 23

2 Answers2

6

Resources of this type are typically best contained within the application context (such as a jar file). This reduces the chances of someone tampering with it as it's much more time consuming to unpack, modify and repack a jar file then simply replace a file. It also reduces what you need to distribute as it becomes self-contained.

These are known as embedded resources.

Where you would put them within this context is up to up, many people use a "resources" folder to store these types of files, but sometimes, you may want something that is relative to the context of the class. It's up to you.

This raises issues with loading these resources, as you can no longer reference them using something like File.

In general you can use Class#getResource(String), which returns a URL or Class#getResourceAsStream(String) which returns a InputStream. This provides you with all you need to load these embedded resources.

ImageIcon(String) expects the value to be a file reference, which means it won't work for embedded resources, but ImageIcon provides a constructor that takes a URL as a reference, this means you would need to use

icon[i] = new ImageIcon(getClass().getResource(iconFiles[i]));

To load your images.

Based on your example, the images would need to be relative to the class (ie within a directory structure the same as your package structure). How you achieve this will depend on your development environment.

Remember, you can also specify relative paths to getResource and even an absolute path in some contexts. An absolute path basic prefixes the elements of class path to the specified path when it searches for the resources.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
6

I would use an Action. Here is the AbstractAction constructor

  • public AbstractAction(String name, Icon icon) - Creates an Action with the specified name and small icon.

    Parameters:
    name - the name (Action.NAME) for the action; a value of null is ignored
    icon - the small icon (Action.SMALL_ICON) for the action; a value of null is ignored

The benefit of using an Action is that is can be reused for components with similar purposes. So say you want to have an icon button in the toolbar to open a file, and also have a JMenuItem in a JMenu that also opens a file. They could share the same action, thus sharing the same icon, action command, and action to perform.

Action action = new AbstractAction("someActionCommand", someIcon) {
    @Override
    public void actionPerformed(ActionEvent e) {
        // do something.
    }
};

toolbar.add(action);

The above will automatically put the icon for you, but not the String. In a JMenuItem it would put both the String and the icon.

Then just add the Action to the tool bar.


See more at How to use Actions


To answer you real question, as @MadProgrammer noted, you should be loading your images as an embedded resource, using

 ImageIcon icon = new ImageIcon(MyClass.class.getResource("/resources/images/image.png"));

where the /resources/images directory is in the src, and getResource() returns a URL. Upon build, your IDE should copy the files into the class path for you.

 ProjectRoot
           src
               resources
                       images
                             image.png

You'll come to find that when using a file from the file system, will not work upon time of deployment


Here's an example, where the JMenuItem and the JToolBar button share the same action. Notice that in the JToolBar all I have to do is add the Action, I don't need to create a button for it. The JToolBar automatically makes it a button, without the action command

I use this "open.gif" from the below file structure and use

ImageIcon icon = new ImageIcon(
            ActionTest.class.getResource("/resources/image/open.gif"));

enter image description here

Here's the result

enter image description here

Here's the code. Enjoy!

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class ActionTest {

    public ActionTest() {
        ImageIcon openIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/open.gif"));
        ImageIcon saveIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/save.gif"));
        ImageIcon newIcon = new ImageIcon(
                ActionTest.class.getResource("/resources/image/new.gif"));

        Action openAction = new AbstractAction("Open", openIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Open File");
            }
        };
        Action saveAction = new AbstractAction("Save", saveIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Save File");
            }
        };
        Action newAction = new AbstractAction("New", newIcon) {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("New File");
            }
        };

        JMenuItem openMenuItem = new JMenuItem(openAction);
        JMenuItem saveMenuItem = new JMenuItem(saveAction);
        JMenuItem newMenuItem = new JMenuItem(newAction);

        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.add(openMenuItem);
        fileMenu.add(saveMenuItem);
        fileMenu.add(newMenuItem);
        menuBar.add(fileMenu);

        JToolBar toolBar = new JToolBar();
        toolBar.add(Box.createHorizontalGlue());
        toolBar.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
        toolBar.add(newAction);
        toolBar.add(openAction);
        toolBar.add(saveAction);

        JFrame frame = new JFrame("Toolbar and Menu Test");
        frame.setJMenuBar(menuBar);
        frame.add(toolBar, BorderLayout.PAGE_START);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ActionTest();
            }
        });
    }
}
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • +1 for Actions, nice idea, doesn't quite answer the problem of missing resources though...but that's how I read the question ;) – MadProgrammer Jan 30 '14 at 03:15
  • 1
    @ManProgrammer I really need to start reading these question. Especially when they're _soo short_. I'm getting too used to just skimming these long descriptive question. – Paul Samsotha Jan 30 '14 at 03:19
  • 1
    And there, I thought I was the only one that did that ;) – MadProgrammer Jan 30 '14 at 03:22
  • *"I'm getting too used to just skimming these long descriptive question."* Oh, I'm worse than that. On occasions I will answer a question based on the ***title.*** Perhaps I should look around for duplicates before I answer such questions. ;) So @MadProgrammer, am I counted 'in or out' of the 'description browsing group'? – Andrew Thompson Jan 30 '14 at 04:07
  • 2
    @AndrewThompson Welcome aboard. It's always nice when the title doesn't match the question though :D – MadProgrammer Jan 30 '14 at 04:08
  • thank you a lot but do i have to create a new class because i am using one class for the gui and another Package for image – isslam akkilah Jan 30 '14 at 05:05
  • also i am using png images is it ok – isslam akkilah Jan 30 '14 at 05:08
  • @isslamakkilah what do you mean new class? No matter what package your class is in, the image should still load using the same relative path, as long as they're within the same project – Paul Samsotha Jan 30 '14 at 05:10
  • @isslamakkilah yes `.png`s are fine – Paul Samsotha Jan 30 '14 at 05:13
  • but there is wrong with the class Exception in thread "main" java.lang.NullPointerException at javax.swing.ImageIcon.(ImageIcon.java:205) at AnimeAid.GuiInterface.(GuiInterface.java:62) at AnimeAid.GuiInterface.main(GuiInterface.java:44) Java Result: 1 – isslam akkilah Jan 30 '14 at 07:21
  • @Isslamakkilah look at my file structure and the code. from the image. It should work fine. You are getting the null pointer because it can't find the image. make sure your path is correct, and you directory you use is in the src – Paul Samsotha Jan 30 '14 at 07:25
  • also did you add new package and add the image to it or what happen in this case – isslam akkilah Jan 30 '14 at 07:25
  • @isslamakkilah yeah I just added a package and named it `resources.image`. That will make the file structure `src/resources/image/open.gif` – Paul Samsotha Jan 30 '14 at 07:28
  • I removed the line toolbar.(Box.creatHorzonal...) to move the icon to the left but what is this class for "box" – isslam akkilah Jan 30 '14 at 13:35
  • The only reason I used it _was_ to align it to the right so you could still see it in the image when I open the File menu. You did the right thing by moving it back to the left. Basically a `JToolBar` uses a default `BoxLayout`. `Box` is just a convenience class for `BoxLayout`. You can read more about [`createGlue()`](http://docs.oracle.com/javase/7/docs/api/javax/swing/Box.html#createGlue%28%29) – Paul Samsotha Jan 30 '14 at 13:39
  • @peeskillet can you talk to me in chat please Mr hero i need some information form you about the ability of java to do some project – isslam akkilah Jan 30 '14 at 20:52
  • @peeskillet ok are you available now – isslam akkilah Jan 31 '14 at 15:57
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/46528/discussion-between-peeskillet-and-isslam-akkilah) – Paul Samsotha Jan 31 '14 at 15:57
  • @peeskillet are you online now – isslam akkilah Feb 02 '14 at 23:54
  • @isslamakkilah go to chat if you're online – Paul Samsotha Feb 03 '14 at 03:11