SWT Tips and Tricks: Part 1 - Window and Dialog Initialization
Introduction
SWT is an emerging Java GUI toolkit that gives Java developers access
to the operating system's native widgets in a cross-platform manner.
I have had the pleasure of using the toolkit in several major projects
now, and I have come to see its strengths and its weaknesses. I have also
found myself implementing certain tasks repeatedly, so this series of
articles endevors to share a few of the insights I have gained to make
working with this toolkit more rewarding.
So, for the disclaimer - this article isn't a comparison between SWT
and Swing. It is not a comparison between SWT and JFace either. The
following tips are for developers building SWT-based applications.
Window and Dialog Initialization
It seems that every time I design a new composite or dialog box with
SWT I end up doing the same mundane tasks. Usually I set the tab
order of each parent composite to contain the widgets I want in the
tab loop. Granted, you don't have to set the tab order explicitly if you construct
your objects in the correct order, but most of the time I want to leave
a few controls out of the tab order completely, or I don't want to have to
modify already written code. Setting the tab order isn't hard:
parent.setTabList(new Control[] {
text1, text2, combo1, button1
});
I then go on to set the maximum length for all the text controls - especially
if the data is get pushed into a database back-end eventually. This is also
easy enough, and if you use a GUI builder, chances are that you can set
this property there.
text1.setTextLimit(100);
text2.setTextLimit(50);
Then, especially if the application is data-entry intensive, I set all the
text boxes to highlight their content when they gain focus. This allows
the user to work with the data quickly using only the keyboard. This is a
bit more of a pain since you have to create a listener for each control.
text1.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
try {
Text text = (Text) evt.getSource();
text.selectAll();
} catch (ClassCastException cse) {}
}
});
This isn't too bad when you only have a handful of widgets. However, it gets really
boring to write and maintain if you do it more than a few times. So, what do I want?
I want a method that sets the tab order, the maximum length, and adds a focus listener
to all the applicable widgets on that composite.
So, here is how I tackled the problem. I first built a class that would server
as a model for the options that I wanted to perform on it.
import org.eclipse.swt.widgets.*;
class ControlMetaItem {
Control item = null;
int maxTextLength = -1;
boolean includeInTabOrder = false;
boolean selectAllOnFocus = false;
public ControlMetaItem(Control item, int maxTextLength,
boolean includeInTabOrder, boolean selectAllOnFocus) {
this.item = item;
this.maxTextLength = maxTextLength;
this.includeInTabOrder = includeInTabOrder;
this.selectAllOnFocus = selectAllOnFocus;
}
}
Then, I built a class that would iterate through an array of these objects
and set the right options on each one.
import java.util.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
class WindowUtils {
public static void setOptionsOnControls(Composite parent, ControlMetaItem[] items) {
ArrayList tabOrderList = new ArrayList();
for (int i = 0; i < items.length; i++) {
Control item = (Control) items[i].item;
// include in the tab order list
if (items[i].includeInTabOrder) tabOrderList.add(item);
// set the max text length and add listener for text widgets
try {
final Text text = (Text) item;
if (items[i].maxTextLength > 0) {
text.setTextLimit(items[i].maxTextLength);
}
if (items[i].selectAllOnFocus) {
text.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
text.selectAll();
}
});
}
} catch (ClassCastException cce) {}
// set the max text length for combo widgets
try {
Combo combo = (Combo) item;
if (items[i].maxTextLength > 0) {
combo.setTextLimit(items[i].maxTextLength);
}
} catch (ClassCastException cce) {}
// set the max text length for ccombo widgets
try {
CCombo ccombo = (CCombo) item;
if (items[i].maxTextLength > 0) {
ccombo.setTextLimit(items[i].maxTextLength);
}
} catch (ClassCastException cce) {}
}
// now set the tab order according to the order
// of the items in the ArrayList
parent.setTabList( (Control[]) tabOrderList.toArray(new Control[] {}));
}
}
Once I had this working, I would just call the static method like so:
WindowUtils.setOptionsOnControls(this, new ControlMetaItem[] {
new ControlMetaItem(text1, 5, true, true),
new ControlMetaItem(text2, 10, true, false),
new ControlMetaItem(text3, -1, true, true),
new ControlMetaItem(combo1, -1, true, false),
new ControlMetaItem(combo2, -1, false, false),
new ControlMetaItem(combo3, -1, true, false),
new ControlMetaItem(cCombo1, -1, true, false),
new ControlMetaItem(cCombo2, -1, false, false),
new ControlMetaItem(cCombo3, -1, true, false),
});
Now windows and dialogs are much easier to create and maintain if you are doing a
lot of repetitive work. A lot of the initialization settings are in a concise
piece of code making it easier to maintain, and if you adopt this approach across
all of your user interface classes in a project (and across developers too),
you'll have a simple, standard way of setting up your forms. Of course,
so could add any other options to the list to fit your particular needs.
There really isn't a whole lot to this trick, but once you get the classes set
up for your needs, it will really save you a lot of repetitive development
time now and down the road.
Author
Written by Nathan Callender
Application Developer
November 10, 2004
|