| download source |
Confessions of the occasional GUI builderLike many Java programmers, I occasionally get to write GUI code. It's a bit more artistic than server-sided code because you get to watch this intriguing visual world emerge. I've written GUIs in about a half dozen languages over the last 15 years, starting with the old DOS implementation of FoxPro (before Microsoft got a hold of it...), Visual Basic, some unusual attempts in Visual C++, Python/Jython, Java AWT and Java Swing. Lately, I've taken up SWT, the open-source Software Windowing Toolkit that drives Eclipse and which is creating rave reviews and great claims about the future. Like the Java AWT, SWT is a relatively thin layer over native operating system windowing APIs. Unlike AWT, it is a much more direct implementation of Java calls to native windowing APIs. The concept of AWT "peer" objects are missing in SWT. As well, it seems quite a bit faster to display and react than typical AWT GUIs. Indeed -- despite some complaints from other OS users -- the Windows implementation behaves almost identical to native Windows applications. For all its benchmarks to Windows, SWT is intended to be as portable as AWT or Swing. The downside for SWT is that each port requires JNI calls to windowing APIS in each OS graphical toolkit. Since SWT is open-source, sometimes its portability has been called into question. For example, porting SWT to the MAC OS X is in its early stages at the time of this writing. A noteworthy aspect to SWT's current state is that its widget set is miles ahead of Swing. For example, if you have compared the Tree control to Swing's JTree, you will be pleasantly surprised. It is easy to code and it looks great. SWT version 3 contains an HTML browser that is truly remarkable, something that has been missing from Swing for a long time. The usual widgets like labels, text boxes, combos are much snappier to paint and react than Swing widgets. How do you download and install it?Go to the SWT Resources and Links page to find the latest download. For this article, I used Eclipse 3.0 M6 which contained 2 DLL files and the swt.jar. To compile or run any example from the SWT site, you need to invoke java with a VM argument -Djava.libary.path=DIRECTORY_WHERE_YOU_DROPPED_THE_SWT_DLLs. Of course, swt.jar needs to be in the java classpath. Running from EclipseIf you are trying to run the examples from inside Eclipse, I should mention that I ran into problems trying to piece together the DLLs and jars out of the Eclipse plug-in directories. Better you should download the SWT 3.0 separately. Set your project build path to the swt.jar in those directories. If you need to reference jface.jar (another package which I will not discuss here...), however, you may need to find it in your plug-ins directories since it wasn't in the SWT 3.0 download. ![]() When you have compiled your files, you will need to modify a section of the Argument tab in the Run properties of the Java program you are trying to run. Set the VM arguments to something like -Djava.library.path="C:\swt". The Eclipse download site has some links to snippets that you can compile and run. One of them features the HTML Browser I talked about earlier. Once you see the SWT browser snippet, I think you will be suitably impressed. Grid Puzzle, history and useI've coded the Grid Puzzle in a couple of other languages. The games is simple: you start with a set of 16 buttons. One button is empty and the rest contain of a jumble of numbers betweer 1 and 15. The object is to move the Buttons so that the numbers are sequenced correctly. Grid Puzzle is a good example of what you should be able to do with buttons, captions, some randomizing logic and simple event handlers. For this article, it allows me to compare a SWT GridLayout to a similar Swing GridLayout. As well, the simple button clicks show how very similar the SWT Event model is to AWT's. ![]() a classic puzzle Some SWT BasicsBefore we get started with the GridPuzzle, we need a minimal subset of SWT information. These are: Basic window populationThe minimum required code to get a main window to appear
Display display = new Display();
Shell shell = new Shell(display);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
The interplay between the Display and Shell indicate a close relationship between the underlying Operating System and the Application Window in this most basic SWT application. Each Control you wish to place in the application window is passed a reference to the shell in its constructor. Button button = new Button (shell, SWT.PUSH); GridPuzzle gets a layoutWhile it is easy enough to add Controls to the display, the Layout classes are essential to getting the controls to display in an orderly fashion. For the GridPuzzle the requirement was to display more or less square buttons in a 4 by 4 grid. This code is all that's necessary to achieve the grid look: GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 4; gridLayout.verticalSpacing=0; gridLayout.horizontalSpacing=0; shell.setLayout(gridLayout); Easy enough... However as you add these buttons to the Shell, you discover that their width and height are defined primarily by their captions. Efforts to call the setSize() method of the Button appear to have no affect and the result is a misshapen hodge podge of buttons. ![]() GridLayout without GridData The answer for the layout is to pass a GridData object to the Button's setLayout() method. button.setLayoutData(new GridData(GridData.FILL_BOTH)); Since there are 16 buttons, I figured for the sake of saving resources, I would reuse a single GridData object for the entire 16. However, this doesn't work! You need to pass a new object to each button.
for (int i = 0; i < 16; i++){
Button button = new Button (shell, SWT.PUSH);
button.setFont( font);
button.setText( this.getRandomCaption(i) );
if (button.getText().equals("0")) button.setText("");
button.addSelectionListener( this);
button.setLayoutData(new GridData(GridData.FILL_BOTH));
button.pack();
buttons[i]=button;
}
The GridData class is designed to allow alignment and fill specifications within the Grid. You can either pass these in the constructor new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL); or you can define them through public fields:
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.END; //right-aligned effect
gridData.grabExcessHorizontalSpace = true; //expand on window resize
button.setLayoutData(gridData);
Some nasty things about fontsI really wanted to make the Button captions a little more readable by increasing the size of its font. Delving into the SWT Javadocs (which are, by the way, very well put together... and, with the current state of SWT information, you tend to spend a lot of time in the Javadocs), you discover two things about fonts: Font font = new Font(display,fd); Buttons pass a reference to the Shell, but Font uses a Display object in the constructor. To tie the whole thing together, you can start with this code:
//create a larger font for the buttons
FontData[] fd = shell.getFont().getFontData();
for (int i = 0; i < fd.length; i++) {
fd[i].setHeight(16);
}
Font font = new Font(display,fd);
Then later on, you set it for each Button in the Grid. button.setFont( font); Unlike the GridData class and mercifully for System resources, you can pass the same font object into each of the 16 buttons. Event Model...a pleasant surpriseSometimes coding in SWT seems like a total departure from either Swing or AWT. But the Event model is surprisingly close to AWT. You define Listeners and you add these listeners to each Control that captures user (or other actor) activities in the form of clicks, keypresses and so on. Although most of the SWT examples define Listeners as inner classes, I opted for the old Swing trick of making the Main class implement one of the Listener interfaces. In this case, the Listener I used was SelectionListener. In Swing, the JButton class will add an ActionListener, but the differences between Swing and SWT end there. Like Swing, there is an Adapter class -- SelectionAdapter -- that provides a "do nothing" implementation. You can subclass SelectionAdapter and implement any of the two methods it defines. However, since SelectionListener defines only two methods -- and partly because I wasn't sure which of the two to implement -- I decided to implement SelectionListener in the GridPuzzle class.
It didn't take long to figure out that when I clicked on a button, the event that fired off was widgetSelected()
public void widgetSelected(SelectionEvent event){
if (event.getSource().getClass().equals(Button.class)){
Button button = (Button) event.getSource();
if (button.getText().equals("") ){
Toolkit.getDefaultToolkit().beep();
} else {
this.swapPlaces(((Integer) button.getData()).intValue());
}
}
}
public void widgetDefaultSelected(SelectionEvent event){
System.out.println("Widget was defaultselected: " + event.getSource());
}
The mechanics of getting at the cause of the event remains just as in Swing. You make a call to the event's getSource() method, normally casting it to the preferred Control, and you are in business. In the code above, I was trying to beep, if someone clicked on a captionless Button, or swap places with any adjacent, blank-captioned button. Concluding commentsI'm kind of impressed with SWT from the point of view of its speed and relative ease of development. I could remark that after 15 years, GUI programming seems to have gotten more difficult, not easier... but that would be complaining. One thing that really impresses me about SWT is that there may be an opportunity for some of us Java gurus to take a break from coding on the server and migrate to client side. Wouldn't that be a switch? ResourcesI'm going to provide some good resources here, but you need to remember that, at the moment, SWT isn't the most widely- documented technology. For all the thousands of pages on Javascript and Jsps, you'd thing it would be easy to find something about something as interesting as SWT. Happy googling! The SWT javadocs are a great place to get started.The Eclipse manual has a good chapter on SWT and another on JFace. The eclipse site has a great SWT section with snippets you should check out, a great FAQ and other resources. Migrate your apps to SWT provides a neat tutorial on migrating from Swing to SWT. Comparing SWT and Swing is a popular sport. This article from developer.com is an honest comparison. Looking for a book? So am I. There are apparently two books coming out soon. Try either Manning or Apress. Both publishing houses will soon feature SWT titles. Copyright (c)2004 Gervase Gallant gervasegallant@yahoo.com |