Time for action – drawing a custom view

An SWT Canvas can be used to provide custom rendering for a view. As a starting point for drawing a clock, the Canvas will use drawArc() to create a circle.

  1. Remove the content of ClockView leaving behind an empty implementation of the setFocus() and createPartControl() methods.
  2. Run the target Eclipse instance and see that ClockView is now empty.
  3. In the createPartControl() method, do the following:
    1. Create a new Canvas, which is a drawable widget.
    2. Add PaintListener to the Canvas.
    3. Get gc from PaintEvent and call drawArc() to draw a circle.

    The code will look like:

    import org.eclipse.swt.*;
    import org.eclipse.swt.events.*;
    import org.eclipse.swt.widgets.*;
    import org.eclipse.ui.part.ViewPart;
    public class ClockView extends ViewPart {
      public void createPartControl(Composite parent) {
        final Canvas clock = new Canvas(parent,SWT.NONE);
        clock.addPaintListener(new PaintListener() {
          public void paintControl(PaintEvent e) {
            e.gc.drawArc(e.x,e.y,e.width-1,e.height-1,0,360);
          }
        });
      }
      public void setFocus() {
      }
    }
  4. Run the Eclipse instance and show the Clock View.
  5. Resize the view and the clock should change size with it:
    Time for action – drawing a custom view

What just happened?

In SWT, the widget used for custom drawing is Canvas. The view is constructed with a call to createPartControl(), which is invoked once when the view is shown for the first time. If the view is minimized, then maximized, this is not invoked again; however, if the view is closed and a new view is opened, then a call will be made to a new instance of ClockView to initialize it.

Unlike other Java GUI frameworks, a widget is not added or removed to a containing parent once created; the widget's parent is specified at construction time. Thus, instead of creating it with an empty constructor and then adding it, the parent is passed into the widget's constructor.

Note

There is also a style flag that is passed in. This is used by widgets in different ways; for example, the Button widget takes various flags to indicate whether it should be rendered as a push button, radio button, checkbox, toggle, or arrow. For consistency, in SWT all widgets have an int style flag, which enables up to 32 bits of different options to be configured.

These are defined as constants in the SWT class; for example, the checkbox button style is represented as SWT.CHECKBOX. Options can be combined; to specify a flat button, one would bitwise or the values of the two fields together:

new Button(parent,SWT.PUSH|SWT.FLAT)

Generally, the value SWT.NONE can be used to represent default options.

The code adds an empty Canvas to the view, but how can it be drawn on? SWT does not expose a paint method on any of its widgets. Instead, PaintListener is called whenever the canvas needs to be repainted.

Note

All in the name of performance

You may wonder why all these little things are different between the way SWT handles its widgets versus how AWT or Swing handle them. The answer is in the name of speed and delegation to native rendering and controls if at all possible. This mattered back in the early days of Java (Eclipse 1.0 was released when Java 1.3 was the most advanced runtime available) when neither the JITs nor the CPUs were as powerful as today.

Secondly, the goal of SWT was to offload as much of the processing onto native components (like AWT) and let the OS do the heavy work instead of Java. By doing that, the time spent in the JVM could be minimized while allowing the OS to render the graphics in the most appropriate (and performant) way. The paint listener is one such example of how to avoid performing unnecessary drawing-related calls unless a component actually needs it.

The paintControl() method is invoked with a PaintEvent argument, which contains references to all the data needed to draw the component. To minimize method calls, the fields are publicly readable (not considered to be a good style, but certainly performant in this case). It also contains a reference to the graphics context (GC) which can be used to invoke drawing commands.

Finally, the event also records the region in which the paint event is to be fired. The x and y fields show the position of the top-left to start from, and the width and height fields of the event shows the drawing bounds.

In this case, the graphics context is set up with the necessary foreground color, and drawArc() is called between the bounds specified. Note that the arc is specified in degrees (from 0 with a 360 span) rather than radians or any other measure.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset