devxlogo

Loading Icons and Other Graphics into an Application Using a Resource Bundle

Loading Icons and Other Graphics into an Application Using a Resource Bundle

esource bundles are intended to provide locale-specific resources so that an application can customize data, usually strings, based on the country or language of the computing environment. Though mostly used to internationalize text, these resources do not have to be confined to strings. You can load icons and other graphics using a resource bundle, but you must implement your own resource bundle to do this. A good way to manage localized resources is to create a resource bundle for each specific type of resource. For example, you could have a separate resource bundle for error messages, menu labels, and images.

The java.util package includes ResourceBundle, an abstract class that implements most of what you need to create your own resource bundles. You simply have to override two of its methods, handleGetObject and getKeys, to create a custom ResourceBundle. The first method is a protected method that does the actual work of fetching an object based on a key value. The second method merely returns anEnumeration of all valid keys.

ResourceBundle also includes two static getBundle methods. These are used to load a resource bundle for a particular locale. getBundle looks for a resource bundle based on a base class name that includes the package name. If it can’t find the class corresponding to the given locale, it defaults to using the bundle defined by the base class name. Bundles for given locales are constructed by creating a class named by appending a suffix to the base class name. This suffix indicates the locale the class is supposed to handle based on a set of rules listed in the ResourceBundle documentation.

In the accompanying code listing, ImageBundle is the default resource bundle, and ImageBundle_fr is the resource bundle for the French locale. This example stores images in a directory called images that is included with the class distribution, either in a JAR file or as separate files. The ImageBundle loads files based on a naming scheme similar to that used for local-specific resource bundles. An image named image.gif is a default image, and an image named image_fr.gif is an image for the French locale. The base name of the image is used as a key for looking up objects in the ImageBundle. This is just a scheme I chose to simplify the example. Rather than load a new image every time, ImageBundle loads an image only the first time it is requested and then caches it in a Hashtable to speed up future lookups and avoid consuming extra memory.

package mypackage;import java.util.*;import java.net.*;import javax.swing.*;/*** * ImageBundle is a ResourceBundle that produces ImageIcon objects * based on the locale.  All the images are GIFs that end with the * .gif suffix.  GIF files are assumed to have the same base name as * the key used to look them up.  An underscore followed by the country * id is appended to the basename to generate the file name.  The * default locale, represented by ImageBundle, has no country id. ***/public class ImageBundle extends ResourceBundle {  private String __fileSuffix;  private static final Vector __KEYS;  private static Hashtable __TABLE;  static {     __KEYS  = new Vector();     __KEYS.addElement("language");     __TABLE = new Hashtable();  }  private ImageIcon __loadImage(String basename, String extension) {    String imageName = basename + __fileSuffix + extension;    ImageIcon icon;    URL url;    icon = (ImageIcon)__TABLE.get(imageName);    if(icon != null)      return icon;    url = ImageBundle.class.getResource("images/" + imageName);    if(url == null)      return null;    icon = new ImageIcon(url);    __TABLE.put(imageName, icon);    return icon;  }  protected ImageBundle(String suffix) {    __fileSuffix = suffix;  }  public ImageBundle() {    this("");  }  public Enumeration getKeys() {    return __KEYS.elements();  }  protected final Object handleGetObject(String key) {    // All of our files are GIFs named by key    return __loadImage(key, ".gif");  }}package mypackage;/*** Implements the French Image resource bundle.  ***/public class ImageBundle_fr extends ImageBundle {  public ImageBundle_fr() {    super("_fr");  }}import java.awt.*;import java.awt.event.*;import java.util.*;import javax.swing.*;import mypackage.*;public class ImageBundleDemo extends JFrame {  public ImageBundleDemo() {    ResourceBundle defaultResourceBundle, frenchResourceBundle;    ImageIcon icon;    defaultResourceBundle =       ResourceBundle.getBundle("mypackage.ImageBundle");    frenchResourceBundle  =       ResourceBundle.getBundle("mypackage.ImageBundle", Locale.FRANCE);    icon = (ImageIcon)defaultResourceBundle.getObject("language");    getContentPane().add(new JLabel(icon), BorderLayout.NORTH);    icon = (ImageIcon)frenchResourceBundle.getObject("language");    getContentPane().add(new JLabel(icon), BorderLayout.SOUTH);  }  public static final void main(String[] string) {    Frame frame;    WindowListener exitListener;    exitListener = new WindowAdapter() {      public void windowClosing(WindowEvent e) {        Window window = e.getWindow();        window.setVisible(false);        window.dispose();        System.exit(0);      }    };    frame = new ImageBundleDemo();    frame.addWindowListener(exitListener);    frame.pack();    frame.setVisible(true);  }        }
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist