Chapter 17. Other Ways: Alternatives to Swing

In which we discover that Swing is not the only GUI game in town. In so doing we learn the rudiments of the Standard Widget Toolkit and we describe some of the key limitations of this alternative toolkit.

What You Will Learn

This chapter will introduce the basic classes of SWT, the Standard Widget Toolkit, which is an alternative GUI library developed mainly for the Eclipse Java IDE.[1] Development of Eclipse has been led primarily by IBM.[2]

The IBM SWT Toolkit

The Standard Widget Toolkit is a complete GUI library for Java, completely independent of Swing and AWT. It is implemented as a library of native methods, so it cannot be ported to any Java runtime unless that platform has the native part of the SWT library implemented for it.

Another GUI Toolkit. Why?

The first question one should ask, perhaps, is why create an alternative GUI? Good question. The answer, according to the SWT FAQ,[3] primarily has to do with execution speed and look-and-feel similarity to native GUI applications on each platform.

If we may editorialize, we find neither reason particularly compelling, although the execution speed argument made some sense when the Eclipse project started. Swing is unlikely to win any performance awards, even though each version brings some improvements in speed.[4] Still, these reasons do not seem particularly compelling for such a large duplication of effort and functionality.

Whatever the reason, SWT exists. SWT works by providing a thin abstraction layer over native GUI features. It is a small GUI library. It is implemented using the Java Native Interface, so it requires that a native binary library be implemented for your platform. Fortunately, such implementations exist for all platforms Eclipse runs on. So if you can run Eclipse, you can write and run SWT applications.

Duplicated Effort. Why Cover It?

The next logical question is, “If you think SWT is unnecessary with Swing already there, why cover it in your book?” Also a sensible question. The answer is that there is very little published literature on this library (a notable exception being Chapter 10 of The Java Developer’s Guide to Eclipse by Shaver et al., from Addison-Wesley). Also, SWT provides the only fully functional GUI library that will work with the GNU Compiler for Java. As such, it is a major required component if you wish to write native compiled GUI applications on Linux systems.

Of course, there is another reason. Anyone heavily into Linux is well aware of the political and philosophical debate about Free Software and Open Source. If the core values of Free Software are critical for you, you should be aware that the IBM Common Public License[5] under which Eclipse (and thus SWT) are published is a Free Software license. You get the source code, you may use it in your own products, and it imposes obligations similar to the GNU GPL,[6] but goes even further by requiring you to grant royalty-free licenses for any patents you hold in derivative works.

So you might choose SWT (or not) for political or philosophical reasons. Both authors still suggest Swing first because it is the official Java GUI library. When an employer wants to know if you can write a Java GUI application, he or she almost certainly means a Swing application. Philosophy is great, but it may not put the food on your table. You need to know that Swing is not Free Software (and neither is either of the major Java SDKs), and SWT is Free Software, but it is up to you to decide what best serves your interests.[7]

Portability: Better and Worse

How about portability? Well, it depends on what “portability” means to you. If portability means “looks and runs the same on all platforms,” then Swing offers better portability. If portability means “runs on all platforms for which there is a Java runtime,” then Swing offers better portability. If portability means “looks like a native application on all supported platforms,” then SWT is your choice. Make your selection accordingly.

Tip

The bottom line: If you only learn one Java GUI, make it Swing.

The Rest of the Chapter

The rest of this chapter will be devoted to describing the basic classes of SWT by converting one of the application classes from the previous chapter from Swing to SWT. We will not attempt to explain the operating principles of GUIs. For an introduction to GUI programming, see the previous chapter on Swing. It introduces the concepts and programming principles for GUI programming in Java. SWT is functionally similar, although quite spartan, providing only basic windows, controls, and events.

Eclipse also contains a family of higher level user interface classes, known collectively as JFace, that provide UI features such as dialogs, wizards, font handlers, and images. We will not cover JFace in this book.

SWT: Close to the Metal

SWT breaks some of the Java contract. For example, you cannot rely on garbage collection to clean up SWT objects. Any SWT object you create with new must be explicitly destroyed with a call to the dispose() method. Why? Since SWT is implemented with native methods, the low-level implementation allocates native OS data structures and objects that must be explicitly freed. Since the Java garbage collector cannot be relied upon to collect objects at a certain time (or ever, for that matter), these allocations can result in memory leaks and address space conflicts. As we shall see, however, SWT is well designed to minimize the amount of this that you need to worry about.

SWT is also close to the metal in the sense that it does not abstract the underlying message-based event system that drives both X Window and Microsoft Windows. If you have ever written an X Window or Microsoft Windows application in straight C (without a GUI framework library or class library), you have written a main() function that contains an event loop. SWT actually puts simple method calls around this core message queue event loop. We’ll cover the details of this in the next section where we introduce the Display and Shell classes.

“Hello, world” SWT Style

SWT consists mainly of classes that represent controls—such as buttons, text areas, scrollbars, and so on—and layout managers which are much like layout managers in Swing. But there are two other classes: Display, which models the interface between your Java application and the underlying windowing system, and Shell, which effectively represents a single window.

The application in Example 17.1 is a parallel to the simple Swing program in the last chapter (Example 16.1).

This simple program, like its parallel in the Swing chapter, is deceptive. Sure, this is a lot of code to say “Hello, world” but it is because what we are setting up here is an event-driven program that must respond to any valid user input.

Setting Up to Run an SWT Application

One advantage of Swing that we haven’t pointed out up to now is that it is part of every Java runtime (well, not gcj; more on that later), so you have all the classes on your classpath without any special setup. Not so with SWT. The exact procedure for setting up to run an SWT application depends on what development environment you are using.

There is an excellent set of directions for running an SWT application under Eclipse in the SWT FAQ.[8] No matter what your environment is, there is a basic series of steps:

  1. Download the Eclipse SDK.

  2. Install it.

  3. Extract the SWT JAR files.

  4. Extract the SWT JNI files.

  5. Configure your development environment.

Example 17.1. A simple SWT application

import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

/**
 * @author mschwarz
 *
 * Sample SWT "Hello, world" application
 */
public class SWTHelloWorld {

  public static void main(String[] args) {
    Display disp = new Display();
    Shell window = new Shell(disp);
    window.setLayout(new RowLayout());
    Label label = new Label(window, SWT.NONE);
    label.setText("Hello, world.");
    window.setSize(320, 160);
    window.open();

    while (!window.isDisposed()) {
      if (!disp.readAndDispatch()) {
        disp.sleep();
      }
    }

    disp.dispose();
  }
}

Let’s go over these in a bit more detail.

SWT was developed as a GUI library for the Eclipse project. It is distributed as part of Eclipse. There is no official standalone SWT package. The right way to obtain SWT is to download and (at least temporarily) install the Eclipse SDK. See Section 10.4 for details.

If you have followed our sage advice and downloaded the GTK version of the Eclipse SDK, then you need to copy out the SWT JAR files. There are two files in the GTK version, and just one in the Motif version. The GTK version’s files are swt.jar and swt-pi.jar. They are both in the eclipse/plugins/org.eclipse.swt.gtk_2.1.2/ws/gtk directory. You will need to have both of these JAR files on the classpath of any SWT application you are compiling or running.

Remember that SWT is a JNI library. You must also have the native Linux shared libraries. These need to be made available to the Java native loader. The files you need are located in the eclipse/plugins/org.eclipse.swt.gtk_2.1.2/os/linux/x86 directory. The .so files there must be available to any running SWT application. There are a couple of ways to do this. First, as described in Section 5.7, you can set the LD_LIBRARY_PATH environment variable. You also can use the -D parameter for the runtime VM to set the java.library.path property.

If you want to, you can copy these files out of the eclipse directory to some other location and then erase the eclipse directory with the lovable old standby, rm -rf eclipse.

Oh, by the way, once you have compiled the sample code above and set your classpath and Java library path correctly, running the application produces the window shown in Figure 17.1.

Running the SWT version of “Hello, world”

Figure 17.1. Running the SWT version of “Hello, world”

Anatomy of an SWT Application

Before we launch into this discussion, we should point out that the Javadoc documentation for all SWT packages is available as part of the Eclipse Platform documentation.[9] You might want to use that resource along with this lightweight tutorial to fill in the gaps and shortcuts.

It should not be too surprising that there are similarities between SWT, AWT, and Swing. They all take different approaches to solving the same problem, namely how to control the complexity of a graphical event-driven application. Because the problem is the same, there can’t help but be similarities between different solutions. By now you may have deduced that the Shell class is an analog to the JFrame class, and that SWT uses a system of layout managers not too different from Swing. If so, you are on the right track and well on your way to using SWT.

If we had to summarize the difference in approaches between SWT and Swing, it would be that SWT tries to provide a small number of complex classes, and Swing tries to provide a large number of simpler classes. Obviously, this is a generalization, but everybody generalizes. Sorry.

The Display is a class that provides the link to the underlying GUI system. Think of it as an abstraction of the interface to the windowing system. In almost all cases, an SWT application will have exactly one instance of Display.

The Shell class represents a window. This class descends from a series of abstract parent classes, so if you look at the Javadoc for Shell and think it is simple, be sure to drill down into those parent classes! We’ll discuss Shell quite a bit more as we go along.

Porting BudgetPro to SWT

The conversion of an existing application is a complex process. Always consider rewriting from scratch. Still, it is worthwhile to show an application converted from Swing to SWT, because it will emphasize the relationship between the two.

We begin with the reobjecting. Starting with the BudgetPro class, we need to add an instance of the Display class. Then the JFrame becomes a Shell. Likewise, the JLabels become Labels. Then ... Wait a minute. You don’t need a blow-by-blow account. Maybe it would be simpler to show you what SWT classes roughly correspond to the equivalent Swing classes (Table 17.1).

Table 17.1. Major SWT widgets and their Swing equivalents

SWT widget

Analogous Swing component

Description

Button

JButton

Display widget that sends notification when pressed and/ or released.

Canvas

java.awt.Canvas, but see also java.awt.Graphics2D

Composite widget that provides a surface for drawing arbitrary graphics. May be used to create custom widgets.

Caret

javax.swing.text.Caret

A cursor used as the insertion point for text.

Combo

JComboBox

Widget that permits the user to choose a string from a list of strings, or to enter a new value into a text field.

Composite

JPanel

Widget that is capable of containing other widgets.

Group

JPanel

Composite widget that groups other widgets and surrounds them with an etched border and/or label.

Label

JLabel

Nonselectable widget that displays an image or a string.

List

JList

Selectable widget to choose a string or strings from a list of strings.

Menu

JMenu

User interface widget that contains menu items.

MenuItem

JMenuItemA, JCheckboxMenuitem, JRadioButtonMenuitem

Selectable widget that represents an item in a menu.

ProgressBar

JProgressBar

Nonelectable widget that displays progress to the user.

Scale

JSpinner

Widget that represents a range of numeric values.

ScrollBar

JScrollPane.

Widget that represents a range of positive numeric values. Used in a Composite that has V_SCROLL and/or H_SCROLL styles. The mapping to Swing is not very tight here, since JScrollPane is like a combination of Composite and ScrollBar.

Shell

JPanel

Window that is managed by the OS window manager. A Shell may be a child of a Display or another shell.

Slider

JSlider

Widget that represents a range of numeric values. Differs from a Scale by having a “thumb” to change the value along the range.

TabFolder

JTabPane

Composite widget that groups pages that can be selected by the user using labeled tabs.

TabItem

Any JComponent

Selectable user interface object corresponding to a tab for a page in a tab folder.

Table

JTable

A selectable widget that displays a list of table items that can be selected by the user. Rows are items, columns are attributes of items.

TableColumn

JTableColumn or instance of TableColumnModel

Selectable widget that represents a column in a table.

TableItem

TableCellRenderer or TableCellEditor

Selectable widget that represents an item in a table.

Text

JTextField, JPasswordField, JFormattedTextField, JTextArea, JEditorPane, JTextPane

Editable widget that allows the user to type text into it.

ToolBar

 

Composite widget that supports the layout of selectable toolbar items.

ToolItem

JButton

Selectable widget that represents an item in a toolbar.

Tree

JTree

A selectable widget that displays a hierarchical list of user-selectable tree items.

TreeItem

MutableTreeNode

Selectable user interface object that represents a hierarchy of items in a tree.

We are going to walk you through converting only one of the GUI source files for the BudgetPro application. We will leave converting the rest as an exercise for you. We’ll talk about some of the entertaining differences between the models. As you shall see, there is no clear “winner” here between SWT and Swing. Almost all technical choices—SWT versus Swing, Java versus C++, Emacs versus vi, or for that matter UNIX versus Windows—are tradeoffs. This is no exception. There are things we like about SWT. For simple GUI applications, we think it is easier to set up and use. We think it is easier to learn in its entirety than Swing. Swing, on the other hand, is more complete, offering classes that will do more than SWT. So the best solution depends (as always) on your requirements.

Step 1: Convert the Class Members

We are going to tackle converting BudgetPro.java from Swing to SWT. In real life, this is an exercise you are unlikely to have to carry out. You will more likely write your GUI applications from scratch. But going through the conversion provides a useful roadmap for talking about the architecture of SWT; it teaches you SWT in terms of a class library with which you are already familiar.

First off, we change the packages imported at the start of the file. Remove all of the awt and swing packages. If you are using an IDE, this should flag every single line of code that touches the GUI as an error. This can be a big help when you are doing a mass conversion like this. When you have killed all the compile errors, you know you are well on your way to completing the conversion.

Replace the import statements with the imports you are likely to need for your SWT application. These are:

import org.eclipse.swt.*;
// The static SWT class, which contains a number of constants.

import org.eclipse.swt.widgets.*;
// The widgets library.  Almost all your display elements are here.

import org.eclipse.swt.events.*;  // Event handlers

import org.eclipse.swt.layout.*;  // Layout managers

We will go into these families of classes in more detail as we convert the members and methods of BudgetPro.java.

The next step is to convert the GUI members of the class from the Swing classes to their SWT counterparts. Of course, SWT requires the Display class, which has no analog in SWT, so we add a Display type member named disp just ahead of the frame member.

Next, we change the type of frame from JFrame to Shell. We could rename the member,[10] but why add to our typing burden? The name is still clear and meaningful, even if it doesn’t match the SWT name.[11] There’s more to it than just changing the type, however. The constructor call for the JFrame doesn’t match any constructor for Shell. In fact, the Shell constructor requires a Display object argument, and all subsequent constructors for widgets and controls require a Composite as an argument.

This is a key difference between Swing and SWT. Swing allows you to build GUI components in arbitrary order at arbitrary times and then join them up to the GUI with an add() method call. SWT instead requires that you link your components up to the GUI element they belong to when they are constructed. There are good reasons for this difference. Remember that SWT allocates native objects and memory that Java’s garbage collector cannot recover. Because of this, SWT makes the promise that if you call the dispose() method on any SWT object, it will dispose of it and everything it contains. That allows you to clean up all resources from an SWT program by calling dispose() on the top level Display object. If SWT allowed you to build GUI structures independently and then graft them onto the hierarchy, it could not keep this promise. For this reason (amongst others) SWT objects are always built in a fairly rigid top-down manner.[12]

The most direct consequence of this is that we have to get rid of the constructors on these declarations. We’ll start construction in the main(). So, away with the constructors for the GUI elements. We now need to change the JButtons to Buttons and the JLabels to Labels. Again, if you are using a dynamic IDE, you should see your error count skyrocket with these changes (well, maybe not really skyrocket, since the import changes have already produced a lot of errors right off the bat).

Finally, we remove the AbstractTableModel member. SWT has a simpler (and more limited) table functionality that we will discuss later.

Step 2: Converting the main() Method

The main (pun unintended) changes that need to be made here include allocating the SWT Display, changing from instantiating a JFrame to a Shell, doing away with the Swing “look and feel” stuff (an SWT application always looks like a platform-native application, that’s SWT’s main selling point), and reworking the construction of the GUI. We’ll explain that a little bit later.

For now, we take care of the simple changes. Remember that main() is a static method, so we do not have any nonstatic class members available right now. The original BudgetPro constructor took a JFrame argument, now it will have to get a Display and a Shell. So we have to allocate a local Display and a local Shell. We also need to add the Display argument to the BudgetPro constructor.

After this is done, we modify the call to the constructor to pass the local Display and Shell to our class instance.

Next, we have to set a layout manager. The original application used the Swing BorderLayout layout manager. SWT doesn’t have such a critter. Fortunately, the original used only the north, center, and south positions of the BorderLayout. SWT has a simple layout manager called a FillLayout that puts its contained controls in a single row or column, equally sized. Putting the three controls in a column will end up looking much like using the north, center, and south of a BorderLayout. So we change the call to the frame.setLayout() to pass in a new FillLayout and add the SWT.VERTICAL attribute.

The next block of code in main() sets the Swing look and feel. SWT has nothing like this. All SWT applications look like native applications (we seem to be saying that a lot), so all of this code may be removed.

The next block of code calls methods on the application object (app) that, in the original, construct the three “chunks” of UI and add them to the frame using the BorderLayout attributes. Since, as we explained earlier, all SWT controls must be explicitly joined to a parent control when they are constructed, the separate create-then-add semantics used in the original will not apply. In the next section, we will walk through converting one of these three create methods. For now, it is enough to know that they will be changed to be methods that return void (no return value) and the calls to add() may be deleted.

That completes the conversion of main().

Step 3: Converting the GUI build() and init() Methods

Lest you believe that this means the application is ready to run, just try compiling what you have. Got a few errors yet, don’t we?

Let’s walk through converting the createStatus() method and its related methods. We’ll then briefly discuss converting the createList() and createButtons() concentrating on the details of the unique UI widgets used in each.

Converting the GUI build() Method

In BudgetPro, the top part of the UI is the status pane. It consists, basically, of three labels. In the original application, this pane is constructed by the createStatus() method. In the original, it returns a Swing Component, which is then placed by calling add() on a container managed by the caller.

In SWT, Widgets must be joined to their containers at construction, so we must restructure this code a little bit. We create a Group to hold our classes together as a unit. We attach the group directly to the parent Shell by using the member variable frame. We set the layout manager to be RowLayout.

We then populate the Group. First, we add the Up button, which is only enabled when in a subaccount. While SWT does support image buttons, we take the shortcut of using the SWT.ARROW style, bitwise-or’ed with the SWT.UP style. Next, we populate the group with our Labels.

Note a change we will talk about some more below: The listener for the Button object called upton is changed. The method is renamed from addActionListener() to addSelectionListener(). Event handling in SWT is similar to Swing/AWT, but not identical, as we will see when we go over the rewrite of the actual event handler code a little later on.

These are the only changes we make to this method.

Caution

If a Composite has no layout manager, each Widget in the Composite must have its size and position explicitly set, or else their sizes will default to zero, and they will all be invisible! Tremendous details on SWT layout manager classes can be found in the article ““Understanding Layouts in SWT”” by Carolyn MacLeod and Shantha Ramachandran on the Eclipse Web site.[13]

Converting the GUI init() Method

The setStatus() method is called whenever the data in the core model changes. Its job is to update the UI to reflect those changes. More specifically, it updates the status pane at the top of the UI. There are corresponding methods for the list pane and the button pane.

Oddly, there are no changes in this particular method. The purpose of this method is unchanged. It updates the Labels with the new numbers and checks to see if the current Account is the top level Account. If it is, the Up button is disabled, otherwise it is enabled.

It turns out that all of the methods called on the UI classes in this method have the same names and purposes in Swing and SWT. Don’t assume this will be true in the other cases.

Reworking Event Handlers

Finally, in the litany of conversion, we have to modify the event handlers. In this case, the only event of interest is when the Up button is pressed. Pressing a Button produces a Selection event.

In SWT, there are several types of events. Generally, you specify a class that will handle the event by calling one of the add...Listener() methods on the Widget that you wish to process the event for. Examples of these method calls include:

  • addSelectionListener()

  • addControlListener()

  • addFocusListener()

  • addHelpListener()

  • addKeyListener()

  • addMouseListener()

  • addMouseMoveListener()

  • addMouseTrackListener()

  • addPaintListener()

  • addTraverseListener()

There are others. SWT naming conventions define an interface for which each add...Listener() method is named. For example, there is a SelectionListener interface. Many such interfaces have multiple methods, each to handle a distinct kind of event; for example, the MouseListener interface defines separate methods to handle a button down event, a button release event, and a double-click event. As in Swing, it is common to implement event listeners as anonymous inner classes that implement the listener interface. However, since it is common to be interested only in some (or even only one) listener event, it is annoying to have to implement the full interface, since you have to provide method implementations for every event. For this reason, SWT also provides classes called adapters that implement “do-nothing” methods for every listener event. These also follow a naming convention. For example, the adapter for the MouseListener interface is a class named MouseAdapter; the SelectionListener interface has an adapter named SelectionAdapter, and so on.

For us, this means that we are going to create a reference to an anonymous inner class that implements the SelectionListener interface by extending the SelectionAdapter class. This is probably the weirdest common code construct in Java. Let’s take a direct look at that method (Example 17.2).

If you can correctly answer the following question, then you can be reasonably assured that you do, in fact, understand what is going on here. Would the program compile and run correctly if the type of the upAction variable were changed to SelectionAdapter? The answer is in the footnote.[14]

Example 17.2. The upton Button event listener class reference declaration

private SelectionListener upAction = new SelectionAdapter()
{
  public void widgetSelected(SelectionEvent e)
  {
    // this is the action for UP arrow icon;
    Account next;
    next = current.getParent();
    if (next != null) {
      current = next;
      setStatus();
    }
  }
} ;

Completing the Conversion of the BudgetPro Class

To keep this book to a reasonable size, we are always trying to avoid covering the same ground more than once. We won’t walk you through the details of converting the createList() and createButtons() methods as we did with the createStatus() method, but we will talk about the details of converting to SWT of some of the classes used in those methods.

The Table, TableColumn, and TableItem Classes

Without a doubt, the biggest change the BudgetPro class requires in order to convert from Swing to SWT lies in the table pane of the UI. The Table class is the root of tables in SWT. The TableColumn class defines the names and headers of the columns. TableColumn constructors must have a Table as their first argument, followed, as usual, by a numeric style specification. The TableItem class defines a row in the Table. As with TableColumn, the TableItem constructor must have a Table as its first argument, followed by a numeric style.

If you think about it, this is an extension of the same design philosophy that requires that all constructors name their parent Composite. While Swing’s abstract table model permits a nice separation between the data and the presentation, implementing a similar system in SWT would violate its strict container semantics.

You will need to follow the basic rewrite process outlined above and you will have to squish the Swing abstract table model into the simpler SWT table model. This will be your biggest challenge. Go to it. It is a great way to learn. Of course, you can also just download the complete SWT application from the book Web site.[15]

Completing the Conversion of the Application

Completing the conversion of the BudgetPro class does not complete the conversion of the entire application. The AcctDialog class must also be converted. Use the same techniques we described here to convert that class as well. (Or, again, just download the complete SWT application.)

Closing Thoughts

Our overall impression is that SWT is more easily comprehended in its entirety than Swing. It may be easier to learn SWT first, since Swing’s core model is more complex but more powerful. But SWT and Swing weren’t developed in that order and Swing is still much more widely used.[16]

For many GUI applications, our feeling is that it may be faster to write in the SWT idiom. The problem lies in that SWT’s model has limitations that Swing’s does not. Notably, SWT GUI elements are in a single rigid tree structure. It is not possible to have a factory class that constructs a GUI element such as a dialog box which is passed up to the caller to be grafted into place on a GUI. Instead, the parent element must be passed in, so all GUI elements belong to the single tree from the moment they are created. Also, by introducing objects that cannot be garbage-collected, SWT brings into your application the possibility of a class of bugs that Java otherwise eliminates.

Moreover, while converting a Swing application helped give this chapter shape, we would, in general, prefer that an application be designed with its GUI toolkit in mind. You would likely make slightly different design decisions depending on which style of the GUI you choose.

SWT and gcj

Up to now, we have told you again and again that SWT will work with gcj. But no Linux distribution with which we are familiar provides SWT with gcj out of the box. So how do you get SWT to play nice with gcj? Unfortunately, you have a bit of work to do. Fortunately, the work is not particularly difficult.

Before we proceed, we must acknowledge those who have been there before. We, too, had heard about SWT’s usability with gcj but we had never bothered to try it because there was no documentation on how to do it. We first made the attempt thanks to a great IBM developerWorks article by Kirk Vogen entitled ““Create Native, Cross-Platform GUI Applications”.” Follow the URL[17] to the information that enabled us to write this chapter.[18]

SWT source code is included in the Eclipse SDK download. See Section 10.4 for details on where and how to download and install Eclipse. Once you have Eclipse, you need to get your mits on the SWT source code. What we will do is compile the SWT source into a shared object file that we can link to any gcj application.

We’re assuming that you’ve got gcj installed. We’re assuming that you’ve unzipped the Eclipse SDK. We’re assuming you’re still reading the book. We have to make that assumption. The first thing you need to do is to unzip the SWT source code. It is found in ECLIPSE_INSTALL/plugins/org.eclipse.platform.linux.gtk.source_2.1.2/src/org.eclipse.swt.gtk_2.1.2/ws/gtk. If you are using (as we recommend) the GTK version of Eclipse,[19] there are two files in there: swtsrc.zip and swt-pisrc.zip.

Once you have these unzipped, you have to compile the code with gcj. There are two different patterns these files follow. Files that do not contain native methods are compiled with a command line that looks like this:

$ gcj -c SomeClass.java -o SomeClass.o

Files that do contain native methods are compiled with a command line that looks like this:

$ gcj -fjni -c SomeClass.java -o SomeClass.o

That said, it does no harm to compile a source file that has no native methods with the -fjni flag. This gives us a quick and dirty way to make our library file.

$ find . -name "*.java" -exec gcj -fjni -c {} ; -print

Remember, you are in UNIX-land. Leverage your tools! In this case, the advantage of using find is that, should the SWT source change (classes added or removed), our “compile process” will handle it. Obviously, you can take this in more sophisticated directions with make or ant. But this will get the job done for us for now.

That will compile all of the SWT source.[20] Next, we want to assemble all of the object files produced into a shared object.

$ gcj -shared -o swt.so $(find . -name "*.o" -print)

Once again, we leverage our tools. This time, we use bash execution quotes around our find command to get all of the .o filenames added to our gcj command that builds the shared library. For our final trick, we will compile our HelloWorld class from the start of this chapter with gcj and our new SWT shared library:

$ gcj -classpath=~/eclipse/plugins/org.eclipse.swt/swt.jar:
~/eclipse/plugins/org.eclipse.swt/swt-pi.jar -c HelloWorld.java
$ gcj -main=HelloWorld -o HelloWorld Hello.o swt.so
$ export LD_LIBRARY_PATH=.:~/eclipse:
~/eclipse/plugins/org.eclipse.swt/ws/gtk
$ ./HelloWorld

Et voilà! You have the HelloWorld application! Again. But now it is an executable binary. Enjoy.

Review

Compared to Swing, SWT is a somewhat simpler GUI library. Unlike Swing, it is Free Software and Open Source. It provides a full GUI library for use with gcj. It is part of the Eclipse project. It uses native methods that require calls to dispose of allocated objects. It has a rigid hierarchy that requires that lower level GUI components be linked to their parents when they are constructed. This means there are some limitations on how applications may be constructed. SWT is much less commonly used than Swing. Swing is the lingua franca of Java GUIs. SWT is definitely worth knowing, but if you want your skills to be marketable, it is probably best to start with Swing.

What You Still Don’t Know

We just scratched the surface of SWT Widgets. There are a bunch we haven’t covered.

Resources

Exercises

1.

Complete the conversion of the BudgetPro class.

2.

Complete the conversion of the entire BudgetPro GUI application.

3.

While you have Eclipse installed, follow the instructions to unpack the SWT examples. In particular, run the ControlExample. This is an application that demos all the major Widgets, while giving you the ability to apply most (if not all) of the style values to them dynamically. It is like a Widget browser that can get you familiar with the look and feel of SWT Widgets quickly. Run it. Play with it. Become friends with it. Also, remember you have the source code for this application. Want to know how to code a given Widget? Look!



[4] The question of speed in Java is a rather tired argument. If maximum speed is a primary concern, Java is probably not your first choice of a development language. In our experience, speed is something everybody says they need, but more often than not other considerations such as development time and error rate are much more important. Java is fast enough for virtually all MIS applications, and that is the market Java is squarely aimed at. Our computers keep getting faster, disk drives and memory keep getting cheaper. The “resource” and “performance” arguments only apply to applications where experienced designers would already have chosen C or assembly language. Besides, with the JIT compilers in both Sun’s and IBM’s JDKs, a well-written Java application is often as fast or faster than some other compiled languages, at least on the second run of the code.

[7] A lot of people couldn’t care less about the Free versus non-Free issue, but I must say that many of my most interesting workplace discussions have arisen from this issue. It is the first issue in my career that has had programmers talking about the balance between their personal interests, their employers’ interests, and the public interest. Wherever you stand philosophically, I think it is good that programmers are thinking about the consequences of their work at all of these levels. I wish there were more pressure at all levels of business to consider and balance all of these interests.

[8] http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-swt-home/faq.html?rev=1.83content-type=text/html#standalone. Note that this link is to the current revision in CVS as of this writing. You should take a look at the parent page to see if there is a newer revision.

[10] If you are using Eclipse, this is easily done throughout your code with the Refactoring feature.

[11] All right, I’m being lazy. Write your own book if you don’t like it.

[12] In some ways, this greatly simplifies SWT programs, but at the cost of some reusability. With Swing, you could construct a panel or other GUI element and reuse it in many places. You can achieve the same thing in SWT by encapsulating such a construct in its own class and passing in a parent to the constructor, but this is a bit more bulky and complex than the Swing way.

[14] Yes, it would. The reason is that the addSelectionListener() method takes an argument of type SelectionListener. Both SelectionListener and SelectionAdapter are of that base type. Aren’t Objects wonderful?

[16] A gut feel—not based on any real statistics.

[18] Please note that Kirk’s article provides links to additional documentation and to an ant buildfile that automates the steps we are going to teach you manually here. We certainly didn’t want to steal anything from Mr. Vogen (or from IBM—scary!), so we will instead direct you to the (copyrighted) IBM Web resources. The article is worth checking out. It can save you some time over our version of the process. It is up to you.

[19] Be aware: As helpful as Kirk Vogen’s article and files are, they are written to an old version of gcj and they assume you are using the Motif version of Eclipse. His scripts work only with the Motif version.

[20] When we did this with Eclipse 2.1 GTK and gcj version 3.2.2, we had one compile error where the return type of the org.eclipse.swt.custom.TableCursor.traverse() method was void, whereas the Control.traverse() method (from which TableCursor inherits) was boolean. So we hacked it. We changed the return type of TableCursor.traverse() to boolean and had it return true. We didn’t test to see if this was right! Use at your own peril!

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

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