BUY THIS BOOK
Add to Cart

Print Book $29.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £20.95

What is this?

Looking to Reprint this content?


SWT: A Developer's Notebook
SWT: A Developer's Notebook

By Tim Hatton
Price: $29.95 USD
£20.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Getting Started
One of the most exciting trends in software development is the move toward the use of open source tools and components to assist developers in quickly and easily completing assigned programming tasks. One of the most successful of the open source platforms is Eclipse, an open source Integrated Development Environment (IDE) which is designed to enable developers to write code in any language, for any platform, using a standardized IDE. Eclipse has been downloaded by more than 18 million developers worldwide and forms the basis for IBM's WebSphere Application Developer, perhaps the most popular Java development environment in the corporate world.
One aspect of Eclipse is the Standard Widget Toolkit (SWT), a set of components that enable the developer to easily build GUIs. Although Java itself has built-in capability to develop graphical applications using the Abstract Windowing Toolkit (AWT) and the Java Foundation Classes (Swing) components, these toolkits have been tarred with the brush of sluggish performance and an inability to deliver user interfaces that appear to seamlessly integrate with the operating system platform for which the GUI was developed. Such is the price we pay for the promise of Java—write once, run anywhere.
The SWT provides the ability to write once, run natively. SWT delivers this capability by delivering the code necessary to create the on-screen widgets in an operating-system-specific library, and allowing access to that library from a thin layer of Java classes that make calls to that native code using the Java Native Interfaces (JNI). This affords developers the best of both worlds. Graphical interfaces run in fast native code, while applications can be developed entirely in Java, preserving the ability to write a single code base across multiple platforms. By shifting the on-screen presentation to native code, Java applications have the same look and feel as applications developed entirely in native code on a particular platform. SWT developers also gain from the performance boost of having the code that does the heavy lifting of drawing graphics being performed in compiled code executing outside the Java Virtual Machine (JVM). The only downside is the requirement that you deploy a separate, and different, runtime library for each platform upon which you want to execute your finished product.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Downloading the SWT Library
The basic Eclipse download doesn't contain the classes and libraries needed to do SWT development. These must be downloaded separately from the Eclipse web site.
Visit http://www.eclipse.org/downloads/index.php online for the SWT download (the web page is shown in Figure 1-1).
Figure 1-1: Downloading SWT releases
The Eclipse web site has a list of mirror sites for downloading in case the Eclipse site happens to be overloaded.
From here, click Main Eclipse Download Site, which will take you to the window shown in Figure 1-2.
Figure 1-2: The current Eclipse builds
From this window, choose the build of Eclipse that you wish to use. This book uses the 3.0M8 version. Clicking that version in Figure 1-1 takes you to .
Figure 1-3: The SWT download area
Here you will find 11 (as of this writing) different versions of the SWT, one for each supported platform. Download the file that matches your development environment and extract the files to a location on your development machine.
For my system, I downloaded the version for Windows 98/ME/2000/XP. This downloaded a file called swt-3.0M8-win32.zip, which I then expanded into a directory on my local machine, C:\swt.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Configuring Eclipse for SWT Development
To gain access to the promise of the SWT, you must first configure your development environment to allow access to the packages and libraries that contain both the thin Java layer as well as the compiled native layer. In this book, all examples are developed using Eclipse 3.0M8, but there is nothing to stop you from writing the code using any other available IDE, including Notepad or vi, with no changes necessary to the code.
No matter what development tool you use, you must do two things before you can develop using the SWT:
  • Add the SWT JAR to the compiler classpath.
  • Add the native library for your platform to your Java Runtime Engine's (JRE's) library path.
If you are using Notepad or vi, do this by specifying command-line parameters at compile and execution time, as shown in Figure 1-4 and Figure 1-5.
Figure 1-4: Specifying the classpath from the command line
Figure 1-5: Specifying the location of the SWT classes and native library for the JRE
The same requirements apply even if you are using an environment such as Eclipse. The difference is that, in Eclipse, you can specify these settings using graphical tools on a per-project basis and have them applied every time you compile or run your code, just as if you were using an Ant script or a batch file from the command line. Since these are two distinct steps, each is covered in a separate lab in the following sections.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Supplying the SWT Package to the Java Compiler
First, you've got to let javac know where to find the SWT libraries so that it can compile your applications.
You first need to create a Java project, and then specify the Java Build Path for that project.
The Java Build Path in Eclipse is the equivalent of specifying the -classpath option for the javac compiler on the command line.
The Java Build Path in Eclipse may be specified either at the time the project is created, or later by selecting Project Properties from the Eclipse menu. Either way, you will invoke a dialog similar to that shown in Figure 1-6, the Project Properties dialog. Select Java Build Path from the list on the left side of the dialog, which will reveal the set of tabs shown in the figure. Click the Libraries tab to specify the SWT packages required for your project.
Figure 1-6: Specifying the Java Build Path
On the Libraries tab, click the Add External JARs button and use the dialog shown in Figure 1-7 to locate the JAR file that contains the SWT classes (you should have these from Section 1.1 Section 1.1. This file is normally called swt.jar and will be located in the directory where you extracted the SWT development files.
Figure 1-7: Locating the swt.jar file
Make sure you include swt.jar in your final distribution so that your code can locate the SWT classes at runtime.
Navigate to the JAR file and click Open; this adds swt.jar into the Java Build Path for the project and returns you to the Project Properties dialog, as shown in Figure 1-8. You should see a reference to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Specifying the Location of the Native Library
The second step in configuring Eclipse for SWT development is to specify the location of the SWT native library that will be passed to the JRE when you run your code within Eclipse for testing purposes. This allows the JRE to load up the native code that handles the tasks of creating and drawing the on-screen widgets. If the JRE is not able to locate this file, a runtime exception will occur.
Since this is a runtime setting, it must be specified as a Run Configuration for your Eclipse project. To specify a Run Configuration, select Run Run from the Eclipse menu. This will invoke the properties dialog shown in Figure 1-9.
Figure 1-9: The Run Configurations dialog
In the Run Configurations dialog, select the type of application (Java Application), then click the New button. This loads the Run Properties dialog, shown in Figure 1-10, where you specify settings that govern how your project is loaded into the JRE. The setting you need to set is located on the Arguments tab.
Since this argument is to be passed to the JVM, it must be entered into the VM arguments text box. The same rules for constructing the argument to pass apply here as when running from the command line.
The argument to pass to java is -Djava.library.path= pathtolibrary, substituting the actual path to the location where you extracted the SWT library files.
Figure 1-10: Setting the runtime arguments
Now Eclipse is configured to allow SWT development and to run your SWT programs from within the Eclipse IDE for testing.
You learned how to specify a runtime property to be passed into the JVM when executing your program. You can learn more about the other arguments that can be passed into the JVM by consulting the Java SDK documentation, or by opening a command prompt and entering
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using swt.jar in Multiple Projects
The Build path set here does not persist across projects. If you have multiple SWT projects, you will need to repeat this process for each. If you are planning on developing many SWT projects, you should consider creating a classpath variable pointing to the location of swt.jar, then using this variable in each project.
To create a classpath variable that can be used in multiple projects, select Windows Preferences from the Eclipse menu; this invokes the dialog shown in Figure 1-11.
Figure 1-11: Specifying classpath variables
Kind of like creating a special batch file or Ant script to do the same thing.
In the tree on the lefthand side of the window, expand the Java branch and select Classpath Variables, then click the New button to display Figure 1-12.
Figure 1-12: Creating a variable entry
In this window, provide a name for the variable (SWT) and the path to the location of the swt.jar file. Click OK to return to the dialog shown in Figure 1-11, with your new entry displayed.
To use your variable in a project, use the Project Properties page, as you did earlier (Figure 1-8). Instead of locating the swt.jar file manually by clicking Add External JARs, click Add Variable to invoke Figure 1-13.
Figure 1-13: Selecting a classpath variable
In Figure 1-13, you see all the variables that are declared in Eclipse. Select SWT and click OK. This returns you to the Project Properties dialog showing your selection as part of the project, as shown in Figure 1-14.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: SWT Shells
The foundation from which you build every GUI is the window, so it's appropriate to begin discussion of the SWT by examining the classes that provide you with the ability to rapidly develop windows of all types.
If you look at all the different operating systems available, you soon realize that GUI windows come in all manner of types. These windows look and behave differently on the MS Windows platform than they do on Motif running under Unix, or KDE running under Linux. Even on a single platform, GUI windows may look and behave differently across versions—compare, for example, applications running under Windows 95, 98, NT, 2000, or XP. Fortunately for us developers, the code necessary to manage these differences is contained in the SWT library for a particular platform and is nicely abstracted for us in the SWT Java classes that we use to access that library. You write your code once, and allow the SWT native library to handle the differences between platforms.
We use two SWT classes to create windows: Display and Shell. Display is the class responsible for managing the interaction between all SWT widgets and the underlying operating system. It is in Display that you find methods that enable you to directly query the operating system for information about things such as which control currently has the focus and what windows are currently open and attached to the display. You will not need to interact directly with the display very often.
The second class, Shell, is much more important to the programmer. Instances of Shell represent windows which are currently being managed by the desktop (on MS Windows) or the windows manager (on Unix or Linux systems). Shells can be created either directly on the display, or within the confines of a parent shell. In this chapter, you will learn to develop code that creates both types of shells.
The first type of shell you need to learn to create is the simple, high-level window that is opened directly on the display.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating a Simple Shell
The first type of shell you need to learn to create is the simple, high-level window that is opened directly on the display.
Two coding steps are always needed to create a window:
  1. Create an instance of the Display class.
  2. Pass the instance of Display to the Shell constructor to create an instance of the Shell class.
Example 2-1 is the code that creates a basic shell, managed directly by the display.
Example 2-1. A very simple shell
import org.eclipse.swt.widgets.*;

public class SimpleShell {
    
     SimpleShell( )    {
        Display d = new Display( );
        Shell s = new Shell(d);
        s.setSize(500,500);
        s.open( );
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );
    }
}
Running on a Windows XP system, this code creates the dialog shown in Figure 2-1 when executed.
Figure 2-1: SimpleShell executing on Windows XP
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Executing the Example
To execute the examples in this book, you will need to do one of two things—either create a runner class or include a main( ) method in each example.
The first approach is to create a simple class called Runner, shown in Example 2-2.
Example 2-2. A Runner class to execute examples
public class Runner {
    
    public static void main(String[] args){
        SimpleShell ss = new SimpleShell( );        
    }
}
Each time you change the class name of the example you wish to run, you must change the name of the class that's being instantiated in your Runner class (which is a bit of a pain, admittedly).
The second approach is to embed a main() method in each example class you create, like this:
import org.eclipse.swt.widgets.*;

public class SimpleShell {
    
     // Class body from previous lab
    public static void main(String [] args)
    {
        SimpleShell ss = new SimpleShell( );
    }
}
In this book, I will use the Runner class method so that I can keep the example code clean of code not directly related to the technique being demonstrated.
If you embed a main( ) method in each class, you have to go through the process of creating a Run Configuration for each one. What a mess that is.
In Eclipse, to execute a class that contains a main( ) method you must create a Run Configuration. To do this, select Run Run from the Eclipse menu. This invokes the dialog shown in Figure 2-2.
Figure 2-2: The Eclipse Run settings dialog
You saw this dialog in Chapter 1, but there you dealt with settings on the Arguments tab. Here, specify the name of your Runner class on the Main tab, then check the Arguments tab to make certain you passed the location of the SWT native library to the JRE, as you learned to do in Chapter 1.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Shell Styles
Windows come in all types, shapes, and sizes. Some have titlebars, some don't. Some have minimize, maximize, and close buttons, and some don't. You need some way to control the appearance of windows, and with the SWT Shell class, you do that by using a second constructor that enables you to pass a style— an integer value the class uses to determine what attributes to show or hide.
To specify a style for a shell, the SWT provides us with a set of enumerated values encapsulated in another class called SWT. The SWT class is located in the org.eclipse.swt package. For shells, the enumerated values are BORDER , CLOSE, MIN, MAX, NO_TRIM, RESIZE, and TITLE. Also, two convenience values—SHELL_TRIM and DIALOG_TRIM combine several of the style attributes to create two common looks for windows.
The Shell class has multiple constructors. You utilized one of those earlier when you created an instance of your first shell:
Shell s = new Shell(d);
This constructor accepted only an instance of the Display class as an argument. To open an instance of Shell that accepts a style value, you must use a different constructor:
Shell(Display display, int style)
As you can see from this constructor's prototype, you are permitted to pass in only a single int value to control all the attributes. This means that you must have some way to combine the enumerated values in any combination you require. In Java programming, you can combine these values using the | operator, as follows:
Shell s = new Shell(d, SWT.CLOSE | SWT.RESIZE);
You can use any combination of the enumerated values to achieve the effect you desire, or you can use one of the two convenience values, SHELL_TRIM or DIALOG_TRIM, to specify the two most common combinations.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating a Shell Styles Example
To demonstrate how different style combinations affect the appearance and functionality of a shell, create a modification to your earlier SimpleShell example and pass the Shell constructor a different combination of styles.
Example 2-3 is similar to the earlier SimpleShell class, modified to specify a window that has a close button, has no min or max button, and is resizable.
Example 2-3. Setting the shell styles
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class ShellStylesExample {
    ShellStyles( )    {
        Display d = new Display( );
        Shell s = new Shell(d, SWT.CLOSE | SWT.RESIZE);
        s.setSize(300,300);
        s.open( );
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );
    }
}
The only difference between this class and the SimpleShell example is that the second constructor form is used and the style parameter is used to specify the desired window attributes.
Next, modify the Runner program to load up an instance of ShellStylesExample, as demonstrated in Example 2-4 .
Or you can create a Run Configuration for the new class.
Example 2-4. Revised Runner class
public class Runner {
    
    public static void main(String[] args){
        ShellStylesExample sse = new ShellStylesExample ( );        
    }
}
This is the last time I will show you how to modify the Runner class. You should have the idea down pat by now.
The result of ShellStylesExample is as shown in Figure 2-3. You see only a close button displayed on the titlebar and the window is resizable.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Child Shells
It is often necessary to open windows that appear not on the desktop or window manager, but within another window. One example of this is the ever-popular Multiple Document Interface (MDI) found in earlier versions of applications such as Microsoft Excel. Another example would be a prompt to the user for information or a display of some type of message.
Figure 2-3: Result of ShellStylesExample
MessageBox and other common forms of dialogs are created from another set of SWT classes and are discussed in Chapter 17.
To open a window within a window, use a third constructor of the Shell class:
Shell(Shell parent)
You can also use a similar constructor that enables you to specify a style:
Shell(Shell parent, int style)
These constructors behave exactly the same as in the earlier examples, except that they cause the shell being opened to be displayed within the shell that is the parent, instead of displaying directly upon the desktop or the window manager.
Example 2-5 creates an instance of Shell that is suitable for opening within the confines of a parent shell.
Example 2-5. A child shell
import org.eclipse.swt.widgets.*;
public class ChildShell {
    
    
ChildShell(Shell parent
){
        Shell child = new Shell(parent);
        child.setSize(200,200);
        child.open( );        
    }
}
The ChildShell constructor enables you to pass in a reference to the shell that will serve as the parent:
ChildShell(Shell parent)
That reference is then passed to a Shell constructor that accepts a reference to another instance of Shell as a parent rather than as a Display reference:
Shell child = new Shell(parent);
This causes child
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Multiple Child Windows
Often you will need to create more than just a single child window within your main window. You can create many instances of ChildShell, using ChildShellExample as the parent, simply by creating new instances of ChildShell.
The code required to create multiple child windows is shown in Example 2-7. All you do is create a new instance of ChildShell for each window desired.
Example 2-7. Creating multiple instances of ChildShell
import org.eclipse.swt.widgets.*;

public class ChildShellExample {
    Display d = new Display( );
        
    ChildShellExample( )    {    
        Shell s = new Shell(d);
        s.setSize(500,500);
        s.open( );
        ChildShell cs1 = new ChildShell(s);
        ChildShell cs2 = new ChildShell(s);
        ChildShell cs3 = new ChildShell(s);
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );

    }
}
Running Example 2-7 creates three child windows, as shown in Figure 2-5.
Figure 2-5: Opening multiple child windows
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Opening True Dialogs
ChildShellExample demonstrated how to open a child window within the confines of a parent window, but this is not the same as opening a true dialog. A dialog window is one that halts processing of code in the parent window until the user takes some action in the dialog. In ChildShellExample, the parent window code continued to execute even while the child window was opened. You can see the effect if you execute Example 2-8.
Example 2-8. Demonstrating the effect of opening a child on the parent
import org.eclipse.swt.widgets.*;

public class ChildShellExample {
    Display d = new Display( );
        
    ChildShellExample( )    {    
        Shell s = new Shell(d);
        s.setSize(500,500);
        s.open( );
        ChildShell cs1 = new ChildShell(s);
        System.out.println("Execution Continues");
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );

    }
}
If you execute this version of ChildShellExample, you see that the message is printed to the Console immediately after the child window is opened. What if you need to wait for the user to take some action in the child window before knowing how to proceed? For this, you must use a special form of window known as a dialog. The SWT provides the capability to work with dialogs in the form of the Dialog class.
The Dialog class enables you to create custom dialogs—those on which you can place any widget you desire. A dialog is simply another type of shell, except that it extends the Dialog class, which encapsulates some additional methods and accepts additional style attributes.
The Dialog class has two style attributes: SWT.APPLICATION_MODAL and SWT.SYSTEM_MODAL . APPLICATION_MODAL, as the name implies, will cause the dialog to halt all processing in the application until the dialog is dismissed.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Setting the Shell Title Text
To create professional-looking windows—those that meet the user's expectations for what a window should look like on a particular platform—it's not enough to just rely upon the SWT to manage the look and feel of the window. Sure, it will have the same look and feel as other windows running on the platform, but it will still be missing certain elements that users expect to see. One of these elements is the title text, used to tell the user the subject matter of the window contents.
Every window that opens in an application should have text in the titlebar area. Setting the text is simply a matter of calling the setText( ) method on the Shell class:
s.setText("A Shell Example");
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Setting the Shell Icon
Another window element is the window icon. If you examine the parent shell in the ShellDialogExample, you notice that there is a generic "window" icon on the right side of the titlebar. Although this icon does not appear on all platforms, when it does appear the user will almost certainly expect that it reflect the type of application and not be the generic "window" icon.
Use the setImage( ) method of the Shell class to specify the image you wish to display, as shown in Example 2-11.
Example 2-11. Setting the shell icon
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;

public class ProfessionalShell {
    
     ProfessionalShell( )    {
        Display d = new Display( );
        Shell s = new Shell(d);
        s.setSize(500,500);
        s.setImage(new Image(d, "c:\\icons\\JavaCup.ico"));
        s.setText("A Shell Example");
        s.open( );
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );
    }
}
Creating an instance of ProfessionalShell generates Figure 2-7, showing a distinct improvement over the generic "window" icon from previous examples.
Figure 2-7: A professional shell
Adding an icon, displaying the appropriate title text, and specifying the correct style for a particular window type will go a long way toward making your windows look the way users expect them to look.
Creating the basic window using the Shell class is only the first step toward generating a professional GUI that users will enjoy using. Most GUIs contain many other elements that users will expect to see in your applications. These include menus, which are discussed in the next chapter, and toolbars, which are examined in Chapter 4.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: SWT Menus
In this chapter you continue your examination of the SWT by looking at another component for designing professional-looking windows—menus. In SWT, the classes provided to help you create menus are Menu and MenuItem, both located in the org.eclipse.swt.widgets package.
Menus are the primary application navigation tool you provide for your users, and it is a rare application that doesn't make use of them. The published standards for designing GUIs specify the types of windows that should display a menu, the functionality the menu should provide, and the names of specific menu items. You can get the same guidance by examining the menu structure of almost any application running on your target platform.
The menu guidelines vary somewhat by platform as far as specific names to be given to menu items and the actual menu structure (what appears under File or Edit, for example). This presents somewhat of a problem for "write once, run anywhere" programming, because SWT won't help when it comes to names, labels, or locations of menu items. As time goes by, the standards for graphical design are merging and this issue will someday vanish into these (theoretical) merged standards. For now, following the Microsoft guidelines should suffice for most platforms.
Most applications will have a minimum of File, Edit, Window, and Help as high-level menu choices, with submenu items varying depending upon the application's functionality. Edit, for example, will almost certainly have Cut, Copy, and Paste items for programs with text capability, but might have directory or folder movement capability for programs that work extensively with lists of items. Other high-level menu items will be application-specific, such as a Report menu if the application generates reports.
The SWT provides two classes to assist in menu creation. These are the Menu and MenuItem classes. Menu is a container class that holds other menus and menu items. Menu represents the highest level of any menu system, the menu bar that appears just below the title of the window. Instances of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating the Menu Bar
The first step in creating a menu system is to create an instance of Menu to serve as the menu bar and attach it to an instance of the Shell class.
Example 3-1 demonstrates how to create a menu bar attached to a simple window..
And if you don't take the time to plan, your menu will look like it grew like a weed instead of being cultivated like a garden.
Example 3-1. Creating the menu bar
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;

public class MenuShell {
    Display d;
    Shell s;
    MenuShell( )    
    {
        d = new Display( );
        s = new Shell(d);
        s.setSize(500,500);
        s.setImage(new Image(d, "c:\\icons\\JavaCup.ico"));
        s.setText("A Shell Menu Example");

        Menu m = new Menu(s,SWT.BAR );
        s.setMenuBar(m);

        s.open( );
        while(!s.isDisposed( )){
            if(!d.readAndDispatch( ))
                d.sleep( );
        }
        d.dispose( );
    }
}
The important code in the example comprises only two lines:
Menu m = new Menu(s,SWT.BAR );
s.setMenuBar(m);
With these two lines you have created an instance of Menu, passing it a reference to its containing Shell, and specifying the SWT.BAR style. The menu is then attached to the window by calling the setMenuBar() method of the Shell class.
How does the Menu class know whether it serves as a menu bar or a high-level menu item such as File? You specify the type of menu created by passing a style attribute to the Menu constructor. As with Shell, the style attributes are specified in the SWT class as enumerated values. For Menu, there are three values to choose from—SWT.BAR, SWT.DROP_DOWN, and SWT.POP_UP .
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding Drop-Down Menus
Executing MenuShell won't display a menu system because no high-level menus have been created and added to the menu bar. To do that, you need to create instances of the MenuItem class using the SWT.CASCADE style.
Create an instance of the MenuItem class for each desired drop down and set the text attribute of each such instance to represent the clickable text the user will see. These instances of MenuItem are what the user will see running across the menu bar (e.g., File). Instances of MenuItem are attached directly to the menu bar by passing a reference to the menu bar in the MenuItem constructor. These MenuItem objects must be given the SWT.CASCADE style. The setText( ) method is called to specify the text you wish to appear on the menu:
MenuItem file = new MenuItem(m, SWT.CASCADE);
file.setText("File");
Next, create a Menu instance to attach to the cascading menu item. This instance of Menu is the container for the individual menu items that appear when the user clicks the cascading menu (i.e., when the menu drops down). This time you pass the Menu constructor the SWT.DROP_DOWN style in addition to a reference to the containing Shell:
Menu filemenu = new Menu(s, SWT.DROP_DOWN);
file.setMenu(filemenu);
Finally, create instances of MenuItem to add to the DROP_DOWN style menu, passing them a reference to the containing Menu instance and specifying the SWT.PUSH style (one of the other available MenuItem styles):
MenuItem openItem = new MenuItem(filemenu, SWT.PUSH);
openItem.setText("Open");
MenuItem separator = new MenuItem(filemenu, SWT.SEPARATOR);
MenuItem exitItem = new MenuItem(filemenu, SWT.PUSH);
exitItem.setText("Exit");
Menu items attached to the drop-down menu can have one of five styles—SWT.CHECK ,
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding Separator Bars
If you examine the menu system for an application running on your chosen platform, you may see that individual menu items are often separated by a line, enabling you to divide the items in a cascading menu into functional groups.
A separator is simply an instance of MenuItem that has been given the SWT.SEPARATOR style:
MenuItem separator = new MenuItem(filemenu, SWT.SEPARATOR);
A separator menu item will take no action and cannot be clicked.
A menu without separators may function okay, but it just won't look good.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating a Complete Menu System
Creating a complete menu system is a matter of duplicating the code seen in Example 3-2 for each high-level menu item that appears on the menu bar.
Example 3-3 creates a menu bar with File, Edit, Window, and Help cascading menus. Each cascading menu drops down to display menu items appropriate to the top-level menu.
Example 3-3. A complete menu system
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;

public class MenuShell {
    Display d;
    Shell s;
     MenuShell( )    {
         d = new Display( );
         s = new Shell(d);
        s.setSize(300,300);
        s.setImage(new Image(d, "c:\\icons\\JavaCup.ico"));
        s.setText("A Shell Menu Example");

        Menu m = new Menu(s,SWT.BAR );
                  
         // create a File menu and add an Exit item
         final MenuItem file = new MenuItem(m, SWT.CASCADE);
         file.setText("File");
         final Menu filemenu = new Menu(s, SWT.DROP_DOWN);
         file.setMenu(filemenu);
         final MenuItem openItem = new MenuItem(filemenu, SWT.PUSH);
         openItem.setText("Open");
         final MenuItem separator = new MenuItem(filemenu, SWT.SEPARATOR);
         final MenuItem exitItem = new MenuItem(filemenu, SWT.PUSH);
         exitItem.setText("Exit");
         
         // create an Edit menu and add Cut, Copy, and Paste items
         final MenuItem edit = new MenuItem(m, SWT.CASCADE);
         edit.setText("Edit");
         final Menu editmenu = new Menu(s, SWT.DROP_DOWN);
         edit.setMenu(editmenu);
         final MenuItem cutItem = new MenuItem(editmenu, SWT.PUSH);
         cutItem.setText("Cut");
         final MenuItem copyItem = new MenuItem(editmenu, SWT.PUSH);
         copyItem.setText("Copy");
         final MenuItem pasteItem = new MenuItem(editmenu, SWT.PUSH);
         pasteItem.setText("Paste");
         
         //create a Window menu and add Child items
         final MenuItem window = new MenuItem(m, SWT.CASCADE);
         window.setText("Window");
         final Menu windowmenu = new Menu(s, SWT.DROP_DOWN);
         window.setMenu(windowmenu);
         final MenuItem maxItem = new MenuItem(windowmenu, SWT.PUSH);
         maxItem.setText("Maximize");
         final MenuItem minItem = new MenuItem(windowmenu, SWT.PUSH);
         minItem.setText("Minimize");
         
         // create a Help menu and add an About item
         final MenuItem help = new MenuItem(m, SWT.CASCADE);
         help.setText("Help");
         final Menu helpmenu = new Menu(s, SWT.DROP_DOWN);
         help.setMenu(helpmenu);
         final MenuItem aboutItem = new MenuItem(helpmenu, SWT.PUSH);
         aboutItem.setText("About");

        s.setMenuBar(m);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding Cascading Submenus
Some menu items that appear in a drop-down menu won't have an action directly associated with them, but will cause another menu to cascade out to the side when the user points to that item (without clicking).
Either approach works as well as the other and you are free to choose which best fits your coding style.
A good demonstration of the ability to cascade submenus is extending the code in Example 3-3 so that the File Open selection permits the user to choose whether to open the ChildExample or DialogExample (from Chapter 2). Such a menu system is shown in Figure 3-3.
Figure 3-3: The cascading Open menu
To convert the Open menu item into a cascading menu to allow for a submenu, first change its style from SWT.PUSH to SWT.CASCADE, and then create menu items to attach to it. The following code creates menu items, with the SWT.PUSH style, with the text Child and Dialog:
final MenuItem openItem = new MenuItem(filemenu, SWT.CASCADE);
openItem.setText("Open");
final Menu submenu = new Menu(s, SWT.DROP_DOWN);
openItem.setMenu(submenu);
final MenuItem childItem = new MenuItem(submenu, SWT.PUSH);
childItem.setText("Child");
final MenuItem dialogItem = new MenuItem(submenu, SWT.PUSH);
dialogItem.setText("Dialog");
To see the effect, alter MenuShell by replacing the code that created the Open menu item with the preceding code, as shown in Example 3-4.
Example 3-4. Creating cascading submenus
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.*;

public class MenuShell {
    Display d;
    Shell s;
     MenuShell( )    {
         d = new Display( );
         s = new Shell(d);
        s.setSize(300,300);
        s.setImage(new Image(d, "c:\\icons\\JavaCup.ico"));
        s.setText("A Shell Menu Example");

        Menu m = new Menu(s,SWT.BAR );
                  
         // create a File menu and add an Exit item
         
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Making Menus Perform the Intended Action
Of course, if you click any of the menu items in the MenuShell example, nothing happens. You must complete one more task to make your menu items perform their intended function—you must attach a Listener to your menu items. As the name implies, a Listener listens for a particular event to occur and then takes some action upon the occurrence.
A Listener is a class that extends one of the Listener interfaces. When an event occurs, the event loop for the main shell of the application dispatches that event to be handled by the Listener attached to the widget that is causing the event to occur. The result is that one of the methods of the Listener will be called. It is in those methods that you develop the code that executes when the event occurs.
The SWT provides you with several Listener interfaces, all a part of the org.eclipse.swt.events or org.eclipse.swt.widgets packages. To use a Listener, first identify the type of event that you are listening for, then call a method to attach that Listener to the widget. Finally, add code to the listener's methods to perform the desired task.
To add a SelectionListener to the MenuItem childItem in MenuExample, use the following code:
childItem.addSelectionListener(new SelectionListener( ) {
     public void widgetSelected(SelectionEvent e) {
         Shell parent = (Shell)maxItem.getParent( ).getParent( );
         ChildShell cs = new ChildShell(parent);
     }
     public void widgetDefaultSelected(SelectionEvent e) {
     }
});
Every widget in the SWT, including MenuItem, has one or more add methods that attach a Listener to the widget. To listen for mouse click events, add a SelectionListener to be called by addSelectionListener() . You pass addSelectionListener() a reference to a class that implements the SelectionListener interface. Usually, this is accomplished by using an anonymous inner class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Other Menu Item Styles
In addition to SWT.SEPARATOR, SWT.PUSH, and SWT.CASCADE, which you have exercised earlier, menu items can have one of two other styles: SWT.RADIO and SWT.CHECK.
The RADIO style assigns multiple menu items to a group of items and allows only one of those items to be selected at any given time. It is analogous to the RADIO style for buttons that you will examine in Chapter 5.
The CHECK style simply places a check icon next to a menu item when the user has selected that option and removes it when the user deselects that option (by clicking the menu while it is in its checked state).
Both of these styles are useful when you want to enable the user to set a system option from the menu and to retain a visual indication of what options have been previously selected.
The following code creates an Options menu with three menu items (plus a separator):
final MenuItem options = new MenuItem(m, SWT.CASCADE);
options.setText("Options");
final Menu optionsmenu = new Menu(s, SWT.DROP_DOWN);
options.setMenu(optionsmenu);
final MenuItem checkItem = new MenuItem(optionsmenu, SWT.CHECK);
checkItem.setText("Checked Option");
final MenuItem optionsseparator = new MenuItem(optionsmenu, SWT.SEPARATOR);
final MenuItem radioItem1 = new MenuItem(optionsmenu, SWT.RADIO);
radioItem1.setText("Radio One");
final MenuItem radioItem2 = new MenuItem(optionsmenu, SWT.RADIO);
radioItem2.setText("Radio Two");
Adding this code to the ShellMenu example class results in the menu shown in Figure 3-4. You can experiment with the menu to see the effects of clicking the various options (see Figure 3-5 and ).
Figure 3-4: The Options menu
Figure 3-5: Clicking Checked Option
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining the State of CHECK and RADIO Menu Items
When you add a Listener to a menu item with the SWT.CHECK or SWT.RADIO style, you need to take extra steps to determine the state of the item. After all, it is the state of the item that controls what action you take in your code.
You add a Listener to a CHECK or RADIO menu item in exactly the same manner as you do for a regular menu item. The difference comes in what code you write in the widgetSelected( ) method for your Listener. Specifically, the action you take will depend upon the state of the menu item (whether checked or unchecked). SWT provides a method to use to determine the menu's state. A typical Listener looks like this:
checkItem.addSelectionListener(new SelectionListener( ) {
      public void widgetSelected(SelectionEvent e) {
          if(checkItem.getSelection(