Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Open Source

Eclipse 3.0's Rich Client Platform


October, 2004: Eclipse 3.0's Rich Client Platform

Taking the drudgery out of cross-platform UI development

Gene works at TimeSys where he focuses on embedded Linux. He can be contacted at gene.sallyverizon.net. Maciej also works at TimeSys where he focuses on embedded Linux and Java. He can be contacted at maciej.halasztimesys.com.


One of the tremendous engineering feats behind Eclipse is that users don't know they're working with a multiplatform application. The user interface elements (drop-downs, option buttons, hierarchical views, and such) look and operate like other applications on the platform, even though the Eclipse platform is built on the same source code base. This article looks into the technology driving the Eclipse user experience and how you can use it to create your own cross-platform applications.

The Standard Widget Toolkit (SWT) serves as the graphical underpinning for the Eclipse framework, powering a sophisticated IDE. However, the SWT framework isn't only for Eclipse. You can use it by itself or in conjunction with the Rich Client Platform (RCP) when creating multiplatform applications. In this article, I examine the SWT and RCP, and show how to use them to deliver cross-platform applications.

Not Swing

Java graphical user interfaces (GUIs) have long been dominated by Sun's Abstract Widget Toolkit (AWT) and Swing windowing component packages. These two kits are widely used to create Java-compliant graphical components. Both AWT and Swing present a highly abstracted API that shields users from the underlying windowing system. While this thick layer lets AWT and Swing behave more like Java than SWT does, users pay in the form of a suboptimal experience. Neither AWT nor Swing applications look and behave like native applications and they typically result in slower performance as well.

SWT is a thin layer on top of the underlying graphics tool kit, providing just enough abstraction to make the API uniform across platforms. It does not attempt to change the default look or behavior of the windowing system. The result is a high-performance application that looks no different than any other native application. (For details on the SWT design philosophy and how the software is both portable and native, see "SWT: The Standard Widget Toolkit" by Steve Northover; http://www.eclipse.org/articles/Article-SWT-Design-1/SWT-Design-1.html.)

On top of SWT is the JFace toolkit. SWT handles primitives such as text boxes, sliders, and option buttons, while JFace presents higher level controls such as dialogs, panels, and layouts. JFace relies entirely on SWT to render the controls it presents. In turn, the Eclipse core relies mostly on the JFace class libraries (using SWT when necessary) to interact with the user. Figure 1 illustrates how these software packages come together.

Minimal SWT Application

Listing One is all the code you need for a minimal SWT application that presents users with a single dialog application. This code instantiates Display and Shell objects. The Display class is the primary interface between you and the underlying windowing system; it handles the synchronization between the threads of the application and the thread handling in the UI. In some windowing systems (particularly Windows), UI objects have thread affinity, meaning you can't manipulate an object outside of the thread that created the object. The shell is the window managed by the display.

Listing One creates an instance of the dialog displayed to users and opens it in an application modal state, so the application blocks on the open() of the dialog. When users close the dialog, control returns to the calling method and the application quits. This works fine for a single dialog application, but gets complex for applications that have menus, toolbars, and the like. In addition, the code to get this running from the command line is more complex; see Listing Two.

The complicated shell script is necessary so that Eclipse has the right graphics libraries in the class path for SWT and has the path to the location of the native files. While this code could be hidden from users in batch files or shell scripts, it still imposes a maintenance burden because it needs to be different for every platform on which the application runs.

The Rich Client Platform

Because Eclipse is designed to handle the drudgery just described and provide the infrastructure for managing modular development, why not just remove all of the plug-ins and use what's left as the starting point for application development? This is the role of the Rich Client Platform (RCP), introduced with Eclipse 3.0.

The RCP provides the facilities for SWT/JFace and plug-in handling. RCP eliminates all of the housekeeping in the previous example by loading the correct classes for the windowing system, as well as loading plug-ins and waiting for user input.

RCP-based applications are written as Eclipse plug-ins. As such, they start as Eclipse plug-in projects so you can use the wizards that are part of the Eclipse Plug-in Development Environment (PDE) to kick-start RCP development (http://www.eclipse.org/pde/index.html).

For the purposes of this article, I use RCP to write a "Hello World" application in which the code puts the text in the title bar of a dialog box (the complete source code is available electronically; see "Resource Center," page 5). Using the Plug-in Project Wizard, I supply a name and ID for the project; for this example, I use org.eclipse.ui.rcp.testapp for the name with an ID of HelloWorld. On the Plug-in Code Generator wizard page, select the Create a Blank Plug-in Project option button, as none of the code generation wizards suit our needs. (Don't select the Hello World code generation wizard on this panel!)

When the wizard finishes, you have the start of a project where you can begin to add code. Listing Three shows some of the code necessary to launch the dialog. The application relies on Eclipse's org.eclipse.core.runtime package. Once the class has been defined, you can concentrate on making the class display a window with a Hello World title bar.

The starting point of the test application starts (as Java developers would expect) in a run method of the main class. You must ensure that the entire lifecycle of the application starts and ends within this run() method's boundaries.

The class that controls the GUI appearance is the WorkbenchAdvisor, which drives the look-and-feel of the interface. I extend this abstract class in the application and define the application-specific look-and-feel by defining new views, menus, and so on, or by simply defining the initial configuration of the GUI window.

Most of the methods defined for the WorkbenchAdvisor class (preWindowOpen(), openIntro(), and postOpenWindow(), for instance) take the IWorkbenchWindowConfigurator interface as a parameter. Through the configurator interface, you can define properties of the window such as the initial size or the title-bar string (see Listing Four). A full list of parameters that can be manipulated are described in the javadoc for the classes.

The getInitialWindowPerspective() method must be overridden to point to at least one perspective that can be serving as the default for the application. The HelloWorldWorkbenchAdvisor class is where you define windows and menus and the actions behind them. For this application, I create several menus that are similar to what users see in a typical application; see Listing Five. The newly created menu functions (createFileMenu()) first define the string appearing on each menu entry and subsequently define all available entries.

Listing Six presents an implementation of a default perspective. User-defined perspectives implement the IPerspectiveFactory interface. Each perspective manages the views and editors that the application presents at start-up. For the Hello World application to create its own perspective, you need to override the createInitialLayout() method, which is responsible for the addition and layout of views. At this point, all coding for the application is done; see Figure 2.

Since development is now occurring on top of the Eclipse core platform, you can benefit from other plug-ins, further reducing development efforts. When using third-party plug-ins, it's important to understand their prerequisites so that they can be distributed with the application. If you decide to use third-party plug-ins, open the plug-in's manifest for a list of dependencies and dependencies of the dependencies (and so on) until all are known.

Launching Hello World

To launch an RCP application, pass these parameters to the Java VM:

  • Classpath to the RCP jar file.
  • Class with the entry point.
  • The name of the class containing the application the RCP runs.

And Hello World is off and running; see Figure 3. (For Linux, use this command line, java -cp startup.jar org.eclipse.core.launcher.Main -application org.eclipse.ui.rcp.testapp.HelloWorld.)

Packaging and Deployment

The easiest way to create a deployment image of the application is to create a "feature" for referencing your plug-in and its components in the Eclipse RCP. The feature works like a manifest for the application, listing the required plug-ins.

While you could spelunk around to discover the plug-ins necessary for the RCP, the easiest way is to download a feature in Eclipse that contains references to the plug-ins used by the RCP. The project is located on the Eclipse CVS server (http://www.eclipse.org/tools/index.html), which you can access by opening a CVS connection to :pserver:anonymousdev.eclipse.org:/home/eclipse. Once you've connected, check out the org.eclipse.rcpHelper project in the pde-build-home/articles/export rcp apps/feature folder.

After adding the org.eclipse.rcpHelper application to your workspace, open feature.xml for your application, go to the Advanced tab, and add the org.eclipse.rcpHelper feature to the list of included features. Now your application will pull in the necessary components when building the feature. Next, you'll need to tell the feature about where to find the startup.jar file by adding the following to your feature's build.properties files:

root = absolute:file:
<eclipse installation directory>/startup.jar

Finally, you'll need to add Listing Seven so the builder for the feature knows how to build the config.ini file for the application. Once this is done, you can use the Export|Deployable features to create a zip or jar file with your application.

Conclusion

There are a number of ways to write and deploy SWT applications. In this article, I present two methods for creating SWT-based applications—one using the bare-bones SWT classes and another with Eclipse 3.0's Rich Client Platform. With the introduction of the RCP, leveraging Eclipse's plug-in architecture has never been easier. The next time your requirements specify a cross-platform UI, RCP can go a long way toward creating a professional user experience, while letting you take advantage of the plug-in development model offered by Eclipse.

DDJ



Listing One

public class CUserInterface {
    private Display m_display;
    public void go(String[] args) {
        m_display = new Display();
        Shell shell = new Shell(m_display);
        CAppDialog targetDialog = new CAppDialog(shell, null);
        // hopefully this will have a dispatch loop built in!
        targetDialog.setBlockOnOpen(true);
        targetDialog.open();
        m_display.dispose();
    }
    public static void main(String[] args) {
        CUserInterface userInterface = new CUserInterface();
        userInterface.go(args);
    }
}
Back to article


Listing Two
ECLIPSE=/opt/eclipse/plugins
ECLIPSE_OS=linux
ECLIPSE_ARCH=x86
SWT=${ECLIPSE}/org.eclipse.swt.${ECLIPSE_WS}
                        _2.1.1/os/${ECLIPSE_OS}/${ECLIPSE_ARCH}
JDTCORE=${ECLIPSE}/org.eclipse.jdt.core_2.1.1/jdtcore.jar
WORKBENCH=${ECLIPSE}/org.eclipse.ui_2.1.1/workbench.jar
SWT2=${ECLIPSE}/org.eclipse.swt.${ECLIPSE_WS}
                       _2.1.1/ws/${ECLIPSE_WS}/swt.jar
LIBPATH=${ECLIPSE}/org.eclipse.swt.${ECLIPSE_WS}
                       _2.1.1/os/${ECLIPSE_OS}/${ECLIPSE_ARCH}
CLASSPATH=userinterface.jar;${SWT};${JDTCORE};${WORKBENCH};${SWT2}
ENTRYPOINT=CUserInterface

java -cp ${CLASSPATH} -Djava.library.path=${LIBPATH} ${ENTRYPOINT}
Back to article


Listing Three
public class HelloWorldApplication implements IPlatformRunnable {
  public Object run(Object args) {
    Display helloDisplay = PlatformUI.createDisplay();
    WorkbenchAdvisor helloWorkbenchAdvisor = new HelloWorldWorkbenchAdvisor();
    try {
      int returnCode = PlatformUI.createAndRunWorkbench(helloDisplay,
                    helloWorkbenchAdvisor);
 ...
       }
    } finally {

      display.dispose();
    }
  }
}
Back to article


Listing Four
public class HelloWorldWorkbenchAdvisor extends WorkbenchAdvisor {
    public String getInitialWindowPerspectiveId() {
        return "org.eclipse.ui.rcp.testapp.HelloWorldPerspective";
    }
    public void preWindowOpen(IWorkbenchWindowConfigurer configurer) {
        super.preWindowOpen(configurer);
        configurer.setInitialSize(new Point(500, 300));
        configurer.setTitle("Hello World");
    }
}
Back to article


Listing Five
private void fillMenuBar(IWorkbenchWindow window, 
                                  IActionConfigurer configurer) {
    IMenuManager helpMenuBar = configurer.getmenuManager();
    helpMenuBar.add(createFileMenu(window));
    helpMenuBar.add(createViewMenu(window));
    // add more menus here, if necessary
}
Back to article


Listing Six
public class HelloWorldPerspective implements IPerspectiveFactory {
    public HelloWorldPerspective() {
    }
    public void createInitialLayout(IPagelayout layout) {
        layout.setEditorAreaVisible(true);
        // creation of view class left as exercise for the reader
        layout.addView(...);
        layout....;
    }
}
Back to article


Listing Seven
osgi.bundles = org.eclipse.core.runtime.start,
 org.eclipse.core.expressions, org.eclipse.help, \
  org.eclipse.jface, org.eclipse.osgi.services, org.eclipse.osgi, 
                            org.eclipse.swt, org.eclipse.swt.gtk, \
  org.eclipse.swt.carbon, org.eclipse.swt.gtk64, 
                     org.eclipse.swt.motif, org.eclipse.swt.photon,\
  org.eclipse.swt.win32, org.eclipse.ui.workbench, org.eclipse.ui, 
                            org.eclipse.ui.rcp.testapp.HelloWorld
eclipse.application = org.eclipse.ui.rcp.testapp.HelloWorld
Back to article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.