Skip to main content

skip to main content

developerWorks  >  Open source | Java technology  >

A gentle introduction to SWT and JFace: How to use combo, list, table, and tree controls

And create form layouts and reusable helper methods

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


New site feature

Check out our new article design and features. Tell us what you think.


Rate this page

Help us improve this content


Level: Introductory

Barry Feigenbaum (feigenba@us.ibm.com), Programming Adviser, IBM

19 Jul 2005

This installment of A gentle introduction to SWT and JFace expands on what you've learned about creating simple Standard Widget Toolkit (SWT) applications using Java™ technology, Eclipse, and the SWT and JFace libraries. This installment shows you how to use combo, list, table, and tree controls, as well as form layouts and reusable helper methods.

Programmers use the Standard Widget Toolkit (SWT) and JFace libraries to develop graphical user interfaces (GUIs) for the Eclipse environment, and to develop stand-alone GUI native applications.

In the first installment of this column, "How to create a simple SWT application," I introduced you to Eclipse, the Eclipse SWT, and the JFace GUI tool kits to construct Eclipse and stand-alone rich GUIs. I also introduced the basic label, text, and button GUI controls, and the composite, group, and shell container types. Finally, I showed you how to combine these controls into a simple working application.

Here, you will learn how to add menus to your application, use some list input controls, and use the more advanced table and tree container controls. I also will demonstrate some best practices by employing service methods to easily build GUIs. Finally, I will show you how to extract reusable function into a base application class.

Except where noted, all the widgets and controls discussed are in the org.eclipse.swt.widgets package.

About this column

A gentle introduction to SWT and JFace includes basic articles on developing applications using the Standard Widget Toolkit (SWT) and JFace libraries that come with the base Eclipse software development kit. This column concentrates on using SWT and JFace for stand-alone applications. However, most of what you learn will apply to using them inside the Eclipse workbench.

We will start out with simple GUIs that have limited function and progress toward useful applications. We will introduce most of the standard and custom SWT widgets and many JFace features. Our discussion will include at least one example use of the technology.

This column assumes that you are familiar with the Java programming language and Java technology-based development, and have some understanding of the Java AWT or Swing GUI tool kits.

Menus

All but the most primitive GUI applications require menus. Menus add to any GUI's usability. Menus are dynamically presented selection lists that correspond to functions available for use (often called commands) or GUI states. As you would expect, you create menus with the menu widget. Menus can contain other menus or menuItems, which can contain menus (that is, a hierarchy of menus). MenuItems represent the commands you can perform or the GUI state you selected. Menus can be associated with the application's (that is, shell) menu bar or they can be pop-up menus that float over the application window.

You must define menus as one of three mutually exclusive styles:

  1. BAR acts as the menu bar for the shell
  2. DROP_DOWN drops down from the menu bar or a menu item
  3. POP_UP pops up from the shell, but is contextual to a specific control

Menus support some additional optional styles:

  • NO_RADIO_GROUP does not act as a radio group; use it when the menu contains RADIO-style items
  • LEFT_TO_RIGHT or RIGHT_TO_LEFT selects the text direction

You must define menuItems as one of five mutually exclusive styles:

  1. CHECK can be persistently selected (that is, checked)
  2. CASCADE contains a menu that should drop down
  3. PUSH acts like a button that causes an immediate action
  4. RADIO acts like a CHECK where only one of the items with this type can be selected
  5. SEPARATOR acts as a separator (often a bar) between groups of items; this item has no function

Creating a menu system is fairly complex. Listing 1 shows a code sample that creates an operable menu system.


Listing 1. Creating a menu system and a pop-up menu

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
  :
Shell shell = ...;
  :
Label body = ...;
  :
// Create the menu bar system
Menu main = createMenu(shell, SWT.BAR | SWT.LEFT_TO_RIGHT);
shell.setMenuBar(main);

MenuItem fileMenuItem = createMenuItem(main, SWT.CASCADE, "&File", 
                                       null, -1, true, null);
Menu fileMenu = createMenu(shell, SWT.DROP_DOWN, fileMenuItem, true);
MenuItem exitMenuItem = createMenuItem(fileMenu, SWT.PUSH, "E&xit\tCtrl+X", 
                                       null, SWT.CTRL + 'X', true, "doExit");

MenuItem helpMenuItem = createMenuItem(main, SWT.CASCADE, "&Help", 
                                       null, -1, true, null);
Menu helpMenu = createMenu(shell, SWT.DROP_DOWN, helpMenuItem, true);
MenuItem aboutMenuItem = createMenuItem(helpMenu, SWT.PUSH, "&About\tCtrl+A", 
                                        null, SWT.CTRL + 'A', true, "doAbout");

// add popup menu
Menu popup = createPopupMenu(shell, body);
MenuItem popupMenuItem1 = createMenuItem(popup, SWT.PUSH, "&About", 
                                         null, -1, true, "doAbout");
MenuItem popupMenuItem2 = createMenuItem(popup, SWT.PUSH, "&Noop", 
                                         null, -1, true, "doNothing");

The code sequence creates the following menu bar, with sub-menus and a pop-up menu (see Figure 1, Figure 2, Figure 3, and Figure 4). The body value is a label control with the text "Sample body." The pop-up menu is contextually associated with this control.


Figure 1. Menu bar with File and Help menus
Menu bar with File and Help menus

Figure 2. File menu drop-down
File menu drop-down

Figure 3. Help menu drop-down
Help menu drop-down

Figure 4. Pop-up menu
Pop-up menu

As you can see, menu items can have accelerators (Ctrl+?) and mnemonics (underlined characters identified by &) to help the user select items with the keyboard.

I created these menus with a set of helper methods, shown in Listing 2. Best practice is to create methods like this to use in creating repetitive GUI parts, such as menus. Over time, you can add more support functions to these helper methods and apply them to all use points. These methods also help prompt you for all the required values.


Listing 2. Menu creation helper routines

protected Menu createMenu(Menu parent, boolean enabled) {
    Menu m = new Menu(parent);
    m.setEnabled(enabled);
    return m;
}
protected Menu createMenu(MenuItem parent, boolean enabled) {
    Menu m = new Menu(parent);
    m.setEnabled(enabled);
    return m;
}
protected Menu createMenu(Shell parent, int style) {
    Menu m = new Menu(parent, style);
    return m;
}
protected Menu createMenu(Shell parent, int style, 
                          MenuItem container, boolean enabled) {
    Menu m = createMenu(parent, style);
    m.setEnabled(enabled);
    container.setMenu(m);
    return m;
}
protected Menu createPopupMenu(Shell shell) {
    Menu m = new Menu(shell, SWT.POP_UP);
    shell.setMenu(m);
    return m;
}
protected Menu createPopupMenu(Shell shell, Control owner) {
    Menu m = createPopupMenu(shell);
    owner.setMenu(m);
    return m;
}
protected MenuItem createMenuItem(Menu parent, int style, String text, 
                                  Image icon, int accel, boolean enabled, 
                                  String callback) {
    MenuItem mi = new MenuItem(parent, style);
    if (text != null) {
        mi.setText(text);
    }
    if (icon != null) {
        mi.setImage(icon);
    }
    if (accel != -1) {
        mi.setAccelerator(accel);
    }
    mi.setEnabled(enabled);
    if (callback != null) {
        registerCallback(mi, this, callback);
    }
    return mi;
}

Listing 3 shows how to use the Java reflection feature to link the menu items with the code that processes them. This feature creates an easy-to-use method where you simply add a public method (such as doExit, doAbout, or doNothing) to your application class to process the command.


Listing 3. Callback routines to process menu command

protected void registerCallback(final MenuItem mi, 
                                final Object handler, 
                                final String handlerName) {
    mi.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
            try {
                Method m = handler.getClass().getMethod(handlerName, null);
                m.invoke(handler, null);
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    });
}

I described the details of using a SelectionListener in the first installment of this column, "How to create a simple SWT application."

Please note that menu items (and items in the list, combo, table, and tree controls discussed later) support only string values; other types must be converted to string values before you add them.



Back to top


Combos and lists

Often, you want your GUI's user to select from a predetermined list of values. The list control is the easiest way to do this. A list shows a predetermined set of string values that the user can select from. Lists typically require a large amount of screen real estate. If you want to save space, you can use a combo control that allows the list to drop down when needed. Combos also optionally allow the user to enter the desired value in a text-like field.

You must define combos as one of two mutually exclusive styles:

  1. SIMPLE shows the list of values
  2. DROP_DOWN drops down the list of values

Combos support an optional style:

  • READ_ONLY prevents users from editing the text field of this combo

All the controls I discuss (list, combo, table, and tree) support one of two mutually exclusive styles:

  1. SINGLE users can select only one item
  2. MULTI users can select multiple items

These controls also support additional styles:

  • H_SCROLL shows a horizontal scroll bar when needed
  • V_SCROLL shows a vertical scroll bar when needed

Creating combos and lists is fairly easy. Create the controls and add the desired string values as shown in Listing 4.


Listing 4. Creating a combo and a list using FormLayout

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
  :
setLayout(new FormLayout());

String[] data = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5",
                  "Item 6", "Item 7", "Item 8", "Item 9", "Item 10" };

Combo c = createCombo(this, data);
configureLayout(c, new FormAttachment(0, 5), new FormAttachment(0, 5), 
                   new FormAttachment(100, -5), null);

List l = createList(this, data);
configureLayout(l, new FormAttachment(0, 5), new FormAttachment(c, 5), 
                   new FormAttachment(100, -5), new FormAttachment(100, -5));

// Create a Combo
protected Combo createCombo(Composite parent, String[] data) {
    Combo combo = new Combo(parent, 
                            SWT.DROP_DOWN | SWT.MULTI | 
                            SWT.V_SCROLL | SWT.H_SCROLL);
    combo.addSelectionListener(new SelectionListener() {
        :
    });
    setComboContents(data);

    return combo;
}
// Create a List
protected List createList(Composite parent, String[] data) {
    List list = new List(parent, SWT.MULTI | 
                         SWT.V_SCROLL | SWT.H_SCROLL);
    list.addSelectionListener(new SelectionListener() {
        :
    });
    setListContents(data);

    return list;
}

public void setComboContents(String[] data) {
    combo.removeAll();
    for (int i = 0; i < data.length; i++) {
        combo.add(data[i]);
    }
}
public void setListContents(String[] data) {
    list.removeAll();
    for (int i = 0; i < data.length; i++) {
        list.add(data[i]);
    }
}

If you add the SelectionListener, it enables the application to take action when the user changes the selected items.

The flow of the main code sequence in Listing 4 assumes it is included in some composite referenced by this. It creates the combo and (partially hidden) list shown in Figure 5.


Figure 5. Combo and list example
Combo and list example

You can use an alternate implementation to the combo control, called CCombo (located in the org.eclipse.swt.custom package). CCombo is similar to Combo, except that it supports some additional functions, the most significant being that you can programmatically ask a CCombo to cut, copy, or paste text into or from its embedded Text control. Also, a CCombo is always in the DROP_DOWN style, so it doesn't support the type styles.

CCombos also support optional styles:

  • BORDER shows a border around the text area
  • READ_ONLY prevents users from editing the text field of this combo

FormLayout

The example in Listing 4 uses a FormLayout to place the combo and list. FormLayout is one of the most useful layout managers because it allows you to lay out each control relative to other controls. It allows you to attach any side (left, top, right, or bottom) of a control to the (typically opposing) side of another control or to the side of the container. Unattached sides take the natural corresponding dimension of the control. Use an instance of FormAttachment to specify the reference control or a percentage of the container size as the attachment point, and to provide a pixel offset from that point. The Listing 4 code uses the helper method from Listing 5.


Listing 5. configureLayout: FormLayout helper method

protected static void configureLayout(Control c, 
                                      FormAttachment left, 
                                      FormAttachment top, 
                                      FormAttachment right, 
                                      FormAttachment bottom) {
    FormData fd = new FormData();
    if (left != null) {
        fd.left = left;
    }
    if (top != null) {
        fd.top = top;
    }
    if (right != null) {
        fd.right = right;
    }
    if (bottom != null) {
        fd.bottom = bottom;
    }
    c.setLayoutData(fd);
}



Back to top


Tables

Tables are enhanced forms of lists that support TableColumns. These columns align their data into a more readable format. They also support column names and the ability to resize the columns. To create tables, first create the table control, add its table columns, then add the string data wrapped in TableItems.

Tables support optional styles:

  • CHECK adds check boxes to the first column
  • VIRTUAL support for large tables (platform-specific)
  • FULL_SELECTION selects all columns (not just the first column)

Listing 6 creates the table shown in Figure 6.


Listing 6. Creating a table using helper methods

// Create the Table and TableColumns 
protected Table createTable(Composite parent, int mode, Object[] contents) {
    table = new Table(parent, mode | SWT.SINGLE | SWT.FULL_SELECTION | 
                      SWT.V_SCROLL | SWT.H_SCROLL);
    table.setHeaderVisible(true);
    table.setLinesVisible(true);

    createTableColumn(table, SWT.LEFT,   "Column 1", 100);
    createTableColumn(table, SWT.CENTER, "Column 2", 100);
    createTableColumn(table, SWT.RIGHT,  "Column 3", 100);

    addTableContents(contents);
    return table;
}
protected TableColumn createTableColumn\
(Table table, int style, String title, int width) {
    TableColumn tc = new TableColumn(table, style);
    tc.setText(title);
    tc.setResizable(true);
    tc.setWidth(width);
    return tc;
}
protected void addTableContents(Object[] items) {
    for (int i = 0; i < items.length; i++) {
        String[] item = (String[])items[i];
        TableItem ti = new TableItem(table, SWT.NONE);
        ti.setText(item);
    }
}
  :
// sample creation code
protected void initGui() {
    Object[] items = {
        new String[] {"A", "a", "0"}, new String[] {"B", "b", "1"},
        new String[] {"C", "c", "2"}, new String[] {"D", "d", "3"},
        new String[] {"E", "e", "4"}, new String[] {"F", "f", "5"},
        new String[] {"G", "g", "6"}, new String[] {"H", "h", "7"},
        new String[] {"I", "i", "8"}, new String[] {"J", "j", "9"}
    };
    table = createTable(this, SWT.CHECK, items);
}


Figure 6. Table example
Table example

The check boxes in the first column are optional. Note the alignment of the columns.



Back to top


Trees

A tree is a list that can show hierarchical information. Trees support the application's ability to expand and collapse intermediate levels of the hierarchy.

Because trees often display hierarchical structures, you should provide a data model for them to use (I will revisit this model notion later when I talk about JFace). In my example, I use the inner class Node, shown in Listing 7, for this purpose.


Listing 7. Tree model class node

public class Node {
    protected java.util.List children;
    public java.util.List getChildren() {
        return children;
    }
    public void setChildren(java.util.List children) {
        this.children = children;
    }
    public void addChild(Node node) {
        children.add(node);
    }

    protected String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Node(String name) {
        this(name, new ArrayList());
    }
    public Node(String name, java.util.List children) {
        setName(name);
        setChildren(children);
    }
}

To create trees, first create the tree control, then add the string data wrapped in TreeItems. TreeItems can contain other TreeItems, thus creating the hierarchy of values. Listing 8 creates the tree shown in Figure 7.


Listing 8. Creating a tree using helper methods

// Create the Tree 
protected Tree createTree(Composite parent, int mode, Node root) {
    tree = new Tree(parent, mode | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
    tree.addSelectionListener(new SelectionListener() {
        :
     });
    setTreeContents(root);
    return tree;
}
protected void setTreeContents(Node root) {
    tree.removeAll();
    TreeItem ti = new TreeItem(tree, SWT.NONE);
    setTreeItemContents(ti, root);

}
protected void setTreeItemContents(TreeItem ti, Node root) {
    ti.setText(root.getName());
    java.util.List children = root.getChildren();
    if (children != null && children.size() > 0) {
        for (Iterator i = children.iterator(); i.hasNext();) {
            Node n = (Node)i.next();
            TreeItem tix = new TreeItem(ti, SWT.NONE);
            setTreeItemContents(tix, n);
        }
    }
}
  :
// sample creation code
protected void addChildren(Node n, int count, int depth, String prefix) {
    if (depth > 0) {
        for (int i = 0; i < count; i++) {
            String name = prefix + '.' + i;
            Node child = new Node(name);
            n.addChild(child);
            addChildren(child, count, depth - 1, name);
        }
    }
}

Node root = new Node("<root>");
addChildren(root, 3, 3, "Child");
tree = createTree(this, SWT.CHECK, root);


Figure 7. Tree example
Tree example

The check boxes are optional.



Back to top


Building a base program

Except for the menu example, all the examples in this article use a base class, called BasicApplication, to simplify their implementation. As another best-practice example, I factored out the common features of an SWT GUI application into this base class (including the helper methods from the menu example) to make them easily available.

BasicApplication is a composite that creates its own shell. This class provides additional services, like an exit verification dialog (see Figure 8) and the ability to dump out the widget tree as a diagnostic aid (see an abridged example in Listing 9). See Download for the code to this class.


Figure 8. Confirmation message dialog
Confirmation message dialog

Listing 9. Printout of (partial) control hierarchy

Shell {Tree1App Example}
    Tree1App {}
        Tree {}
            TreeItem {<root>}
                TreeItem {Child.0}
                    TreeItem {Child.0.0}
                        TreeItem {Child.0.0.0}
                        TreeItem {Child.0.0.1}
                        TreeItem {Child.0.0.2}
                    TreeItem {Child.0.1}
                        TreeItem {Child.0.1.0}
                        TreeItem {Child.0.1.1}
                        TreeItem {Child.0.1.2}
                    TreeItem {Child.0.2}
                        TreeItem {Child.0.2.0}
                        TreeItem {Child.0.2.1}
                        TreeItem {Child.0.2.2}
                TreeItem {Child.1}
                        :
                TreeItem {Child.2}
                        :

Listing 10 shows the main method of each subclass (from the combo and list example in Listing 4), and provides the shell's title and size, the application composite's style, and any command-line inputs.


Listing 10. Main method for example list application

public static void main(String[] args) {
     run(List1App.class.getName(), "List1App Example", SWT.NONE, 400, 300, args);
}

Each subclass, which is loaded through Java technology reflection, must define a constructor and the completeGui method. Subclasses may optionally provide the initGui method. Again using the combo and list application in Listing 4 as an example, these methods are shown in Listing 11.


Listing 11. Required methods supplied in the application subclass

public List1App(Shell shell, int style) {
    super(shell, style);   // must always supply parent and style
}

// Allow subclasses to complete the GUI 
protected void completeGui(String[] args) {
    // create GUI here 
    :
}

// Allow subclasses to initialize the GUI 
protected void initGui() {
    // finish GUI and add dynamic contents here
    :
}

MessageBox

Before I close, I will show you how to use the MessageBox control to request the user to input choices.

You must define MessageBoxes as one of five mutually exclusive styles:

  1. ICON_ERROR presents an error message
  2. ICON_INFORMATION presents an information message
  3. ICON_QUESTION presents a question message
  4. ICON_WARNING presents a warning message
  5. ICON_WORKING presents a working message

MessageBoxes support some additional optional styles, all of which present their respective choices on buttons:

  • OK, OK | CANCEL
  • YES | NO, YES | NO | CANCEL
  • RETRY | CANCEL
  • ABORT | RETRY | IGNORE

Listing 12 shows a typical use of MessageBox, which presents the confirmation dialog as seen in Figure 8 when the user closes the application shell.


Listing 12. Using MessageBox to create an exit confirmation dialog

shell.addShellListener(new ShellAdapter() {
        public void shellClosed(ShellEvent e) {
            MessageBox mb = new MessageBox(shell, SWT.ICON_QUESTION | SWT.OK | SWT.CANCEL);
            mb.setText("Confirm Exit");
            mb.setMessage("Are you sure you want to exit?");
            int rc = mb.open();
            e.doit = rc == SWT.OK;
        }
});



Back to top


Conclusion

In this second installment of A gentle introduction to SWT and JFace, I introduced more SWT controls: combo, list, table, and tree. I also showed you how to create a base class for your SWT applications and how to use helper methods to make it easier to build GUIs.

The next installment will show you how to create more containers and input controls, and how to use the StackLayout layout manager.




Back to top


Download

DescriptionNameSizeDownload method
Java code samplesos-jface2source.ZIP12.2KBHTTP
Information about download methods


Resources

Learn

Get products and technologies
  • Get the latest version of Eclipse, an open source IDE for application development.

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.


Discuss


About the author

Barry Feigenbaum, Ph.D., is a member of the IBM Worldwide Accessibility Center, which helps IBM make its products accessible to people with disabilities. He has published several books and articles, holds several patents, and has spoken at industry conferences, such as JavaOne. He has served as an adjunct assistant professor of computer science at the University of Texas at Austin and other schools..




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top