SWT provides a graphics engine for drawing graphics and displaying images in widgets. You can get pretty far without ever programming to the graphics interface, since widgets handle the painting of icons, text, and other data for you. However, if your application displays custom graphics, or if you are implementing a custom drawn widget, then you will need to understand some basic drawing objects in SWT.
The graphics context, GC, is the focal point for SWT graphics support. Its API describes all of the drawing capabilities in SWT.
A GC can be used for drawing on a control (the most common case), on an image, on a display, or to a printer. When drawing on a control, you use the GC supplied to you in the control's paint event. When drawing on an image, display, or printer, you must create a GC configured for it, and dispose of the GC when you are finished using it.
Once you've got a GC, you can set its attributes, such as color, line width, and font, which control the appearance of the graphics drawn in the GC.
The API Reference for GC describes the complete set of graphics functions.
The Font and FontData classes are used when manipulating fonts in SWT.
FontData describes the characteristics of a font. You can create a FontData by specifying a font name, style, and size. FontData includes API for querying these attributes. Since FontData does not allocate any OS resources, you do not need to dispose of it.
The Font is the actual graphic object representing a font that is used in the drawing API. You create a Font for a Display by specifying the Display and the FontData of the font that you want. You can also query a Font for its FontData.
You must dispose of an allocated Font when you are finished using it.
Colors are similar to fonts. You create a Color for a Display by specifying the RGB values for the desired color. You must dispose of an allocated color when you are finished using it.
The Display method getSystemColor(int)
allows you to query the predefined
system colors for the OS platform. You should not free colors obtained using
this technique.
The color model is discussed in detail in the article SWT color model.
The Image, ImageData, and ImageLoader classes are used when manipulating Images in SWT.
ImageData describes the actual pixels in the image, using the PaletteData class to describe the utilized color values. ImageData is a device- and platform-independent description of an image.
ImageLoader loads and saves ImageData in different file formats. SWT currently supports loading and saving of image formats including BMP (Windows Bitmap), ICO (Windows Icon), JPEG, GIF, and PNG.
The Image is the actual graphic object representing the image that is used in the drawing API. You create an image for a particular Display. Images can be created in several ways:
Regardless of how you create the Image, you are responsible for disposing it.
Most of the graphics objects used for drawing in SWT allocate resources in the underlying OS and must be explicitly freed. The same rule discussed earlier applies here. If you create it using a constructor, you should free it. If you get access to it from somewhere else, do not free it.
Graphics objects such as graphics contexts, fonts, colors, and images are allocated in the OS as soon as the object is created. How you plan to use your graphics objects determines when you should create them.
For graphics objects that are used heavily throughout the application, you can create them at the time that you create your widgets. This is commonly done for colors and fonts. In other cases, it is more appropriate to create your graphics objects on the fly. For example, you might create a graphics context in one of your widget event handlers in order to perform some calculations.
If you are implementing a custom widget, you typically allocate graphics objects in the constructor if you always make use of them. You might allocate them on the fly if you do not always use them or if they are dependent upon the state of some attribute.
Once you have allocated your graphics objects, you are ready to paint. You should always do your painting inside of a paint listener. There are rare cases, particularly when implementing custom widgets, when you paint while responding to some other event. However this is generally discouraged. If you think you need to paint while handling some other event, you should first try to use the redraw() method, which will generate another paint event in the OS. Drawing outside of the paint method defeats platform optimizations and can cause bugs depending upon the number of pending paints in the event queue.
When you receive a paint event, you will be supplied with a GC pre-configured for drawing in the widget. Do not free this GC! You did not create it.
Any other graphics objects must be allocated while handling the event (or beforehand). Below is a snippet based on the org.eclipse.swt.examples.HelloWorld5 sample. The color red was previously allocated when creating the widget, so it can be used here.
shell.addPaintListener (new PaintListener () { public void paintControl (PaintEvent event) { GC gc = event.gc; gc.setForeground (red); Rectangle rect = event.widget.getClientArea (); gc.drawRectangle (rect.x + 10, rect.y + 10, rect.width - 20, rect.height - 20); gc.drawString (resHello.getString("Hello_world"), rect.x + 20, rect.y + 20); } });
Every graphics object that you allocate must be freed when you are finished using it.
The timing of the disposal depends upon when you created the object. If you create a graphics object while creating your widget, you should generally add a dispose listener onto the widget and dispose of the graphics when the widget is disposed. If you create an object on the fly while painting, you should dispose of it when finished painting.
The next code snippet shows a slightly modified version of our paint listener. In this example, it allocates and frees the color red while painting.
shell.addPaintListener (new PaintListener () { public void paintControl (PaintEvent event) { GC gc = event.gc; Color red = new Color (event.widget.getDisplay (), 0xFF, 0, 0); gc.setForeground (red); Rectangle rect = event.widget.getClientArea (); gc.drawRectangle (rect.x + 10, rect.y + 10, rect.width - 20, rect.height - 20); gc.drawString (resHello.getString ("Hello_world"), rect.x + 20, rect.y + 20); red.dispose (); } });
If a resource is detected to not have been disposed then
Resource.setNonDisposeHandler
can be used to have custom logging or error handling of that case. A default
non-disposed handler which prints the error to System.err
can be
enabled with the org.eclipse.swt.graphics.Resource.reportNonDisposed
property set to true
. When the Eclipse IDE is run, this is logged
to the workbench log instead of System.err
.