Time for action – using Images in JFace
The TimeZoneLabelProvider
can return an SWT Image
. Although they can be loaded dynamically as in the previous chapter, JFace provides a number of resource registries that can be used to manage a set of resources for the application. Standard registries include the ImageRegistry
, FontRegistry
, and ColorRegistry
classes. The purpose of a resource registry is to maintain a list of Resource
instances and ensure that they are correctly disposed when they are no longer needed.
JFace has a set of these global registries; but there are specific ones, for example, those used by the IDE to maintain folder and file type icons. These use resource descriptors as a lightweight handle for the resource, and a means to acquire an instance of the resource based on that descriptor. The returned resource is owned by the registry, and as such, should not be disposed by clients that acquire or use them.
Standard images can be acquired by injecting an ISharedImages
instance from the org.eclipse.ui
package.
- In the
TimeZoneTreeView
class, add an injected field of typeISharedImages
:@Inject private ISharedImages images;
- Update the call in the
create
method where theTimeZoneLabelProvider
is instantiated to pass the shared images as an argument:treeViewer.setLabelProvider(new TimeZoneLabelProvider(images));
- In the
TimeZoneLabelProvider
class, create a constructor that takes theISharedImages
instance and save it as aprivate final
field:private final ISharedImages images; public TimeZoneLabelProvider(ISharedImages images) { this.images = images; }
- Add a method called
getImage
that uses theimages
to provide the folder icon:public Image getImage(Object element) { if (element instanceof Map.Entry) { return images.getImage(ISharedImages.IMG_OBJ_FOLDER); } else { return super.getImage(element); } }
- Run the Eclipse instance, and open the Time Zone Tree View. A folder icon will be shown for each of the time zones in the view. The
Image
doesn't need to be disposed because it's owned by the provider of theISharedImages
instance (the images are disposed when thePlatformUI
shuts down): - To use a different image, either the global
ImageRegistry
fromJFaceRegistry
can be used, or one can be created. Although using the global one will work, it means that effectively theImage
never gets disposed, since theJFaceRegistry
will last for the lifetime of the Eclipse instance.Instead, create a
LocalResourceManager
instance based on theJFaceResources
resource manager, which is tied to the lifetime of the parent. When theparent
control is disposed, the images will be disposed automatically. These should be added to thecreate
method ofTimeZoneTreeView
:public void create(Composite parent) { ResourceManager rm = JFaceResources.getResources(); LocalResourceManager lrm = new LocalResourceManager(rm, parent);
- Using the
LocalResourceManger
, create anImageRegistry
and add anImageDescriptor
from a URL using thecreateFromURL
method:ImageRegistry ir = new ImageRegistry(lrm); URL sample = getClass().getResource("/icons/sample.gif"); ir.put("sample", ImageDescriptor.createFromURL(sample));
- Now that the
ImageRegistry
is populated, it must be connected up to theLabelProvider
so that it can show the right image on demand. Pass the image registry into the constructor of theTimeZoneLabelProvider
:treeViewer.setLabelProvider(new TimeZoneLabelProvider(images, ir));
- Modify the constructor in the
TimeZoneLabelProvider
to store theImageRegistry
, and use it to acquire the image in thegetImage
call:private
finalImageRegistry
images: private final ImageRegistry ir; public TimeZoneLabelProvider(ISharedImages images, ImageRegistry ir) { this.ir = ir; } public Image getImage(Object element) { if (element instanceof Map.Entry) { return images.getImage(ISharedImages.IMG_OBJ_FOLDER); } else if (element instanceof ZoneId) { return ir.get("sample"); } else { return super.getImage(element); } } - Now, when opening the view, the sample
gif
is used as a zone icon:
What just happened?
To start with, standard images (injected from the PlatformUI
plug-in) were used, with pre-defined descriptors from ISharedImages
. The names of the descriptors begin with IMG
, and then follow a pre-defined pattern:
etool
: Enabled toolbar iconsdtool
: Disabled toolbar iconselcl
: Enabled local toolbar iconsdlcl
: Disabled local toolbar iconsdec
: Decoratorobj
andobjs
: Objects such as file and folder icons
The ISharedImages
instance was injected into the part since the @Inject
annotation was present on the field. When E4 instantiates the view, it ensures that all the @Inject
dependencies are satisfied.
Note
What is injection?
JSR 330 standardized dependency injection annotations in the javax.inject
package, the most common of which is @Inject
. Dependency injection systems provide a Don't call us, we'll call you approach to wiring together dependent components, and this separates the component's implementation from knowing how to satisfy its own dependencies.
By annotating a field or method with @Inject
, when the class is instantiated by the dependency injection framework (E4 in this case), it will try and satisfy all the required dependencies (since this is achieved with introspection, the fields don't have to be exposed with setters or getters). It is the job of the dependency injection framework to know how to acquire or create the required dependencies; all the client code is concerned with is that there is a dependency injected into the code.
The net effect in this case is that when the TimeZoneTreeViewer
is instantiated, the dependency injection mechanism will automatically insert an appropriate ISharedImages
instance that has been acquired from elsewhere.
To use custom images instead, an ImageRegistry
was created, backed by a LocalResourceManager
. When a Control
is passed into the constructor, it registers itself as a DisposeListener
—so that when the control is disposed, so are the associated images. This also makes the code cleaner, because the ImageRegistry
can be passed into the TimeZoneContentProvider
.
Finally, the ImageRegistry
was initialized with a set of ImageDescriptor
objects—in this case, the icons/sample.gif
that came from the new plug-in project wizard. The same key is used when both initializing and accessing the image. Some Eclipse projects follow a convention of having an ISharedImages
interface with a set of constants. Other plug-ins have a similar set of images, such as JDT UI, which adds icons for packages, classes, methods, and fields.