Rich clients with the SWT and JFace

Build a GUI application using Java and the Eclipse GUI APIs

The rise of the Internet and the Web browser as the universal computing client forced user-interface development and the overall user experience to take a step backwards. Web applications, due to their ease of maintenance in terms of deployment and upgrading, allow you to reach a larger audience. Yet, they deny the user the experience that a full-fledged desktop application can provide. The raw power of today's personal computers is mostly untapped when it comes to browser-based enterprise applications. The browser-based application is to a certain extent a glorified version of the dumb terminal of days gone by. Although Java made its debut with applets, which promised many of the features of rich native applications combined with the ease of maintenance of Web applications, the applets' tumultuous evolution has relegated them to a limited functionality—stock tickers and news feeds. This has led many to argue that browser-side Java is effectively dead. The technology wasn't completely to blame because Java on the browser was a casualty of the browser wars and the early problems faced by VM integration in the two leading browsers, Internet Explorer and Netscape Navigator.

Java's client-side technologies have all had their share of criticisms and never conquered the share of the desktop market that many predicted. As with applets, many believe that the rough transition from the Abstract Window Toolkit (AWT) to the early days of Swing, coupled with the overall complexity and paradigm change in UI development introduced by Java (in comparison to the Model-View-Controller (MVC)-less world of Visual Basic, Delphi, and other RAD (rapid application development) environments) caused Java to lose the battle for the desktop.

In this article, we introduce the open source community's answer to the rich client conundrum in the form of the Eclipse project UI frameworks, namely the Standard Widget Toolkit (SWT) and JFace. The Eclipse frameworks provide a Java alternative to building robust, responsive, and great-looking desktop applications.

The Eclipse user interface frameworks

The Eclipse project is described on its Website as an "IDE for anything and for nothing in particular." The use of the term IDE in the previous sentence might be a bit misleading because, although the composing subsystems of the Eclipse framework have at certain points in their API an IDE-ish flavor to them, the majority of the framework is usable as a general desktop application framework.

The Eclipse project spawned out of the early work of Erich Gamma and the folks at Object Technology International (OTI), which is now an IBM subsidiary. OTI is well known for its work in the areas of development tools (VisualAge) and object languages like Smalltalk and Java.

This article deals with using the underlying frameworks created by OTI and IBM to deliver a fast, responsive Java desktop application. Many pages can be written about the controversies surrounding the Eclipse project, its underlying APIs (particularly the SWT), the design choices, and the impact that open sourcing the codebase has created in the community. Instead, you'll focus on building a robust application using Eclipse.

The following are the two main frameworks that you'll learn about:

  • SWT: A widget set and graphics library that provides a portable graphics API independent of the OS but that relies on the native widgets
  • JFace: A model-based UI toolkit that simplifies common UI programming tasks

Standard Widget Toolkit

SWT is the foundation upon which the Eclipse IDE is built. SWT delivers the richness and responsiveness of an application build using native widgets, yet it manages to do so in an operating system-independent fashion.

The Eclipse team realized early that creating a cross-platform set of widgets is a daunting task, both in the areas of matching the functionality of mature operating-system widgets and in making the application seamlessly blend with the native applications. SWT takes a hybrid approach between those taken by AWT and Swing. Instead of using "fat native peers," SWT uses a procedural pass-through layer to the OS graphics API. This thin Java Native Interface (JNI) layer enables SWT to control the native widgets. This approach minimizes the amount of native code involved, thereby making debugging SWT a lot easier. SWT also avoids the need for a pluggable look and feel because it adopts and immediately reflects any changes to the underlying OS look and feel.

Note
Pluggable look and feel is another hotly debated topic. The Eclipse mentality is one of "uniform is better," and we certainly agree with this when it comes to commercial business software. Many other applications can certainly benefit from a pluggable look and feel in the same way that many applications benefit from the use of skins. If your application needs to support a customizable or personalized look, then Swing is the obvious choice.

The SWT approach not only makes the API simpler, but also provides tight integration with hard-to-integrate features such as drag and drop. Drag-and-drop support is another area in which Swing's implementation was plagued for a long time by bugs and inconsistencies. With SWT, any improvements in the drag-and-drop behavior of the OS are reflected in your Java applications immediately.

To resolve the least common denominator problem, SWT widgets that aren't present in a specific platform are emulated using lightweight techniques in the way that it's done in Swing, yet the components are unencumbered by any built-in patterns. A good example is the Tree widget. In Windows, Tree widgets are native components, but in Motif, they're emulated. The SWT implementation in Motif contains the Java code to provide the Tree functionality, but in Windows, using a Tree widget is simply a matter of calling the correct Windows graphics device interface (GDI) commands. Figure 1 shows the three different approaches.

Figure 1. Rendering approaches of AWT, SWT, and Swing

The SWT API is the same on all different supported platforms. Behind the scenes, SWT uses a factory pattern of sorts to plug the right implementations for a given platform. Not only do SWT applications look like they belong among other native applications, but they also feel like native applications. Figure 2 provides a graphical overview of the SWT architecture.

Figure 2. SWT packages

At the time of this writing, SWT has been ported to the following platforms (operating systems and windowing systems): aix/motif, hpux/motif, linux/gtk, linux/motif, linux/qt, macos/carbon, qnx/photon, solaris/motif, win32/win32, and win32-ce/win32. SWT is also a very lightweight API, which makes it ideal for embedded devices as demonstrated by the Windows CE port.

JFace

From the previous description of SWT, you should have gotten the impression that it provides a raw widget set. But what about all of the advancements implemented in Swing, such as strong MVC microarchitectures for complex, often-used widgets such as Trees and Tables? To provide a more advanced, model-driven interaction with SWT, the Eclipse team created the JFace toolkit. JFace is a higher-level user interface toolkit that uses the raw SWT widgets to provide model-driven widgets, and to some extent some functionality that isn't available in the Swing libraries, such as advanced editors, dialog boxes, and wizards. JFace covers many areas of UI development that developers encounter over and over, and it provides a clean way to accomplish those tasks. JFace depends on SWT, but it doesn't hide SWT widgets. For example, JFace viewers, which are model-based content adapters for SWT widgets, provide methods to access the underlying SWT widgets. This duality provides developers with the separation and ability to choose between model-driven UI development and raw widget manipulation. Figure 3 shows a graphical overview of the JFace API.

Figure 3. JFace packages

Some of the packages shown in Figure 3 and a short explanation of their functionality are shown here:

  • Window: The org.eclipse.jface.window package provides window creation and management facilities. Of particular interest is the ApplicationWindow class, which provides a higher-level application window and encapsulates the SWT event loop.
  • Viewers: The org.eclipse.jface.viewers package provides a framework of viewers such as TreeViewer and TableViewer, which are model-driven components that make use of SWT widgets and adapt content of a model to the widget.
  • Dialogs: The org.eclipse.jface.dialogs package provides several commonly used dialog boxes.
  • Actions: The org.eclipse.jface.actions package provides a UI action framework that's similar to Swing's action framework in order to implement shared behavior between two or more user interface components, such as a menu item and toolbar button.
  • Wizards: The org.eclipse.jface.wizard package provides an advanced framework to create wizards (the familiar dialog boxes that automate repetitive and complex tasks).
  • Resource: The org.eclipse.jface.resource package provides support for managing resources, such as SWT fonts and images.
  • Text: The org.eclipse.jface.text package and its subpackages provide a framework for creating, manipulating, displaying, and editing text documents.

SWT primer

The first step you need to take to start building SWT applications is to get the latest SWT release for your platform. If you've installed the Eclipse IDE on your system, then you already have all the necessary JARs and native libraries. If you don't have Eclipse installed, you can obtain SWT as a separate distribution (since release 2.1).

The downloaded file is swt-2.1.1-win32.zip, which is a drop containing the SWT libraries and source code for standalone SWT application development. The zip file contains a jar file (swt.jar), a Windows DLL (dynamic link library) file (or the native library for your chosen platform), a zip file with the source code, and an about.html file.

For the following simple examples, let's place the contents of the SWT distribution file in a directory named lib and the example Java files in the parent directory of the lib directory. Let's start by looking at the simplest SWT application, which simply shows an empty application window:

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SimplestSWTExample {
   public static void main(String []args){
      Display display =new Display();
      Shell shell =new Shell(display);
      shell.setText("Simplest SWT Example");
      shell.pack();
      shell.open();
      while (!shell.isDisposed()){
         if (!display.readAndDispatch()){
            display.sleep();
         }
      }
      display.dispose();
   }
}

To compile the application, use the javac command as usual and include the swt.jar file in the classpath, as follows:

javac -classpath .;lib \swt.jar SimplestSWTExample.java

Let's try to run the example using the javac command as follows:

java -classpath .;lib \swt.jar SimplestSWTExample

The console output should produce the following stack trace:

Exception in thread "main"java.lang.UnsatisfiedLinkError:no swt-win32-
     2135 in java.library.path
   at java.lang.ClassLoader.loadLibrary(Unknown Source)
   at java.lang.Runtime.loadLibrary0(Unknown Source)
   at java.lang.System.loadLibrary(Unknown Source)
   at org.eclipse.swt.internal.Library.loadLibrary(Library.java:108)
   at org.eclipse.swt.internal.win32.OS.<clinit>(OS.java:46)
   at org.eclipse.swt.widgets.Display.internal_new_GC(Display.java:1291)
   at org.eclipse.swt.graphics.Device.init(Device.java:547)
   at org.eclipse.swt.widgets.Display.init(Display.java:1310)
   at org.eclipse.swt.graphics.Device.<init>(Device.java:96)
   at org.eclipse.swt.widgets.Display.<init>(Display.java:291)
   at org.eclipse.swt.widgets.Display.<init>(Display.java:287)
   at SimplestSWTExample.main(SimplestSWTExample.java:10)

The error shown is telling you that in order to run the SWT example, you need the swt-win32 DLL. Notice that as part of the SWT distribution for Windows, you have the swt-win32-VERSION.dll file where VERSION denotes the particular version of the DLL. To make the DLL available to the running JVM use the -Djava.library.path parameter as part of the Java command line as follows (the same applies to other environments such as Linux or Mac OS X):

java -classpath .;lib \swt.jar -Djava.library.path=lib SimplestSWTExample

The output should now resemble what's shown in Figure 4.

Figure 4. A simple SWT example
Tip
If you want to eliminate the need for specifying the classpath and java.library.path options in the Java command line you can integrate the SWT JAR and DLL (for Windows) with your Java Runtime Environment (JRE) by copying the jar files to the JRE's lib/ext directory and the DLL to the JRE's bin directory (the same procedure can be applied to other platforms).

Let's examine the example's code to gain an understanding of how SWT works under the covers. The first object instantiated is of type org.eclipse.swt.widgets.Display, although it's in the SWT widgets package, this class actually isn't a widget but rather a bridge that widgets and other SWT classes use to communicate with the underlying operating system. The Display class extends org.eclipse.swt.graphics.Device (which also has a child class named Printer).

1 2 3 4 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more