Cart   |   Search   |   Site Map

News & Articles > SWT Tips and Tricks: Part 1 - Window and Dialog Initialization

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