Creating a GUI for an Address Book Application

We are going to go through an example of how to create a GUI for an Address Book application. Because this example only shows how to build a GUI, the example application will have no real functionality.

Creating a new Project:

Select File > New > Project, and then select Designer > SWT/JFace Java Project. Set the project name to AddressBook.

Creating a new SWT Application:

Select File > New > Other, then click on Designer > SWT > Application Window and hit Next (alternatively, you can use the drop down menu on the Designer toolbar button). Set the name to AddressBookUI, select the "public open() method" radio button under "Create contents in:" and then click Finish.

Your generated class' source code should look like the following:

public class AddressBookUI {
   
       public static void main(String[] args) {
           AddressBookUI window = new AddressBookUI();
           window.open();
       }
       public void open() {
           final Display display = new Display();
           final Shell shell = new Shell();
           shell.setText("SWT Application");
           shell.open();
           while (!shell.isDisposed()) {
              if (!display.readAndDispatch())
                 display.sleep();
           }
       }
    }

As you can see above, the Designer creates two methods. The open() method contains all your GUI code, and your main() method calls the open() method. In a real application, you may have several classes, and you may want to have your main() method in another class. We will leave it in this class in order to make it easy to run our GUI.

The Designer automatically creates instances of Display and Shell. It sets the name displayed in the title bar of the shell and then opens the shell. The Designer also creates an event loop.

Since the Designer initially generates all the code needed to create a window, we can run the application and see a blank window. While the AddressBookUI.java file is in focus in the editor, select Run > Run As > Java Application. A blank window should appear. Close it by clicking on the X on the top-right corner.

Designing the GUI Window

Expand the editor window by double-clicking on the tab above the editor that shows AddressBookUI.java. Click on the design tab on the bottom of the screen to enter the Designer's design view.

We will be using a NullLayout for the shell, so make sure that you have enabled it by following the instructions that can be found in the NullLayout section of this tutorial. In a real application, it would be best to use layout managers in order to make the application more portable, but for this simple example a NullLayout will be sufficient.

First, we will change the title from "SWT Application" to "Address Book". Select shell in the Control Tree and change the text property in the Inspector to "Address Book".

Next we will create the buttons on the bottom of the window. Select the Button control from the Control Palette. Now on the bottom left corner of the window in the Content Pane, draw out a button. In the Inspector, set the text property to be "New" and set the variable property to be "newButton". Your window in the Content Pane should look something like the following:

Now we create two more buttons called "deleteButton" and "editButton" with the text as "Delete" and "Edit", respectively.

Now make sure that a button is selected. Click on the "Open definition" button.

You should see the following lines added to your code:

    {
       final Button newButton = new Button(shell, SWT.NONE);
       newButton.setBounds(10, 380, 75, 35);
       newButton.setText("New");
    }
    {
       final Button deleteButton = new Button(shell, SWT.NONE);
       deleteButton.setBounds(85, 380, 75, 35);
       deleteButton.setText("Delete");
    }
    {
       final Button editButton = new Button(shell, SWT.NONE);
       editButton.setBounds(160, 380, 75, 35);
       editButton.setText("Edit");
    }

You should notice the opening and closing braces on the top and the bottom of the code for each button. Within these braces is a block of code that creates and configures the button. Go back to the design view and select the "New" button. Then click on the "Convert local to field" button. The "Convert local to field" button's image changes and its tooltip changes to "Convert field to local".

Switch back to the source view and we will see what occurred by clicking on this button. Look at the top of the class, just before the main() method. You should see a new line added:

   private Button newButton;

Also, "final Button" is removed from the beginning of the button instantiation in its block. Declaring the button outside the block and as a field in the AddressBookUI class allows you see and modify its properties anywhere in the AddressBookUI class.

All that you have to do to convert a control to a field of the class is to click on the "Convert local to field" button. To change the control back to local, just click the button again.

Now convert the other two buttons into fields by clicking the "Convert local to field" button for each of them. We will now finish creating the other buttons. Name these buttons "prevButton", "nextButton", "saveButton", and "cancelButton". Set their text to be "Previous", "Next", "Save", and "Cancel", respectively. To quickly set the text on the buttons, select the button, hold down Alt and click on the button in the Content Pane. Make sure you enable the Allow Direct Edit setting in the Designer's properties. Your window should now look something like this:

Now create a group in the top part of the shell by selecting Group from the Control Palette, click and hold down the mouse button on the top-left corner of the shell, and then drag the group across the rest of the shell. Set the text of the group to "Details".

We now create a label and a text field inside our newly created group. Make sure that the label and the text field are children of group in the Control Tree. If they are, they will be listed under the group and indented a little bit.

Set the label's text to "First Name:" and the text's variable name to "fnameText". Because we will never have to set properties of the label in our code, we will just leave the label as local and keep label's variable name as label. Select fnameText and click on the "Convert local to field" button. Your window should now look something like this:

Click on group in the Control tree and then click on the "Open definition" button. You should see the following code added to your class:

    {
       final Group group = new Group(shell, SWT.NONE);
       group.setText("Details");
       group.setBounds(10, 10, 585, 355);
       {
           final Label label = new Label(group, SWT.NONE);
           label.setBounds(10, 20, 135, 25);
           label.setText("First Name:");
       }
       {
           fnameText = new Text(group, SWT.BORDER);
           fnameText.setBounds(150, 15, 420, 25);
       }
    }

You can see that the group is in a block just like the buttons are. You may notice that the label and the text field are both nested in the group block. This is because they are both children of group. The Designer nests all control blocks inside their parent container's block. The declaration for fnameText is higher up in the source code with the other field declarations. Now return to the design view.

Create five more labels and five more text fields. Set the text in the labels to "Last Name:", "Phone:", "Email:", "Address:", and "Miscellaneous Information". Set the variable names of the text fields to "lnameText", "phoneText", "emailText", "addrText", and "miscText". Under the style complex property of both addrText and miscText, set the v_scroll property to true. This adds vertical scrollbars to the text fields. For all the text fields, make sure that each is a field by clicking on the Convert local to field button. Now your window should look something like this:

Use the Designer's test feature to see what your window will actually look like by clicking on the Test toolbar button. Close the window by clicking on the X in the top-right corner of the window.

Save and run the application. The window we get when we run the application is probably a different size than the window we got when we used the Designer's test feature.

To make the window the size that we specify, right-click on the shell in the Control Tree or Content Pane, and then select Set shell size > Using the setSize() method. Now make sure you resize the shell window on the Content Pane to the desired size. Select the shell and then click on "Open definition". You should see a line similar to the following added:

   shell.setSize(610, 477);

Now try compiling and running your application again. You will notice that your application is now the same size as the shell in the Content Pane.

Note: The Designer will add all the appropriate imports into your code that are necessary for your GUI to work. These are the imports that the Designer has put into our application so far:

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

Creating Menus

Though the professional version of the Designer supports building menus, the free version does not. If we wish to design a menu using the free version of the Designer, we will have to code it ourselves.

In order to create the menu, we will create a method in AddressBookUI called setupMenu(). Since we create the menu on the shell, shell will have to be visible to this method. In the design view, select shell from the Control Tree and click on Convert local to field. The remainder of the creation of the menu will be done in the source view. Add the following line to your list of imports:

import org.eclipse.swt.widgets.*;

Then add the following method to your AddressBookUI class:

    private void setupMenu() {
       //create the menu bar
       Menu menu = new Menu(shell, SWT.BAR);
       shell.setMenuBar(menu);
 
       //add the File option to it
       MenuItem file = new MenuItem(menu, SWT.CASCADE);
       file.setText("File");
 
       //create a menu for the File option
       Menu filemenu = new Menu(file);
       file.setMenu(filemenu);
 
       //add MenuItems to the File menu
       MenuItem prevItem = new MenuItem(filemenu, SWT.NONE);
       prevItem.setText("Previous");
      
       MenuItem nextItem = new MenuItem(filemenu, SWT.PUSH);
       nextItem.setText("Next");
      
       MenuItem seperator = new MenuItem(filemenu, SWT.SEPARATOR);
 
       MenuItem quitItem = new MenuItem(filemenu, SWT.PUSH);
       quitItem.setText("Quit");
 
       //add listeners for the actions
       prevItem.addListener(SWT.Selection, new Listener() {
           public void handleEvent(Event e) {
              System.out.println("Previous menu item selected.");
           }
       });
 
       nextItem.addListener(SWT.Selection, new Listener() {
           public void handleEvent(Event e) {
              System.out.println("Next menu item selected.");
           }
       });
 
       quitItem.addListener(SWT.Selection, new Listener() {
           public void handleEvent(Event e) {
              shell.dispose();
           }
       });
    }

Here, as you can see, we do not use the block style. All controls declared in this method are visible throughout the entire method. This style of coding is called flat style.

Now, just before the shell.open() call in your open() method, place a call to the new setupMenu() method.

    setupMenu();
    shell.open();
    while (!shell.isDisposed()) {
       if (!display.readAndDispatch())
           display.sleep();
    }

If you return to the design view, you will see the menu on the Content Pane. You can click on the individual menu components and change some of their settings, but you cannot create new menu items. Because the menu takes up some space on the shell, the buttons on the bottom of the shell may have part of their bottoms cut off as shown below. Simply resize the shell to fix this.

Now try compiling and running your application. Make sure you can see the console on the bottom of your screen. Then try selecting Previous and Next from the File menu. Messages should be sent to the console when you select one of the menu items. Quit will close the application.

For more information on creating menus, see the tutorial Advanced SWT Widgets.

Creating Event Handlers

We are now almost done creating our GUI. All that is left to do is to create some functionality. This primarily involves setting up event handlers for the buttons. The Designer will set up the proper framework for the event handlers, but we will have to code what we want the application to do when an event is triggered.

We will now go over what sort of actions and events we want to take place in our application.

First, we want all the text fields to initially be non-editable. They will only be editable if we select either the New or the Edit button. The Save and Cancel buttons will initially be disabled.

If the New button is selected, all the text fields will be cleared and made editable, the New, Delete, and Edit buttons will be disabled, and the Save and Cancel buttons will be enabled. The same will happen with the Edit button, except the text fields will not be cleared.

While editing, if either the Save or the Cancel button is selected, the text fields will return to being non-editable, the New, Delete, and Edit buttons will be re-enabled, and the Save and Cancel buttons will be disabled.

If the Delete button is selected, all the text fields will be cleared of their text.

For all the buttons, a message will appear in the console saying which button was pressed.

First of all we will set up the initial window state. To initially make the text fields be non-editable, you can set their style to be read only. Select each text field and under the style complex property in the Inspector, set the read_only property to true. Disabling the Save and Cancel buttons is also easy. Select each button, and then in the Inspector, set the enabled property to false.

Instead of placing all the lines of code that modify the properties of the controls inside the event handlers, we will create methods for each action. This is because an action may take place on several different occasions. This also makes our code more readable. We will create four new methods called clearText(), setTextEditable(), enableEditButtons(), and enableSaveButtons(). They are as follows:

    private void clearText() {
       fnameText.setText("");
       lnameText.setText("");
       phoneText.setText("");
       emailText.setText("");
       addrText.setText("");
       miscText.setText("");      
    }
 
private void setTextEditable(boolean editable) {
       fnameText.setEditable(editable);
       lnameText.setEditable(editable);
       phoneText.setEditable(editable);
       emailText.setEditable(editable);
       addrText.setEditable(editable);
       miscText.setEditable(editable);
    }
   
    private void enableEditButtons(boolean enable) {
       newButton.setEnabled(enable);
       deleteButton.setEnabled(enable);
       editButton.setEnabled(enable);
    }
   
private void enableSaveButtons(boolean enable) {
       saveButton.setEnabled(enable);
       cancelButton.setEnabled(enable);
    }

Now double-click the New button. The view should be switched to your source code and a stub for an event handler should have been created. Make your code look like this:

    {
       newButton = new Button(shell, SWT.NONE);
       newButton.addSelectionListener(new SelectionAdapter() {
           public void widgetSelected(SelectionEvent e) {
              clearText();              
              setTextEditable(true);
              enableEditButtons(false);
              enableSaveButtons(true);
                
              System.out.println("New button selected.");
           }
       });
       newButton.setBounds(10, 380, 75, 35);
       newButton.setText("New");
    }

You can see that when the New button is clicked, the text fields are cleared and made editable, the edit buttons (New, Delete, Edit) are disabled, the save buttons (Save, Cancel) are enabled, and a message is sent to the console saying that the New button was selected.

In the same way, add the following code to each of the buttons.

Delete button:

    clearText();             
    System.out.println("Delete button selected.");

Edit button:

   setTextEditable(true);
    enableEditButtons(false);
    enableSaveButtons(true);
   
    System.out.println("Edit button selected."); 

Previous button:

System.out.println("Previous button selected.");

Next button:

System.out.println("Next button selected.");

Save button:

    setTextEditable(false);
    enableEditButtons(true);
    enableSaveButtons(false);
                
    System.out.println("Save button selected.");

Cancel button:

    setTextEditable(false);
    enableEditButtons(true);
    enableSaveButtons(false);
                
    System.out.println("Cancel button selected.");

Run the application. Play around with it a little bit to see what happens because of the code that you added to your buttons. Look at the console to view the messages that are printed when the buttons are clicked.

We have now finished creating the GUI for a simple Address Book application. Though this application has no real practical use in its current form, a database could be added to make the application a fully functional address book. For information on how you would add functionality to a GUI by adding a database, see the tutorials Client Billing Application and Time-Tracker Application.

For more information on events and event-handling, see the tutorials Basic SWT Widgets and Advanced SWT Widgets.