9-Custom SWT Controls
9-Custom SWT Controls
by Shantha Ramachandran
Department of Computer Science, University of Manitoba, Winnipeg, Manitoba, Canada
Overview:
Tutorials 2 and 3 described the pre-defined SWT controls. Eclipse developers may also
define custom controls that provide additional functionality. There are two different
types of custom controls: basic widgets and compound widgets. In this tutorial, we
examine a simple example of both types of widgets, and a more complex example which
deals with event handling as well. We also briefly examine custom layout managers.
There are a number of Custom Controls that have already been implemented in Eclipse.
These include CCombo, CLabel, CTabFolder, SashForm, StyledText and TableTree. To
view these controls in action, first install the Examples plugin for Eclipse (see
http://www.eclipse.org/downloads/index.php for how to install the Examples). After the
Examples have been installed, click on Window -> Show View -> Other… From the
window that appears, expand SWT Examples and click on SWT Custom Controls.
1
This work was funded by an IBM Eclipse Innovation Grant.
2
© Shantha Ramachandran and David Scuse
There are two different ways to create your own controls in Eclipse. The first is by
subclassing Canvas, and the second is by subclassing Composite. Canvas is subclassed
when you wish to draw basic widgets. This means that you do not need to use any other
widgets within your control, but instead will draw the specific elements of your custom
control onto a canvas. Composite is subclassed when you wish to group together a
number of basic controls to create a larger or more functional control, called a compound
widget.
Basic Widgets:
A custom control should subclass Canvas when the control can be drawn out by itself.
The Canvas widget allows a blank working space on which you can draw out your
widget. By creating a graphics context, you are provided with a number of methods that
allow you to draw your control.
Suppose we need to build a label which has a customizable border. To build this label,
which is a basic widget, we first need to subclass Canvas and give the widget a
constructor.
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e){
BorderLabel.this.paintControl(e);
}
});
To draw the widget, we need to next create the paintControl method. In this method, we
create a graphics context which will do all of the drawing. In the following code, we draw
void paintControl(PaintEvent e) {
GC gc = e.gc;
Point pt = this.getSize();
if (text != null) {
gc.drawString(text,size,size);
}
if (size > 0) {
gc.setLineWidth(size);
gc.setLineStyle(style);
gc.drawRectangle(0,0,pt.x-size,pt.y-size);
}
}
Now our widget can be drawn. All we need to do is add access methods that allow the
user to set the text and the style of the border for the label.
The redraw method that is called in each set method will queue a paint event for the
widget. This event causes the PaintListener to execute its paintControl method, and the
widget is redrawn. Now lets look at an example that uses our custom BorderLabel
widget:
shell.open();
while(!shell.isDisposed()){
if(!display.readAndDispatch())
display.sleep();
}
display.dispose();
When we run this program, we get a label with a 5 pixel sold border around the edge.
There are many other properties to a custom basic widget that you are free to implement,
such as finding the preferred size of the widget. For more information, see the article on
the Eclipse website Creating Your Own Widgets Using SWT.
Compound Widgets:
Compound widgets should be used when you want to create a widget out of other
widgets. When you create a compound widget, you need to subclass Composite. Contrary
to basic widgets, where you draw the widgets themselves, compound widgets are made
up of other basic widgets. No drawing is involved. The Composite holds the other
widgets together to form one complex widget.
To illustrate how to create a compound widget, we will create the same widget over
again, the BorderLabel. This time, it will be a compound widget.
Once again, the first thing we need to do is to create a constructor. In this widget, we will
use a label and a group. We can initialize the widgets in the constructor as well. To make
this example simplest, we will use a FillLayout to lay the widgets out within the control.
In the case of compound widgets, we do not need to draw anything. All we need to finish
off the widget is to add set methods. Note that this widget is simpler than the basic widget
we just created as we can only set the text, not the border size or style.
shell.open();
while(!shell.isDisposed()){
if(!display.readAndDispatch())
display.sleep();
}
display.dispose();
Once again, there are other methods that can be implemented for a compound widget. For
example, if you do not wish to use a layout, you can implement a method that will
position your children on a resize. For more information on compound widgets, see the
article on the Eclipse website Creating Your Own Widgets Using SWT.
By looking at the previous two examples, you can hopefully differentiate between a basic
and a compound widget. You should also be able to create a simple custom control. Next,
we will go over an example of a more complex widget that uses event handlers as well.
Suppose that we want to display images on a screen. However, we want these images to
be zoomed from small to large. Also, when the images get bigger, we want to be able to
scroll the image to see all of it. To do this, we will create a zoomed scrolled canvas
widget that subclasses composite. This widget will contain a canvas, scrollbars, and a
scale all grouped together in one composite.
If you looked at the Eclipse custom controls that have already been created, you will
notice that a ScrolledComposite is one of the custom controls available for use. For the
next example, we will cheat a little and use the ScrolledComposite custom control within
our own custom control, instead of building it from scratch.
In our constructor, we create all our widgets, and give our control a Grid Layout. This
will allow us to place the controls in specified positions. We need to do one more thing in
our constructor though. We have to initialize and place the widgets. This can be done by
calling setup methods from the constructor. We will have a setup method for the
composite, the scale and the label.
To setup the composite, we simply give it layout data to expand horizontally and
vertically within the widget. We also attach the canvas to the composite so that we can
draw the image within the scrollbars.
To setup the scale, we need to specify the maximum, minimum, the increment, and the
current selection. We also need to give it layout data.
canvas.setSize(comp.getSize().x, comp.getSize().y);
canvas.setLocation(0,0);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
GC gc = e.gc;
width = comp.getSize().x;
height = comp.getSize().y;
gc.drawImage(image, 0, 0,
image.getBounds().width,
image.getBounds().height,
0, 0, canvas.getSize().x,
canvas.getSize().y);
}
});
canvas.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
image.dispose();
}
});
redraw();
}
Remember we placed a paint listener on our canvas, so when the canvas is resized in the
selection listener, the paint listener will generate a PaintEvent and the image will be
drawn to its new size.
scale.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent arg0) {
zoom.setText("Zoom Factor = " +
(scale.getSelection()-50));
int newWidth = width * (scale.getSelection())/50;
int newHeight = height * (scale.getSelection())/50;
canvas.setSize(newWidth, newHeight);
}
});
This is the last step to creating our custom zoomed scrolled image widget. To see the
widget in action, we use it in exactly the same way as we would use any widget.
shell.open();
while(!shell.isDisposed()){
if(!display.readAndDispatch())
display.sleep();
}
display.dispose();
We set the size and position of our widget just as we would with a basic widget. The only
custom parameter we must set is the image. We set the image to be cats.JPG. The
following screen is generated from this code:
When we move the zoom scale up, the image gets larger and we can scroll through it:
Custom Layouts
In the same fashion that you can create custom widgets, you can also create custom
layouts to arrange your widgets in a specific manner. Before building a custom layout
manager, make sure that the layouts provided by SWT are not sufficient and that a
custom layout really is necessary.
The following is an example to show how to build a simple layout. This example creates
a layout that arranges widgets in a square, so we’ll call it the SquareLayout. It will take
the widgets on a composite and arrange them row by row in a square format. The widgets
will fill the space of the composite.
The first thing we need to do is subclass the Layout class. We will add fixed values for
the margin and the spacing between the widgets on the composite.
// constructor
public SquareLayout() {
super();
}
}
The next thing we will do is override the layout method. This is the method that will
actually lay out the widgets on the composite. But before we can know where to lay the
child widgets, we need to know the size of the widgets, and the size that the composite is
going to be.
We will create a method called initialize. In this method, we will figure out how many
widgets will be in a row or a column. Since we are creating a square, these numbers are
the same. If we find the square root of the total number of children, and round this
number up, we will get the number of rows or columns.
After completing the initialize method, we can now create our layout method. Here, all
we need to do is place the widgets, taking margins and spacing into account. Since we
know the size that the widgets must be from our initialization, we can simply specify the
coordinates of the widgets.
One thing to note is that if the composite size is set to be larger than our calculated size,
we will choose the larger size and grow the widgets to fit.
After we have completed this, the only thing left to do is override the ComputeSize
method. This will return the preferred size of the composite using your layout.
We will create a sample program to test our layout. In this program, we will create four
buttons. The layout should arrange the four buttons in a square:
shell.pack();
shell.open();
while(!shell.isDisposed()){
if(!display.readAndDispatch())
display.sleep();
}
display.dispose();
Note that if the number of widgets is not a perfect square, there will not be an even
number of widgets in each row and column:
There are many other things you can do with your custom layout. For more information,
see the online articles Creating Your Own Widgets Using SWT and Understanding
Layouts in SWT.