Skip to content

5. Graphical User Interfaces

Here we aim to show how to build graphical user interfaces with Java. First, we will look at the basic classes that allow us to build a graphical user interface. Initially, we will not use any automatic generation tools. Then we will use JBuilder, a Borland/Inprise development tool that facilitates the development of Java applications and, in particular, the construction of graphical user interfaces.

5.1. The Basics of Graphical User Interfaces

5.1.1. A Simple Window

Consider the following code:


// imported classes
import javax.swing.*;
import java.awt.*;
    
    // the form class
  public class form1 extends JFrame {
    
      // the constructor
      public form1() {
            // window title
            this.setTitle("My first form");
            // window dimensions
            this.setSize(new Dimension(300, 100));
      }//constructor
  
      // test function
      public static void main(String[] args) {
            // Display the form
            new Form1().setVisible(true);
      }
  }//class

Executing the above code displays the following window:

Image

A graphical user interface generally extends the JFrame base class:


  public class form1 extends JFrame {

The JFrame base class defines a basic window with close, maximize/minimize buttons, adjustable size, etc., and handles events on these graphical objects. Here we specialize the base class by setting its title and its width (300 pixels) and height (100 pixels). This is done in its constructor:


      // the constructor
      public form1() {
            // window title
            this.setTitle("My first form");
            // window dimensions
            this.setSize(new Dimension(300, 100));
      }//constructor

The window title is set by the setTitle method and its dimensions by the setSize method. This method takes as a parameter a Dimension object (width, height), where width and height are the window's width and height expressed in pixels.

The main method launches the graphical application as follows:


            new form1().setVisible(true);

A form1-type form is then created (new form1()) and displayed (setVisible(true)), after which the application listens for events occurring on the form (clicks, mouse movements, etc.) and executes those that the form handles. Here, our form does not handle any events other than those handled by the JFrame base class (clicks on close buttons, maximize/minimize, window resizing, window movement, etc.).

When testing this program by running it from a DOS window using:

java form1

to execute the form1.class file, we notice that when we close the window that was displayed, we do not "regain control" of the DOS window, as if the program had not finished. This is indeed the case. The program executes as follows:

  • Initially, a first execution thread is launched to execute the main method
  • when this method creates the form and displays it, a second thread is created to specifically handle events related to the form
  • after this creation, and in our example, the main method’s thread terminates, leaving only the GUI execution thread.
  • When the window is closed, it disappears but does not interrupt the thread in which it was running
  • For now, we are forced to stop this thread by pressing Ctrl-C in the DOS window from which the program was launched.

Let’s verify the existence of two separate threads: one in which the main method runs, and the other in which the GUI window runs:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;

// The form class
 public class form1 extends JFrame {
    
 // the constructor
 public form1() {
   // window title
   this.setTitle("My first form");
   // window dimensions
   this.setSize(new Dimension(300, 100));
 }//constructor
  
 // test function
 public static void main(String[] args) {
   // logging
   System.out.println("Start of the main thread");
   // display the form
   new Form1().setVisible(true);
   // continued
   System.out.println("End of main thread");  
 }//main
}//class

Execution yields the following results:

Image

We can see that the main thread has finished while the window is still displayed. Closing the window does not terminate the thread in which it was running. To stop this thread, press Ctrl-C again in the DOS window.

To conclude this example, note the imported packages:

  • javax.swing for the JFrame class
  • java.awt for the Dimension class

5.1.2. Handling an Event

In the previous example, we would need to handle the window’s closure ourselves so that when it occurs, the application stops—which is not currently the case. To do this, we need to create an object that “listens” for events occurring on the window and detects the “window closure” event. This object is called a "listener" or event handler. There are different types of listeners for the various events that can occur on the components of a graphical user interface. For the JFrame component, the listener is called WindowListener and is an interface defining the following methods (see Java documentation)

Method Summary
void
windowActivated(WindowEvent e)
          The window becomes the active window
void
windowClosed(WindowEvent e)
          The window has been closed
void
windowClosing(WindowEvent e)
          The user or the program requested that the window be closed
void
windowDeactivated(WindowEvent e)
          The window is no longer the active window
void
windowDeiconified(WindowEvent e)
          The window switches from minimized to normal state
void
windowIconified(WindowEvent e)
          The window switches from normal state to minimized state
void
windowOpened(WindowEvent e)
          The window becomes visible for the first time

There are therefore seven events that can be handled. All handlers receive a WindowEvent object as a parameter, which we will ignore for now. The event of interest here is the closing of the window, which must be handled by the windowClosing method. To handle this event, we can create a WindowListener object using an anonymous class as follows:


   // creating an event handler
   WindowListener win = new WindowListener() {
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e) {}
     public void windowOpened(WindowEvent e) {}
   };//win definition

Our event handler implementing the WindowListener interface must define all seven methods of this interface. Since we only want to handle the window closing, we only define code for the windowClosing method. When the other events occur, we will be notified but will not take any action. What will we do when we are notified that the window is closing (windowClosing)? We will terminate the application:


     public void windowClosing(WindowEvent e){System.exit(0);}

Here we have an object capable of handling window events in general. How do we associate it with a specific window? The JFrame class has a method addWindowListener(WindowListener win) that allows us to associate a "window" event handler with a given window. So here, in the window constructor, we will write:


   // create an event handler
   WindowListener win = new WindowListener() {
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e) {}
     public void windowOpened(WindowEvent e) {}
   };//win definition
   // This event handler will manage events for the current window
   this.addWindowListener(win);

The complete program is as follows:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// the form class
 public class form2 extends JFrame {
    
 // the constructor
 public form2() {
   // window title
   this.setTitle("My first form");
   // window dimensions
   this.setSize(new Dimension(300, 100));
   // create an event handler
   WindowListener win = new WindowListener() {
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e) { System.exit(0); }
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e) {}
     public void windowOpened(WindowEvent e) {}
   };//win definition
   // This event handler will manage events for the current window
   this.addWindowListener(win);
 }//constructor
  
 // test function
 public static void main(String[] args) {
   // display the form
   new form2().setVisible(true);
 }//main
}//class

The java.awt.event package contains the WindowListener interface. When we run this program and close the window that appeared, we see in the DOS window where the program was launched that the program has finished executing, which was not the case before.

In our program, creating the object responsible for handling window events is a bit cumbersome, as we are forced to define methods even for events we do not want to handle. In this case, instead of using the WindowListener interface, we can use the WindowAdapter class. This class implements the WindowListener interface with seven empty methods. By deriving from the WindowAdapter class and redefining only the methods that interest us, we achieve the same result as with the WindowListener interface but without needing to define the methods that do not interest us. The sequence

  • defining the event handler
  • associating the handler with the window

can be carried out as follows in our example:


   // create an event handler
   WindowAdapter win = new WindowAdapter() {
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//win definition
   // This event handler will handle events for the current window
   this.addWindowListener(win);

Here we use an anonymous class that extends the WindowAdapter class and overrides its windowClosing method. The program then becomes:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// the form class
 public class form2 extends JFrame {
    
 // the constructor
 public form2() {
   // window title
   this.setTitle("My first form");
   // window dimensions
   this.setSize(new Dimension(300, 100));
   // create an event handler
   WindowAdapter win = new WindowAdapter() {
     public void windowClosing(WindowEvent e) { System.exit(0); }
   };//define win
   // This event handler will handle events from the current window
   this.addWindowListener(win); }//constructor
  
 // test function
 public static void main(String[] args) {
   // display the form
   new form2().setVisible(true);
 }//main
}//class

It produces the same results as the previous program but is simpler to write.

5.1.3. A form with a button

Now let's add a button to our window:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// the form class
 public class form3 extends JFrame {
 
    // a button
  JButton btnTest = null;
  Container container = null;
  
 // the constructor
  public Form3() {
    // window title
    this.setTitle("Form with button");
    // window dimensions
    this.setSize(new Dimension(300, 100));
    // Create an event handler
    WindowAdapter win = new WindowAdapter() {
     public void windowClosing(WindowEvent e) { System.exit(0); }
    };//define win
    // This event handler will handle events from the current window
    this.addWindowListener(win);
    // retrieve the window's container
    container = this.getContentPane();
    // select a layout manager for the components in this container
    container.setLayout(new FlowLayout());
    // create a button
    btnTest = new JButton();
    // set its label
    btnTest.setText("Test");
    // add the button to the container
    container.add(btnTest);
  }//constructor
  
 // test function
 public static void main(String[] args) {
   // display the form
   new Form3().setVisible(true);
 }//main
}//class

A JFrame window has a container into which graphical components (buttons, checkboxes, drop-down lists, etc.) can be placed. This container is accessible via the getContentPane method of the JFrame class:


  Container container = null;
..........
    // retrieve the window's container
    container = this.getContentPane();

Any component is placed in the container using the add method of the Container class. Thus, to place component C in the container object above, we write:

container.add(C)

Where is this component placed in the container? There are various component layout managers named XXXLayout, where XXX can be Border, Flow, etc. Each layout manager has its own characteristics. For example, the FlowLayout manager arranges components in a row starting from the top of the form. When a row is full, components are placed on the next row. To associate a layout manager with a JFrame window, use the setLayout method of the JFrame class in the following form:

    setLayout(XXXLayout object);

So in our example, to associate a FlowLayout manager with the window, we wrote:


    // we choose a layout manager for the components in this container
    container.setLayout(new FlowLayout());

You can choose not to use a layout manager and write:

    setLayout(null);

In this case, we must specify the exact coordinates of the component within the container in the form (x,y,width,height), where (x,y) are the coordinates of the component’s top-left corner within the container. This is the method we will use most often going forward.

We now know how components are added to the container (add) and where they are placed (setLayout). All that remains is to identify the

components that can be placed in a container. Here, we place a button modeled by the javax.swing.JButton class:



  JButton btnTest = null;
..........
    // create a button
    btnTest = new JButton();
    // set its label
    btnTest.setText("Test");
    // add the button to the container
    container.add(btnTest);

When you run this program, you get the following window:

Image

If you resize the form above, the container’s layout manager is automatically called to reposition the components:

Image

This is the main benefit of layout managers: maintaining a consistent layout of components as the container’s size changes. Let’s use the null layout manager to see the difference. The button is now placed in the container using the following instructions:


// We choose a layout manager for the components in this container
container.setLayout(null);
    // create a button
btnTest = new JButton();
    // set its label
btnTest.setText("Test");
    // Set its position and dimensions
btnTest.setBounds(10, 20, 100, 20);
    // add the button to the container
container.add(btnTest);

Here, we explicitly place the button at point (10,20) on the form and set its dimensions to 100 pixels wide and 20 pixels tall. The new window looks like this:

Image

If we resize the window, the button remains in the same place.

Image

If we click the Test button, nothing happens. This is because we haven’t yet associated an event handler with the button. To find out what types of event handlers are available for a given component, we can look in its class definition for addXXXListener methods, which allow us to associate an event handler with the component. The javax.swing.JButton class extends the javax.swing.AbstractButton class, which contains the following methods:

Method Summary
void
addActionListener(ActionListener l)
void
addChangeListener(ChangeListener l)
void
addItemListener(ItemListener l)

Here, you need to consult the documentation to determine which event handler handles the button click. It is the ActionListener interface. This interface defines only one method:

Method Summary
void
actionPerformed(ActionEvent e)

The method receives an ActionEvent parameter, which we will ignore for now. To handle the click on the btntest button in our program, we first associate an event listener with it:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_click(evt);
              }
            }//anonymous class
    );//event handler

Here, the actionPerformed method calls the btnTest_clic method, which we define as follows:


public void btnTest_click(ActionEvent evt){
  // console logging
System.out.println("button clicked");
}//btnTest_click

Every time the user clicks the Test button, a message is written to the console. This is shown in the following execution:

Image

The complete program is as follows:


// imported classes
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// the form class
 public class form4 extends JFrame {
 
    // a button
  JButton btnTest = null;
  Container container = null;
  
 // the constructor
  public form4() {
    // window title
    this.setTitle("Form with button");
    // window dimensions
    this.setSize(new Dimension(300, 100));
    // create an event handler
    WindowAdapter win = new WindowAdapter() {
     public void windowClosing(WindowEvent e) { System.exit(0); }
    };//define win
    // This event handler will handle events from the current window
    this.addWindowListener(win);
    // retrieve the window's container
    container = this.getContentPane();
    // select a layout manager for the components in this container
    container.setLayout(null);
    // create a button
    btnTest = new JButton();
    // set its label
    btnTest.setText("Test");
    // Set its position and dimensions
    btnTest.setBounds(10, 20, 100, 20);
    // assign an event handler to it
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_click(evt);
          }
        }//anonymous class
    );//event handler
    // add the button to the container
    container.add(btnTest);
  }//constructor

    public void btnTest_click(ActionEvent evt){
      // console logging
    System.out.println("button clicked");
  }//btnTest_click
    
 // test function
 public static void main(String[] args) {
   // display the form
   new Form4().setVisible(true);
 }//main
}//class

5.1.4. Event Handlers

The main Swing components we will cover are windows (JFrame), buttons (JButton), checkboxes (JCheckBox), radio buttons (JButtonRadio), drop-down lists (JComboBox), lists (JList), scroll bars (JScrollBar), labels (JLabel), single-line text fields (JTextField) or multi-line text fields (JTextArea), menus (JMenuBar), and menu items (JMenuItem).

The following tables list some event handlers and the events they are associated with.

Handler
Component(s)
Registration method
Event
ActionListener
JButton, JCheckbox, JButtonRadio, JMenuItem
public void addActionListener(ActionListener)
Click on the button, checkbox, radio button, or menu item
JTextField
The user pressed [Enter] in the text field
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
The selected item has changed
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
The text in the input field has changed or the input cursor has moved
CaretListener
JTextField, JTextArea
public void addCaretListener(CaretListener)
The input cursor has changed position
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
The slider value has changed
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
the mouse has moved
WindowListener
JFrame
public void addWindowListener(WindowListener)
window event
MouseListener
 
public void addMouselistener(MouseListener)
mouse events (click, entering/leaving a component's area, button pressed, release)
FocusListener
 
public void addFocusListener(FocusListener)
focus events (gained, lost)
KeyListener
 
public void addKeyListener(KeyListener)
keyboard event (key typed, pressed, released)
Component
Method for registering event handlers
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void addItemListener(ItemListener)
JComboBox
public void addItemListener(ItemListener)
public void addActionListener(ActionListener)
Container
public void addContainerListener(ContainerListener)
JComponent
public void addComponentListener(ComponentListener)
public void addFocusListener(FocusListener)
public void addKeyListener(KeyListener)
public void addMouseListener(MouseListener)
public void addMouseMotionListener(MouseMotionListener)
JFrame
public void addWindowListener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void addActionListener(ActionListener)
JPanel
as Container
JScrollPane
as Container
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
like JTextComponent
JTextField
as JTextComponent
public void addActionListener(ActionListener)

All components, except those of the TextXXX type, are derived from the JComponent class and therefore also have the methods associated with that class.

5.1.5. Event handler methods

The following table lists the methods that the various event handlers must implement.

Interface
Methods
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componentHidden(ComponentEvent)
public void componentMoved(ComponentEvent)
public void componentResized(ComponentEvent)
public void componentShown(ComponentEvent)
ContainerListener
public void componentAdded(ContainerEvent)
public void componentRemoved(ContainerEvent)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
ItemListener
public void itemStateChanged(ItemEvent)
KeyListener
public void keyPressed(KeyEvent)
public void keyReleased(KeyEvent)
public void keyTyped(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
TextListener
public void textValueChanged(TextEvent)
InputMethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void caretPositionChanged(InputMethodEvent)
CaretListener
public void caretUpdate(CaretEvent)
WindowListener
public void windowActivated(WindowEvent)
public void windowClosed(WindowEvent)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void windowIconified(WindowEvent)
public void windowOpened(WindowEvent)

5.1.6. Adapter classes

As we saw with the WindowListener interface, there are classes named XXXAdapter that implement the XXXListener interfaces with empty methods. An event handler derived from an XXXAdapter class can then implement only a subset of the methods in the XXXListener interface—specifically, those required by the application.

Suppose we want to handle mouse clicks on a Frame component f1. We could associate an event handler with it using:

    f1.addMouseListener(new MouseHandler());

and write:


    public class MouseHandler implements MouseListener{
        // we implement the 5 methods of the MouseListener interface
        // mouseClicked, ..., mouseReleased)
    }// end class

Since we only want to handle mouse clicks, it is better to write:


public class MouseHandler extends MouseAdapter {
        // We write a single method, the one that handles mouse clicks
        public void mouseClicked(MouseEvent evt){

        }
}// end class

The following table lists the adapter classes for the various event handlers:

Event handler
Adapter
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter
MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

5.1.7. Conclusion

We have just presented the basic concepts of creating graphical user interfaces in Java:

  • creating a window
  • creating components
  • associating components with the window using a layout manager
  • associating event handlers with components

Now, rather than building graphical user interfaces "by hand" as we just did, we will use JBuilder, a Java development tool from Borland/Inprise, version 4 and above. We will use components from the java.swing library, currently recommended by Sun, the creator of Java.

5.2. Building a graphical user interface with JBuilder

5.2.1. Our First JBuilder Project

To familiarize ourselves with JBuilder, let’s build a very simple application: an empty window.

  1. Launch JBuilder and select File/New Project. The first page of a wizard will then appear:

Image

  1. Fill in the following fields:
Project Name
start
This will create a project file named start.jpr in the folder specified in the "Project Directory Name" field
Root Path
Specify the folder where the project folder you are about to create will be located.
Project directory name
Specify the name of the folder where all project files will be placed. This folder will be created in the directory specified in the "Root Path" field

Source files (.java, .html, ...), destination files (.class, ...), and backup files may be placed in different directories. If you leave their fields blank, they will be placed in the same directory as the project.

Click [Next]

  1. A screen confirms the choices made in the previous step

Image

Click [Next]

  1. A new screen asks you to describe your project:

Image

Click [Finish]

  1. Verify that the View/Project option is checked. You should see your project structure in the left pane.

Image

  1. Now let’s build a graphical user interface in this project. Select the File/New/Application option:

Image

In the Class field, enter the name of the class to be created. Here, we used the same name as the project.

Click [Next]

  1. The following screen appears:

Image

Class
interfaceStart
This is the name of the class corresponding to the window that will be created
Title
This is the text that will appear in the window's title bar

Note that above, we have specified that the window should be centered on the screen when the application starts.

Click [Finish]

  1. This is where JBuilder comes in handy.
  • It generates the .java source files for the two classes we named: the application class and the GUI class. These two files appear in the project structure in the left-hand window

Image

  • To access the generated code for the two classes, simply double-click the corresponding .java file. We’ll return to the generated code later.
  • Make sure the View/Structure option is checked. This allows you to view the structure of the currently selected class (double-click on the .java file). Here, for example, is the structure of the début class:

Image

Here we learn about:

  • the imported libraries (imports)

  • that there is a constructor start()

  • that there is a static method main()

  • that there is a packFrame attribute

What is the benefit of having access to a class’s structure?

  • You get an overview of it. This is useful if your class is complex.

  • You can access a method’s code by clicking on it in the class structure window. Again, this is useful if your class has hundreds of lines. You don’t have to scroll through every line to find the code you’re looking for.

The code generated by JBuilder is already usable. Click Run/Run Project or press F9, and you’ll see the window you requested:

Image

Furthermore, it closes properly when you click the window’s close button. We’ve just built our first graphical user interface. We can save our project using the File/Close Projects option:

Image

By clicking All, all projects in the window above will be selected. Clicking OK will close them. If we’re curious enough to navigate, using Windows Explorer, to our project folder (the one specified to the wizard at the start of project setup), we’ll find the following files there:

Image

In our example, we specified that all files (.java source, .class output, .jpr backup) should be in the same folder as the .jpr project.

5.2.2. Files generated by JBuilder for a graphical interface

Let’s now take a look at the .java source files generated by JBuilder. It’s important to know how to read what’s generated, since most of the time we’ll need to add code to what’s already there. Let’s start by opening our project: File/Open Project and select the debut.jpr project. We’ll see the project we built earlier.

5.2.2.1. The main class

Let’s examine the début.java class by double-clicking its name in the window displaying the list of project files. We have the following code:

import javax.swing.UIManager;
import java.awt.*;

public class start {
  boolean packFrame = false;

  /**Build the application*/
  public Start() {
    StartInterface frame = new StartInterface();

    //Validate frames with predefined sizes
    //Compress frames with preferred size informatione.g., from their layout
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Center the window
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }
  /**Main method*/
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new start();
  }
}

Let's comment on the generated code:

  1. The main function sets the window's appearance (setLookAndFeel) and creates an instance of the début class.
  2. The début() constructor is then executed. It creates a frame instance of the window class (new interfaceDébut()). This instance is constructed but not displayed.
  3. The window is then sized based on the information available for each of its components (frame.validate). It then begins its independent existence by displaying itself and responding to user input.
  4. The window is centered on the screen because we requested this when configuring the window with the wizard.

Let’s see what would happen if we reduced the début.java code to its bare minimum, as we did at the beginning of the chapter. Let’s create a new class. Select File/New Class:

Image

Name the new class "start2" and click [Finish]. A new file appears in the project:

Image

The début2.java file is reduced to its simplest form:

public class start2 {
}

Let’s complete the class as follows:

public class start2 {
  // main function
  public static void main(String args[]){
    // create the window
    new StartInterface().show();    // or new StartInterface.setVisible(true);
  }//main
}//start2 class

The main function creates an instance of the interfaceDébut window and displays it (show). Before running our project, we need to specify that the class containing the main function to be executed is now the début2 class. Right-click on the début.jpr project and select the Properties option, then the Execution tab:

21

Image

Here, it is indicated that the main class is début (1). Click the button (2) to select a different main class:

Image

Select début2 and click [OK].

Image

Click [OK] to confirm this choice, then run the project by selecting Run/Run Project or pressing F9. You get the same window as with the "start" class, except that it is not centered since this was not requested here. From now on, we will no longer present the main class generated by JBuilder because it always does the same thing: create a window. From now on, we will focus on the window class.

5.2.2.2. The window class

Let’s now look at the code that was generated for the interfaceDébut class:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceStart extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

  /**Construct the frame*/
  public interfaceStart() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("My first GUI with JBuilder");
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. Imported libraries
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

These are the java.awt, java.awt.event, and javax.swing libraries. The first two were the only ones available for building graphical user interfaces in the early versions of Java. The javax.swing library is more recent. Here, it is required for the JFrame window used in this example.

5.2.2.2.2. The attributes
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

JPanel is a container type in which components can be placed. BorderLayout is one of the layout managers available for placing components within the container. In all our examples, we will not use a layout manager and will place the components ourselves at a specific location within the container. To do this, we will use the null layout manager.

5.2.2.2.3. The window constructor
  /**Construct the frame*/
  public interfaceStart() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("My first GUI with JBuilder");
  }
  1. The constructor begins by stating that it will handle events on the window (enableEvents), then it calls the jbInit method.
  2. The container (JPanel) of the window (JFrame) is obtained (getContentPane)
  3. The layout manager is set (setLayout)
  4. The window size is set (setSize)
  5. The window title is set (setTitle)

5.2.2.2.4. The event handler
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

The constructor had indicated that the class would handle window events. The processWindowEvent method performs this task. It begins by passing the received WindowEvent to its parent class (JFrame); then, if the event is WINDOW_CLOSING—triggered by clicking the window’s close button—the application is terminated.

5.2.2.2.5. Conclusion

The code for the window class differs from that presented in the example at the beginning of the chapter. If we were using a Java code generator other than JBuilder, we would likely have even different code. In practice, we will accept the code generated by JBuilder to build the window so that we can focus solely on writing the event handlers for the graphical user interface.

5.2.3. Drawing a GUI

5.2.3.1. An example

In the previous example, we did not place any components in the window. Let’s now build a window with a button, a label, and an input field:

Image

The fields are as follows:

No.
name
type
role
1
lblInput
JLabel
a label
2
txtInput
JTextField
an input field
3
cmdDisplay
JButton
to display the contents of the txtSaisie text field in a dialog box

Following the same procedure as in the previous project, build the interface2.jpr project without adding any components to the window for now.

Image

In the window above, select the interface2.java class from the window. To the right of this window is a tabbed folder:

Image

The Source tab provides access to the source code of the interface2.java class. The Design tab allows you to visually build the window. Select this tab. You now see the window container, which will hold the components you place in it. It is currently empty. The left window shows the class structure:

Image

this
represents the window
contentPane
its container, into which we will place components, as well as the layout mode for these components within the container (BorderLayout by default)
borderLayout1
an instance of the layout manager

Select the this object. Its properties window will then appear on the right:

Image

Some of these properties are worth noting:

background
to set the window's background color
foreground
to set the color of the text and buttons in the window
JMenuBar
to associate a menu with the window
title
to give the window a title
resizable
to set the window type
font
to set the font for text in the window

With the this object still selected, you can resize the container displayed on the screen by dragging the anchor points around the container:

Image

We are now ready to drop components into the container above. Before doing so, we will change the layout manager. Select the contentPane object in the structure window:

Image

Then, in this object’s properties window, select the layout property and choose the value null from the available options:

Image

This absence of a layout manager will allow us to freely place components within the container. It is now time to select them.

When the Design pane is selected, the components are available in a tabbed folder at the top of the design window:

Image

To build the graphical user interface, we have Swing components (1) and AWT components (2). Here, we will use the Swing components. In the component bar above, select a JLabel component (3), a JTextField component (4), and a JButton component (5), and place them in the container of the Design window.

Image

Now let’s customize each of these three components:

  • the label (JLabel) jLabel1

Select the component to open its Properties window. In the Properties window, modify the following properties: name: lblSaisie, text: Saisie

  • the text field (JTextField) jTextfield1

Select the component to open its properties window. In the window, modify the following properties: name: txtSaisie, text: leave blank

  • the button (JButton): name: cmdAfficher, text: Display

We now have the following window:

Image

and the following structure:

Image

We can run (F9) our project to get a first look at the window in action:

Image

Close the window. We still need to write the procedure associated with a click on the Show button. Select the button to access its Properties window. This window has two tabs: Properties and Events. Select Events.

Image

The left column of the window lists the possible events for the button. A click on a button corresponds to the actionPerformed event. The right column contains the name of the procedure called when the corresponding event occurs. Click on the cell to the right of the actionPerformed event:

Image

JBuilder generates a default name for each event handler in the format ComponentName_EventName, in this case cmdDisplay_actionPerformed. You could delete the default name and enter a different one. To access the code for the cmdDisplay_actionPerformed handler, simply double-click its name above. You are then automatically taken to the class's source pane, positioned on the skeleton of the event handler's code:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

All that remains is to complete this code. Here, we want to display a dialog box containing the contents of the txtSaisie field:

  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "text entered="+txtSaisie.getText(), 
"Verifying input", JOptionPane.INFORMATION_MESSAGE);
 }

JOptionPane is a class from the javax.swing library. It allows you to display messages accompanied by an icon or to request information from the user. Here, we are using a static method of the class:

Image

parentComponent
the "parent" container object of the dialog box: here, this.
message
an object to display. Here, the content of the input field
title
the title of the dialog box
messageType
the type of message to display. Determines the icon that will be displayed in the box next to the message. Possible values:
INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE

Let's run our application (F9):

Image

Image

5.2.3.2. The window class code

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;


public class interface2 extends JFrame {
  JPanel contentPane;
  JLabel lblInput = new JLabel();
  JTextField txtInput = new JTextField();
  JButton cmdDisplay = new JButton();

  /**Create the window*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    lblSaisie.setText("Input");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Inputs & Buttons - 1");
    txtInput.setBounds(new Rectangle(120, 21, 138, 24));
    cmdDisplay.setText("Display");
    cmdDisplay.setBounds(new Rectangle(111, 77, 77, 20));
    cmdDisplay.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdDisplay_actionPerformed(e);
      }
    });
    contentPane.add(lblInput, null);
    contentPane.add(txtInput, null);
    contentPane.add(cmdDisplay, null);
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  void cmdShow_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "text entered=" + txtSaisie.getText(), "Input validation", JOptionPane.INFORMATION_MESSAGE);
  }
}

5.2.3.2.1. The attributes
  JPanel contentPane;
  JLabel lblInput = new JLabel();
  JTextField txtInput = new JTextField();
  JButton cmdDisplay = new JButton();

Here we have the JPanel component container and the three components.

5.2.3.2.2. The constructor
  /**Construct the frame*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    lblSaisie.setText("Input");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Inputs & Buttons - 1");
    txtInput.setBounds(new Rectangle(120, 21, 138, 24));
    cmdDisplay.setText("Display");
    cmdDisplay.setBounds(new Rectangle(111, 77, 77, 20));
    cmdDisplay.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdDisplay_actionPerformed(e);
      }
    });
    contentPane.add(lblInput, null);
    contentPane.add(txtInput, null);
    contentPane.add(cmdDisplay, null);
  }

The interface2 constructor is similar to the constructor of the previous graphical interface we studied. The differences are found in the jbInit method: the window construction code depends on the components placed within it. We can reuse the jbInit code by adding our own comments:

  private void jbInit() throws Exception  {
      // the window itself (size, title)
this.setSize(new Dimension(304, 129));
    this.setTitle("Inputs & Buttons - 1");
        // the component container
    contentPane = (JPanel) this.getContentPane();
        // no layout manager for this container
    contentPane.setLayout(null);
        // the lblSaisie label (text, position, size)
         lblSaisie.setText("Input");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
       // the input field (position, size)
    txtInput.setBounds(new Rectangle(120, 21, 138, 24));
        // the Display button (label, position, size)
    cmdDisplay.setText("Display");
    cmdDisplay.setBounds(new Rectangle(111, 77, 77, 20));
        // the button's event handler
    cmdDisplay.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdDisplay_actionPerformed(e);
      }
    });
        // Add the 3 components to the container
    contentPane.add(lblInput, null);
    contentPane.add(txtInput, null);
    contentPane.add(cmdDisplay, null);
  }//jbInit

Two points are worth noting:

  • this code could have been written by hand. This means that JBuilder is not required to build a graphical user interface.
  • the way the event handler for the cmdAfficher button is set. The event handler for the cmdAfficher component could have been declared using `cmdAfficher.addActionListener(new handler())`, where `handler` would be a class with a public `actionPerformed` method responsible for handling the click on the Show button. Here, JBuilder uses an instance of an anonymous class as the handler:
 new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }

A new instance of the ActionListener interface is created with its actionPerformed method defined on the spot. This method simply calls a method of the interface2 class. All of this is just a workaround to define the event-handling procedures for the window’s components within the same class as the window itself. We could do it differently:

cmdAfficher.addActionListener(this)

which causes the actionPerformed method to be looked for in this, i.e., in the window class. This second method seems simpler, but the first has an advantage: it allows for different handlers for different buttons, whereas the second method does not. In the latter case, the single actionPerformed method must handle clicks from different buttons and therefore must first identify which button triggered the event before it can begin processing.

5.2.3.2.3. Event Handlers

We see the ones we’ve already covered:

  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

    // Click on the "Display" button
  void cmdShow_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "text entered=" + txtSaisie.getText(), "Verifying input", JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusion

From the two projects studied, we can conclude that once the graphical user interface has been built with JBuilder, the developer’s task is to write the event handlers for the events they want to handle for that graphical user interface.

5.2.4. Seeking Help

With Java, you often need help, particularly because of the very large number of available classes. Here are some tips for finding help on a class. Select the Help/Help Topics option from the menu.

Image

The Help screen generally has two windows:

  • the left one, where you enter what you’re looking for. It has three tabs: Table of Contents, Index, and Search.
  • the right-hand window, which displays the search results

Help is available on how to use JBuilder’s help system. In JBuilder’s help, select the Help/Using Help option. This will explain how to use the help system. For example, it will show you the different components of the help viewer:

Image

Let’s take a closer look at the Table of Contents and Index pages.

5.2.4.1. Help: Table of Contents

Image

5.2.4.1.1. Table of Contents: Introduction to Java

Here you will find the basics of Java, but not only that, as shown by the list of topics covered in this section:

Image

5.2.4.1.2. Table of Contents: Tutorials

If we select the Tutorials option in the table of contents above, the window on the right displays a list of available tutorials:

Image

The basic tutorials are particularly useful for getting started with JBuilder. There are many others besides those shown above, and when you want to develop an application, it can be helpful to check first if there is a tutorial that might assist you.

5.2.4.1.3. Contents: The JDK

By selecting the Java 2 JDK 1.3 option, you have access to all the JDK libraries. Generally, this is not the place to look if you need information about a specific class and don’t know which library it is in. However, this option is useful if you’re interested in getting an overview of the Java libraries.

5.2.4.2. Help: Index

Select the Index tab in the left pane of the Help window. This option allows you, for example, to find help on a class. Suppose, for instance, that you want to know the methods of the Swing JTextField input fields. Type JTextField in the search text field:

Image

The Help will return index entries beginning with the text you typed:

Image

All you have to do is double-click on the entry you're interested in, in this case JTextField class. The help for this class will then appear in the right-hand window:

Image

A complete description of the class is then provided.

5.2.5. Some Swing Components

We will now present various applications that use the most common Swing components to explore their main methods and properties. For each application, we will present the graphical interface and the relevant code, particularly that of the event handlers.

5.2.5.1. JLabel and JTextField components

We have already encountered these two components. JLabel is a text component and JTextField is an input field component. Their two main methods are

String getText()
to retrieve the input field’s content or the label’s text
void setText(String text)
to set unTexte in the field or label

The events commonly used for JTextField are as follows:

actionPerformed
indicates that the user has confirmed (by pressing Enter) the entered text
caretUpdate
indicates that the user has moved the input cursor
inputMethodChanged
indicates that the user has modified the input field

Here is an example that uses the caretUpdate event to track changes in an input field:

Image

No.
type
name
role
1
JTextField
txtInput
input field
2
JTextField
txtControl
displays the text from 1 in real time
3
JButton
cmdClear
to clear fields 1 and 2
4
JButton
cmdExit
to exit the application

The relevant code for this application is as follows:

import java.awt.*;
....


public class Frame1 extends JFrame {
  JPanel contentPane;
  JTextField txtInput = new JTextField();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField txtControl = new JTextField();
  JButton CmdClear = new JButton();
  JButton CmdExit = new JButton();

  /**Create the frame*/
  public Frame1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    ....
    txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
      public void caretUpdate(CaretEvent e) {
        txtSaisie_caretUpdate(e);
      }
    });

...
    CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdDelete_actionPerformed(e);
      }
    });
...
    CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdQuitter_actionPerformed(e);
      }
    });
....
}

  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
        // the input cursor has moved
    txtControl.setText(txtInput.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        // exit the application
    System.exit(0);
  }

  void CmdClear_actionPerformed(ActionEvent e) {
        // clear the contents of the input field
    txtInput.setText("");
  }
}

Here is an example of execution:

Image

5.2.5.2. JComboBox component

Image

Image

A JComboBox component is a drop-down list combined with an input field: the user can either select an item from (2) or type text into (1). By default, JComboBoxes are not editable. You must explicitly call the setEditable(true) method to make them editable. To learn more about the JComboBox class, type JComboBox in the help index.

The JComboBox object can be created in several ways:

new JComboBox()
creates an empty combo box
new JComboBox (Object[] items)
creates a combo box containing an array of objects
new JComboBox(Vector items)
same as above, but with a vector of objects

It may seem surprising that a combo box can contain objects when it usually contains strings. Visually, this is indeed the case. If a JComboBox contains an object obj, it displays the string obj.toString(). Recall that every object has a toString method inherited from the Object class, which returns a string that "represents" the object.

The useful methods of the JComboBox class are as follows:

void addItem(Object anObject)
adds an object to the combo
int getItemCount()
returns the number of items in the combo
Object getItemAt(int i)
returns the i-th object in the combo box
void insertItemAt(Object anObject, int i)
Inserts unObjet at position i in the combo box
int getSelectedIndex()
returns the index of the selected item in the combo box
Object getSelectedItem()
returns the selected item in the combo box
void setSelectedIndex(int i)
selects item i in the combo box
void setSelectedItem(Object anObject)
selects the specified object in the combo box
void removeAllItems()
clears the combo box
void removeItemAt(int i)
removes item number i from the combo box
void removeItem(Object anObject)
removes the specified object from the combo box
void setEditable(boolean val)
makes the combo box editable (val=true) or not (val=false)

When an item is selected from the drop-down list, the actionPerformed event is triggered, which can then be used to detect the change in selection within the combo box. In the following application, we use this event to display the item that was selected from the list.

Image

We are only showing the relevant code for the window.

public class Frame1 extends JFrame {
  JPanel contentPane;
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel1 = new JLabel();

  /**Construct the frame*/
  public Frame1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // processing - populate the combo box
    String[] info = {"one", "two", "three", "four"};
    for (int i = 0; i < info.length; i++)
      jComboBox1.addItem(info[i]);
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
        ....

    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
       .... 
  }

  void jComboBox1_actionPerformed(ActionEvent e) {
        // a new item has been selected - display it
    JOptionPane.showMessageDialog(this, jComboBox1.getSelectedItem(),
"actionPerformed", JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. JList component

The Swing JList component is more complex than its counterpart in the AWT library. There are two important differences:

  • The list's content is managed by an object separate from the list itself. Here, we will use a DefaultListModel object, which functions like a Vector but also notifies the JList object whenever its content changes so that the list's visual display updates accordingly.
  • The list does not scroll by default. You must place the list inside a ScrollPane container, which enables scrolling.

In the source code, a list can be defined as follows:

     // the array of list values 
DefaultListModel values = new DefaultListModel();
// the list itself, to which the array of its values is associated
  JList jList1 = new JList(values);
    // the scrollable container in which the list is placed to create a scrollable list
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

To include the jList1 list in the jScrollPane1 container, the code generated by JBuilder proceeds differently:

  • declaration of the container in the window attributes
  JScrollPane jScrollPane1 = new JScrollPane();
  • Then, in the jbInit code, the list is added to the container
    jScrollPane1.getViewport().add(jList1, null);

To add values to the JList1 list above, simply add them to its values array:

    // initialize list
    for(int i=0;i<10;i++)
      values.addElement(""+i);

and you will then see the following window:

Image

How is this interface built?

  • Select a JScrollPane component from the "Swing Containers" page of components and drag it into the window, resizing it to the desired dimensions
  • Select a JList component from the "Swing" page of the components and drop it into the JScrollPane container, where it will occupy the entire space.

The code generated by JBuilder needs to be slightly modified to produce the following code:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  DefaultListModel values = new DefaultListModel();
  JList jList1 = new JList(values);
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel2 = new JLabel();


  /**Build the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // processing
    // add the list to the scrollPane
    // initialize list
    for(int i=0;i<10;i++)
      values.addElement(""+i);
  }

  /**Initialize the component*/
  private void jbInit() throws Exception  {
        ....
        // The jList1 list is associated with the jScrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

Let’s now explore the main methods of the JList class by searching for JList in the help index. The JList object can be constructed in various ways:

Image

One simple method is the one we used: create an empty DefaultListModel V and then associate it with the list to be created using new JList(V). The list’s content is not managed by the JList object but by the object containing the list’s values. If the content was constructed using a DefaultListModel object based on the Vector class, the methods of the Vector class can be used to add, insert, and remove elements from the list. A list can support single or multiple selection. This is set by the setSelectionMode method:

Image

You can determine the current selection mode using getSelectionMode:

Image

The selected item(s) can be obtained using the following methods:

Image

We know how to associate a value vector with a list using the JList(DefaultListModel) constructor. Conversely, we can obtain the DefaultListModel object from a JList by:

Image

We now know enough to write the following application:

Image

The components of this window are as follows:

No.
type
name
role
1
JTextField
txtInput
input field
2
JList
jList1
list contained in a container jScrollPane1
3
JList
jList2
list contained in a jScrollPane2 container
4
JButton
cmd1To2
transfers the selected items from list 1 to list 2
5
JButton
cmd2To1
does the opposite
6
JButton
cmdRaz1
clears list 1
7
JButton
cmdRaz2
clears list 2

The user types text into field (1) and submits it. This triggers the actionPerformed event on the input field, which is used to add the entered text to list 1. Here is the code for this first function:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtInput = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1 = new DefaultListModel();
  DefaultListModel v2 = new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

  /**Build the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

  /**Initialize the component*/
  private void jbInit() throws Exception {
    ...
    txtInput.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
        // JList1 is placed in the jScrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
        // JList2 is placed in the jScrollPane2 container
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
    // The text entered has been validated
    // retrieve it with leading and trailing spaces removed
    String text = txtInput.getText().trim();
    // if it is empty, we don't want it
    if (text.equals("")) {
      // error message
      JOptionPane.showMessageDialog(this, "You must enter text",
        "Error", JOptionPane.WARNING_MESSAGE);
      // end
      return;
    }//if
    // if it is not empty, add it to the values in list 1
    v1.addElement(text);
    // and clear the input field
    txtInput.setText("");
  }/// txtSaisie_actionperformed
}//class

The code to transfer selected items from one list to another is as follows:

  void cmd1To2_actionPerformed(ActionEvent e) {
    // Transfer selected items from list 1 to list 2
    transfer(jList1, jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    // Transfer the selected items from jList2 to jList1
      transfer(jList2, jList1);
  }//cmd2To1

  private void transfer(JList L1, JList L2){
      // Transfer the selected items from list 1 to list 2
      // retrieve the array of indices for the selected items in L1
      int[] indices = L1.getSelectedIndices();
      // anything to do?
      if (indices.length == 0) return;
      // retrieve the values from L1
      DefaultListModel v1 = (DefaultListModel) L1.getModel();
      // and those from L2
      DefaultListModel v2 = (DefaultListModel) L2.getModel();
      for (int i = indices.length - 1; i >= 0; i--) {
        // add the values selected in L1 to L2
        v2.addElement(v1.elementAt(indices[i]));
        // the elements from L1 copied to L2 must be removed from L1
        v1.removeElementAt(indices[i]);
      }//for
  }//transfer

The code associated with the Raz buttons is very simple:

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // clear list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // clear list 2
    v2.removeAllElements();
  }///cmd Raz2

5.2.5.4. JCheckBox checkboxes, JButtonRadio radio buttons

We propose to write the following application:

Image

The window components are as follows:

No.
type
name
role
1
JButtonRadio
jButtonRadio1
jButtonRadio2
jButtonRadio3
3 radio buttons that are part of the buttonGroup1 group
2
JCheckBox
jCheckBox1
jCheckBox2
jCheckBox3
3 checkboxes
3
JList
jList1
a list in a container jScrollPane1
4
ButtonGroup
buttonGroup1
non-visible component - used to group the three radio buttons so that when one is selected, the others are deselected.

A group of radio buttons can be created as follows:

  • Place each radio button without worrying about grouping them
  • Place a Swing ButtonGroup component in the container. This component is non-visual. It therefore does not appear in the window designer. However, it appears in its structure:

Image

Above, in the Other branch, you can see the window’s non-visual attributes. Once a radio button group has been created, you can associate each radio button with it. To do this, select the radio button’s properties:

Image

and in the radio button’s buttonGroup property, enter the name of the group you want to place the radio button in, here buttonGroup1. Repeat this step for all 3 radio buttons.

The main method for radio buttons and checkboxes is the isSelected() method, which indicates whether the checkbox or button is selected. The text associated with the component can be retrieved using getText() and set using setText(String text). The checkbox or radio button can be selected using the setSelected(boolean value) method.

When a radio button or checkbox is clicked, the actionPerformed event is triggered. In the following code, we use this event to track changes in the values of the radio buttons and checkboxes:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JRadioButton jRadioButton1 = new JRadioButton();
  JRadioButton jRadioButton2 = new JRadioButton();
  JRadioButton jRadioButton3 = new JRadioButton();
  JCheckBox jCheckBox1 = new JCheckBox();
  JCheckBox jCheckBox2 = new JCheckBox();
  JCheckBox jCheckBox3 = new JCheckBox();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel values = new DefaultListModel();
  JList jList1 = new JList(values);

  /**Build the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
    jRadioButton1.setSelected(true);
    jRadioButton1.setText("one");
    jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
    jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayRadioButtons(e);
      }
    });

    jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
    jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayRadioButtons(e);
      }
    });
    jRadioButton2.setText("two");

    jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
    jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayRadioButtons(e);
      }
    });
    jRadioButton3.setText("three");

// the radio buttons are grouped
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// checkboxes
    jCheckBox1.setText("A");
    jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayCheckboxes(e);
      }
    });

    jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayCases(e);
      }
    });
    jCheckBox2.setText("B");

    jCheckBox3.setText("C");
    jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
    jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        displayCheckboxes(e);
      }
    });

    ....
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void displayRadioButtons(ActionEvent e){
    // displays the values of the 3 radio buttons
    values.addElement("radio buttons=" + jRadioButton1.isSelected() + "," +
      jRadioButton2.isSelected() + "," + jRadioButton3.isSelected() + ""));
  }//displayRadioButtons

  void displayCheckboxes(ActionEvent e) {
    // displays the values of the checkboxes
    values.addElement("checkboxes=[" + jCheckBox1.isSelected() + "," +
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//displayCheckboxes

}//class

Here is an example of execution:

Image

5.2.5.5. JScrollBar component

Let's create the following application:

Image

No.
type
name
role
1
JScrollBar
jScrollBar1
a horizontal scroll bar
2
JScrollBar
jScrollBar2
a vertical slider
3
JTextField
txtvalueHS
displays the value of horizontal slider 1 - also allows you to set this value
4
JTextField
txtVSvalue
displays the value of vertical slider 2 - also allows you to set this value
  • A JScrollBar slider allows the user to select a value from a range of integer values represented by the slider's "bar," along which a cursor moves.
  • For a horizontal slider, the left end represents the minimum value of the range, the right end the maximum value, and the cursor the currently selected value. For a vertical slider, the minimum is represented by the top end, and the maximum by the bottom end. The (min,max) pair defaults to (0,100).
  • Clicking on the ends of the slider changes the value by one increment (positive or negative) depending on the end clicked, as defined by the unitIncrement parameter, which defaults to 1.
  • Clicking on either side of the slider changes the value by one increment (positive or negative) depending on the end clicked, known as blockIncrement, which defaults to 10.
  • These five values (min, max, value, unitIncrement, blockIncrement) can be retrieved using the methods getMinimum(), getMaximum(), getValue(), getUnitIncrement(), and getBlockIncrement(), all of which return an integer, and can be set using the methods setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), and setBlockIncrement(int bInc)

There are a few things to know when using JScrollBar components. First, it can be found in the Swing component palette:

Image

When you drop it onto the container, it is vertical by default. You can make it horizontal using the orientation property below:

Image

In the properties sheet above, you can see that you have access to the JScrollBar’s minimum, maximum, value, unitIncrement, and blockIncrement properties. You can therefore set these at design time. When you place a scrollbar on the container, its “scroll bar” does not appear:

Image

You can fix this issue by adding a border to the component. This is done using its border property, which can take on various values:

Image

Here is an example of RaisedBevel:

Image

When you click on the top end of a vertical slider, its value decreases. This may surprise the average user, who normally expects to see the value "increase." We resolve this issue by setting unitIncrement and blockIncrement to negative values.

How do you track changes to a slider? When its value changes, the adjustmentValueChanged event is triggered. Simply associate a procedure with this event to be notified of every change in the scrollbar’s value.

Image

The relevant code for our application is as follows:

....

public class applicationFrame extends JFrame {
  JPanel contentPane;
  JScrollBar jScrollBar1 = new JScrollBar();
  Border border1;
  JTextField txtHSValue = new JTextField();
  JScrollBar jScrollBar2 = new JScrollBar();
  JTextField txtValueVS = new JTextField();
  TitledBorder titledBorder1;

  /**Build the frame*/
  public frameAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
...

// a border for the scrollbars
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.white, Color.white, new Color(134, 134, 134), new Color(93, 93, 93));
        // no title bar border
    titledBorder1 = new TitledBorder("");

    jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
    jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
    jScrollBar1.setAutoscrolls(true);
    jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
    jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar1_adjustmentValueChanged(e);
      }
    });

    txtHSValue.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtHSValue_actionPerformed(e);
      }
    });

    jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
    jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar2_adjustmentValueChanged(e);
      }
    });
    jScrollBar2.setAutoscrolls(true);
    jScrollBar2.setUnitIncrement(-1);
    jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());

    txtValueVS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValueVS_actionPerformed(e);
      }
    });

    ......
  }

  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // The value of scrollbar 1 has changed
    txtHSValue.setText("" + jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // The value of scrollbar 2 has changed
    txtValueVS.setText("" + jScrollBar2.getValue());
  }

  void txtHSValue_actionPerformed(ActionEvent e) {
    // Set the value of the horizontal scrollbar
    setValue(jScrollBar1, txtValueHS);
  }

  void txtVertValue_actionPerformed(ActionEvent e) {
    // Set the value of the vertical scrollbar
    setValue(jScrollBar2, txtValueVS);
  }

  private void setValue(JScrollBar jS, JTextField jT){
    // Set the value of the jS scrollbar to the text in the jT field
    int value = 0;
    try{
      value = Integer.parseInt(jT.getText());
      jS.setValue(value);
    }
    catch (Exception e) {
      // display the error
      display("" + e);
    }//try-catch
  }//setValue

  void display(String message) {
    // displays a message in a dialog box
    JOptionPane.showMessageDialog(this, message, "Menus", JOptionPane.INFORMATION_MESSAGE);
  }//display

}

Here is an example of execution:

Image

5.2.5.6. JTextArea component

The JTextArea component is a component where you can enter multiple lines of text, unlike the JTextField component, where you can only enter a single line. If this component is placed in a scrollable container (JScrollPane), you have a scrollable text input field. This type of component might be found, for example, in an email application where the text of the message to be sent is typed into a JTextArea component. The standard methods are String getText() to retrieve the text area’s content, setText(String text) to set text in the text area, and append(String text) to append text to the text already present in the text area. Consider the following application:

Image

No.
type
name
role
1
JTextArea
txtText
a multi-line text area
2
JButton
cmdDisplay
displays the contents of 1 in a dialog box
3
JButton
cmdClear
clears the contents of 1
4
JTextField
txtAdd
text added to the text in 1 when validated by pressing the Enter key.
5
JScrollPane
jScrollPane1
scrollable container in which text box 1 has been placed to create a scrollable text box.

The relevant code is as follows:

.....

public class AppFrame extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JButton cmdDisplay = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea textPane = new JTextArea();
  JLabel jLabel2 = new JLabel();
  JTextField txtAdd = new JTextField();
  JButton cmdClear = new JButton();

  /**Build the frame*/
  public frameAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {

    cmdDisplay.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdDisplay_actionPerformed(e);
      }
    });
    txtAdd.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtAdd_actionPerformed(e);
      }
    });
    cmdClear.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdClear_actionPerformed(e);
      }
    });
    .......
    jScrollPane1.getViewport().add(txtText, null);
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdDisplay_actionPerformed(ActionEvent e) {
    // displays the contents of the TextArea
    display(txtText.getText());
  }

    void display(String message) {
    // displays a message in a dialog box
    JOptionPane.showMessageDialog(this, message, "Follow-up", JOptionPane.INFORMATION_MESSAGE);
  }// display

  void cmdDelete_actionPerformed(ActionEvent e) {
    txtText.setText("");
  }//cmdEffacer_actionPerformed

  void txtAdd_actionPerformed(ActionEvent e) {
    // add text
    txtText.append(txtAdd.getText());
    // clear addition
    txtAdd.setText("");
  }//
}

5.2.6. Mouse events

When drawing in a container, it is important to know the mouse position, for example, to display a point when clicked. Mouse movements trigger events in the container within which it moves. Here are, for example, those provided by JBuilder for a JPanel container:

Image

mouseClicked
mouse click
mouseDragged
mouse is moving, left button pressed
mouseEntered
the mouse has just entered the container's area
mouseExited
the mouse has just left the container area
mouseMoved
the mouse is moving
mousePressed
Left mouse button pressed
mouseReleased
Left mouse button released

Here is a program to help you better understand when the various mouse events occur:

Image

No.
type
name
role
1
JTextField
txtPosition
to display the mouse position in the container (possibly MouseMoved)
2
JList
lstDisplay
to display mouse events other than MouseMoved
3
JButton
cmdClear
to clear the contents of 2

When you run this program, here is what you get for a click:

Image

Events are stacked from the top of the list. Therefore, the screenshot above shows that a click triggers three events, in the following order:

  1. MousePressed when the button is pressed
  2. MouseReleased when the button is released
  3. MouseClicked, which indicates that the sequence of the two previous events is considered a click. This could be a double-click. But above, the information clickCount=1 indicates that it is a single click.

Now, if you click the button, move the mouse, and release the button:

Image

Here we see the three events:

  1. MousePressed when the button is initially pressed
  2. MouseDragged when you move the mouse with the button pressed
  3. MouseReleased when you release the button

In the two examples above, we see that a mouse event carries various pieces of information, including the mouse coordinates (x,y), for example (408,65) in the first line above.

If we continue in this manner, we discover that the MouseExited event is triggered as soon as the mouse leaves the container or moves over one of its components. In the latter case, the container receives the MouseExited event and the component receives the MouseEntered event. The opposite will occur when the mouse leaves the component to return to the container.

What happens during a double-click?

Image

We get exactly the same events as for a single click. The only difference is that the event carries the information clickCount=2 (see above), indicating that a double-click actually occurred.

The relevant code for this application is as follows:

public class Frame1 extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtPosition = new JTextField();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel values = new DefaultListModel();
  JList lstDisplay = new JList(values);
  JButton cmdClear = new JButton();

  /**Build the frame*/
  public Frame1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {

    contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        contentPane_mouseMoved(e);
      }
      public void mouseDragged(MouseEvent e) {
        contentPane_mouseDragged(e);
      }
    });

    contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        contentPane_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        contentPane_mouseExited(e);
      }
      public void mousePressed(MouseEvent e) {
        contentPane_mousePressed(e);
      }
      public void mouseClicked(MouseEvent e) {
        contentPane_mouseClicked(e);
      }
      public void mouseReleased(MouseEvent e) {
        contentPane_mouseReleased(e);
      }
    });

    cmdClear.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdClear_actionPerformed(e);
      }
    });

    jScrollPane1.getViewport().add(lstAffichage, null);

...............
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
    .........
  }

  void contentPane_mouseMoved(MouseEvent e) {
    txtPosition.setText("(" + e.getX() + "," + e.getY() + ""));
  }

  void contentPane_mouseDragged(MouseEvent e) {
    display(e);
  }

  void contentPane_mouseEntered(MouseEvent e) {
    display(e);
  }

  void display(MouseEvent e) {
    // displays event e in the lstAffichage list
    values.insertElementAt(e, 0);
  }

  void contentPane_mouseExited(MouseEvent e) {
    display(e);
  }

  void contentPane_mousePressed(MouseEvent e) {
    display(e);
  }

  void contentPane_mouseClicked(MouseEvent e) {
    display(e);
  }

  void contentPane_mouseReleased(MouseEvent e) {
    display(e);
  }

  void cmdClear_actionPerformed(ActionEvent e) {
    // clears the list
    values.removeAllElements();
  }
}

5.2.7. Creating a Window with a Menu

Now let's see how to create a window with a menu using JBuilder. We will create the following window:

Image

Image

Create a new project starting with an empty window. From the "Swing Containers" component list, select the JMenuBar component (see Figure 1 below) and drag it onto the window you are designing.

Image

Nothing appears in the design window, but the JMenuBar component appears in your window’s structure panel:

Image

Double-click the jMenuBar1 element above to access the menu in design mode:

Image

1
Insert a menu item
2
Insert a separator
3
Insert a nested menu
4
Remove a menu item
5
Disable a menu item
6
Checkbox menu item
7
Toggle the radio button

To create your first menu item, type "Options A" in box A above, then below in the following order: A1, A2, separator, A3, A4.

Image

Then next to it:

Image

Use tool 3 to indicate that B3 is a nested submenu.

As we design the menu, the logical structure of our window evolves:

Image

If we run our application now, we will see an empty window with no menu. We need to associate the created menu with our window. To do this, in the window structure, select the "this" object:

Image

You will then have access to the properties of this:

Image

One of these is JMenuBar, which is used to set the menu that will be associated with the window. Click in the cell to the right of JMenuBar. All the menus you have created will then be displayed. Here, we will only have jMenuBar1. Select it.

Run the application (F9):

Image

Now we have a menu, but the options don’t do anything yet. Menu options are treated as components: they have properties and events. In the menu structure, select the jMenuItem1 option:

Image

You now have access to its properties and events:

Image

Select the events page and click on the cell to the right of the actionPerformed event: this is the event that occurs when you click on a menu item. A handler procedure is provided by default. Double-click on it to access its code:

Image

We will write the following simple code:

  void jMenuItem1_actionPerformed(ActionEvent e) {
    display("Option A1 has been selected");
  }

  void display(String message){
    // displays a message in a dialog box
    JOptionPane.showMessageDialog(this, message, "Menus", JOptionPane.INFORMATION_MESSAGE);
  }//display

Run the application and select option A1 to see the following message:

Image

The relevant code for this application is as follows:

.....

public class Frame1 extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  JMenu jMenu2 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenu jMenu3 = new JMenu();
  JMenuItem jMenuItem7 = new JMenuItem();
  JMenuItem jMenuItem8 = new JMenuItem();
  JMenuItem jMenuItem9 = new JMenuItem();

  /**Create the frame*/
  public Frame1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**Initialize the component*/
  private void jbInit() throws Exception {
        // The window is associated with a menu
    this.setJMenuBar(jMenuBar1);

    jMenu1.setText("Options A");
    jMenuItem1.setText("A1");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }
    });
    jMenuItem2.setText("A2");
    jMenuItem3.setText("A3");
    jMenuItem4.setText("A4");
    jMenu2.setText("Options B");
    jMenuItem5.setText("B1");
    jMenuItem6.setText("B2");
    jMenu3.setText("B3");
    jMenuItem7.setText("B31");
    jMenuItem8.setText("B32");
    jMenuItem9.setText("B4");
    jMenuBar1.add(jMenu1);
    jMenuBar1.add(jMenu2);
    jMenu1.add(jMenuItem1);
    jMenu1.add(jMenuItem2);
    jMenu1.addSeparator();
    jMenu1.add(jMenuItem3);
    jMenu1.add(jMenuItem4);
    jMenu2.add(jMenuItem5);
    jMenu2.add(jMenuItem6);
    jMenu2.add(jMenu3);
    jMenu2.add(jMenuItem9);
    jMenu3.add(jMenuItem7);
    jMenu3.add(jMenuItem8);
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

  void jMenuItem1_actionPerformed(ActionEvent e) {
    display("Option A1 has been selected");
  }

  void display(String message) {
    // displays a message in a dialog box
    JOptionPane.showMessageDialog(this, message, "Menus", JOptionPane.INFORMATION_MESSAGE);
  }//display

}

5.3. Dialog boxes

5.3.1. Message boxes

We have already used the JOptionPane class to display messages. Thus, the following code:

import javax.swing.*;

public class dialog1 {
  public static void main(String arg[]){
    JOptionPane.showMessageDialog(null, "A message", "Box title", JOptionPane.INFORMATION_MESSAGE);
  }
}

displays the following dialog box:

Image

When this window is closed, it disappears, but the execution thread in which it was running is not stopped. This phenomenon does not normally occur. Dialog boxes are used within an application that, at some point, uses a System.exit(n) statement to stop all threads. We will keep this in mind in the upcoming examples, all of which are built on the same model. In DOS, the application can be interrupted by Ctrl-C. With JBuilder, use the Run/Reset Program option (Ctrl-F2). Additionally, the first argument of showMessageDialog is null here. This is not usually the case; it is typically this, where this refers to the application’s main window.

5.3.2. Looks and Feels

The appearance of the dialog box above could be different. You can configure this appearance using the javax.swing.UIManager class. When we commented on the code generated by JBuilder for our first window, we encountered a statement that we didn’t dwell on:

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

The setLookAndFeel method of the UIManager class (UI = User Interface) allows you to set the appearance of graphical interfaces. The UIManager class has a method that lets you determine the possible "looks" for interfaces:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

The method returns an array of LookAndFeelInfo objects. This class has a method:

String
getClassName()

which returns the name of the class "implementing" a given look and feel. Let's try the following program:

import javax.swing.*;

public class LookAndFeels {
  // displays the available look and feels
  public static void main(String[] args) {
    // list of installed look and feels
    UIManager.LookAndFeelInfo[] lf = UIManager.getInstalledLookAndFeels();
    // display
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//for
  }//main
}//class

It produces the following results:

javax.swing.plaf.metal.MetalLookAndFeel
 com.sun.java.swing.plaf.motif.MotifLookAndFeel
 com.sun.java.swing.plaf.windows.WindowsLookAndFeel

There therefore appear to be three "different" "looks". Let's revisit our message display program by trying out the different possible looks:

import javax.swing.*;

public class LookAndFeel2 {
  // displays the available look and feels
  public static void main(String[] args) {
    // list of installed look and feels
    UIManager.LookAndFeelInfo[] lf = UIManager.getInstalledLookAndFeels();
    // display
    for(int i=0;i<lf.length;i++){
      // look and feel manager
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      } catch (Exception ex) {
        System.err.println(ex.getMessage());
      }//catch
      // message
      JOptionPane.showMessageDialog(null, "A message", lf[i].getClassName(), JOptionPane.INFORMATION_MESSAGE);
    }//for
  }//main
}//class

Execution produces the following displays:

corresponding from right to left to the "themes" Metal, Pattern, Windows.

5.3.3. Confirmation boxes

The JOptionPane class has a showConfirmDialog method for displaying confirmation dialogs with Yes, No, and Cancel buttons. There are several overloaded versions of the showConfirmDialog method. We will examine one of them:

static int
showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
parentComponent
the parent component of the dialog box. Often the window or the value null
message
the message to display
title
the title of the dialog box
optionType
JOptionPane.YES_NO_OPTION: Yes, No buttons
JOptionPane.YES_NO_CANCEL_OPTION: Yes, No, Cancel buttons

The result returned by the method is:

JOptionPane.YES_OPTION
the user clicked Yes
JOptionPane.NO_OPTION
the user clicked No
JOptionPane.CANCEL_OPTION
the user clicked Cancel
JOptionPane.CLOSED_OPTION
The user closed the dialog box

Here is an example:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // displays confirmation dialogs
    int response;
    display(JOptionPane.showConfirmDialog(null, "Do you want to continue?", "Confirmation", JOptionPane.YES_NO_OPTION));
    display(JOptionPane.showConfirmDialog(null, "Do you want to continue?", "Confirmation", JOptionPane.YES_NO_CANCEL_OPTION));
  }//main

  private static void display(int response){
    // indicates what type of response was received
    switch(response){
      case JOptionPane.YES_OPTION :
        System.out.println("Yes");
        break;
      case JOptionPane.NO_OPTION :
        System.out.println("No");
        break;
      case JOptionPane.CANCEL_OPTION:
        System.out.println("Cancel");
        break;
      case JOptionPane.CLOSED_OPTION:
        System.out.println("Closing");
        break;
    }//switch
  }//display
}//class

On the console, the messages "No" and "Cancel" are displayed.

5.3.4. Input box

The JOptionPane class also allows you to enter data using the showInputDialog method. Here again, there are several overloaded methods. We present one of them:

static String
showInputDialog(Component parentComponent, Object message, String title, int messageType)

The arguments are the same ones we’ve seen several times before. The method returns the string typed by the user. Here’s an example:

import javax.swing.*;

public class input1 {
  public static void main(String[] args) {
    // input
    System.out.println("Entered string ["+
      JOptionPane.showInputDialog(null, "What is your name?", "Enter name", JOptionPane.QUESTION_MESSAGE)
      + "]");
  }//main
}//class

The input dialog display:

Image

Console output:

Input string [dupont]

5.4. Selection boxes

We will now look at a number of predefined file selection dialogs in Java 2:

 
a file selection dialog for selecting a file from the file tree
JColorChooser
a selection dialog for choosing a color

5.4.1. JFileChooser selection dialog

We are going to build the following application:

Image

The controls are as follows:

No.
Type
name
role
0
JScrollPane
jScrollPane1
Scrollable container for text box 1
1
JTextArea itself within the JScrollPane
txtText
text typed by the user or loaded from a file
2
JButton
btnSave
saves the text from 1 to a text file
3
JButton
btnLoad
allows you to load the contents of a text file into 1
4
JButton
btnClear
clears the contents of 1

A non-visual control is used: jFileChooser1. This is selected from the JBuilder Swing container palette:

Image

We drop the component into the design window but outside the form. It appears in the component list:

Image

We will now provide the relevant program code to give an overview:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;

public class dialogues extends JFrame {
  // the frame components
  JPanel contentPane;
  JButton saveButton = new JButton();
  JButton btnLoad = new JButton();
  JButton btnDelete = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtText = new JTextArea();
  JFileChooser jFileChooser1 = new JFileChooser();

  // file filters
  javax.swing.filechooser.FileFilter textFilter = null;

  //Build the frame
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
      // Other initializations
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  // moreInit
  private void moreInit(){
    // initializations when the window is created
    // *.txt filter
    textFilter = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // Should we accept f?
        return f.getName().toLowerCase().endsWith(".txt");
      }//accept
      public String getDescription(){
        // filter description
        return "Text Files (*.txt)";
      }//getDescription
    };
    // add the filter
    jFileChooser1.addChoosableFileFilter(textFilter);
    // we also want the filter for all files
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // set the FileChooser's starting directory to the current directory
    jFileChooser1.setCurrentDirectory(new File("."));
  }

  //Initialize the component
  private void jbInit() throws Exception  {
.......................
  }
  //Replaced, so we can exit when the window is closed
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnLoad_actionPerformed(ActionEvent e) {
    // Select a file using a JFileChooser object

    // Set the initial filter
    jFileChooser1.setFileFilter(filterTxt);
    // display the selection dialog
    int returnVal = jFileChooser1.showOpenDialog(this);
    // Did the user select anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // put the file into the text field
       readFile(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

  // readFile
  private void readFile(File file){
    // displays the contents of the text file file in the text field

    // clear the text field
    txtText.setText("");

    // some data
    BufferedReader IN = null;
    String line = null;
    try{
      // Open file for reading
      IN = new BufferedReader(new FileReader(file));
      // read the file line by line
      while ((line = IN.readLine()) != null) {
        txtText.append(line + "\n");
      }//while
      // Close file
      IN.close();
    } catch (Exception ex) {
      // An error occurred
      txtText.setText("" + ex);
    }//catch
  }

  // clear
  void btnClear_actionPerformed(ActionEvent e) {
    // clear the text box
    txtText.setText("");
  }

  // save
  void btnSave_actionPerformed(ActionEvent e) {
    // Save the text box's contents to a file

    // Set the initial filter
    jFileChooser1.setFileFilter(textFilter);
    // display the save dialog
    int returnVal = jFileChooser1.showSaveDialog(this);
    // Did the user select anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // write the contents of the text box to a file
       writeFile(jFileChooser1.getSelectedFile());
    }//if
  }

  // readFile
  private void writeFile(File file){
    // writes the contents of the text box to the file

    // some data
    PrintWriter PRN = null;
    try{
      // Open file for writing
      PRN = new PrintWriter(new FileWriter(file));
      // write the contents of the text box
      PRN.print(txtText.getText());
      // Close file
      PRN.close();
    } catch (Exception ex) {
      // An error occurred
      txtText.setText("" + ex);
    }//catch
  }

We won't comment on the code for the btnEffacer_Click, lireFichier, and écrireFichier methods, as they don't introduce anything new. We'll focus on the JFileChooser class and how to use it. This class is complex—a bit of a "mess." Here, we'll only use the following methods:

addChoosableFilter(FileFilter)
sets the file types available for selection
setAcceptAllFileFilterUsed(boolean)
indicates whether the "All Files" type should be offered for selection or not
File getSelectedFile()
the file (File) selected by the user
int showSaveDialog()
method that displays the save dialog. Returns a result of type int. The value jFileChooser.APPROVE_OPTION indicates that the user has made a valid selection. Otherwise, the user has either canceled the selection or an error has occurred.
setCurrentDirectory
to set the initial directory from which the user will begin exploring the file system
setFileFilter(FileFilter)
to set the active filter

The showSaveDialog method displays a selection dialog similar to the following:

Image

1
drop-down list built using the addChoosableFilter method. It contains what are called selection filters, represented by the FileFilter class. It is up to the developer to define these filters and add them to the list 1.
2
current directory, set by the setCurrentDirectory method if that method was used; otherwise, the current directory will be the "My Documents" folder in Windows or the home directory in Unix.
3
Name of the file selected or typed directly by the user. Will be available via the getSelectedFile() method
4
Save/Cancel buttons. If the Save button is used, the showSaveDialog method returns the result jFileChooser.APPROVE_OPTION

How are the file filters in dropdown list 1 constructed? The filters are added to list 1 using the method:

addChoosableFilter(FileFilter)
sets the file types available for selection

of the JFileChooser class. We still need to understand the FileFilter class. This is actually the javax.swing.filechooser.FileFilter class, which is an abstract class—that is, a class that cannot be instantiated but only derived from. It is defined as follows:

FileFilter()
constructor
boolean accept(File)
indicates whether file f matches the filter or not
String getDescription()
filter description string

Let's take an example. We want dropdown list 1 to offer a filter for selecting *.txt files with the description "Text files (*.txt)".

  • We need to create a class derived from the FileFilter class
  • Use the boolean accept(File f) method to return true if the name of file f ends with .txt
  • use the String getDescription() method to set the description to "Text files (*.txt)"

This filter could be defined in our application as follows:

  javax.swing.filechooser.FileFilter textFilter = new javax.swing.filechooser.FileFilter(){
    public boolean accept(File f){
      // Do we accept f?
      return f.getName().toLowerCase().endsWith(".txt");
    }//accept
    public String getDescription(){
      // filter description
      return "Text Files (*.txt)";
    }//getDescription
  };

This filter would be added to the list of filters for the jFileChooser1 object using the following statement:

    // Add the *.txt filter
    jFileChooser1.addChoosableFileFilter(filtretxt);

All of this and a few other initializations are performed in the moreInit method, which is executed when the window is created (see the complete program above). The code for the Save button is as follows:

  void btnSave_actionPerformed(ActionEvent e) {
    // saves the contents of the text box to a file

    // Set the initial filter
    jFileChooser1.setFileFilter(filtreTxt);
    // display the save dialog
    int returnVal = jFileChooser1.showSaveDialog(this);
    // Did the user select anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // write the contents of the text box to a file
       writeFile(jFileChooser1.getSelectedFile());
    }//if
  }

The sequence of operations is as follows:

  • We set the active filter to *.txt to allow the user to search primarily for this type of file. The "All Files" filter is also present. It was added in the moreInit procedure. So we have two filters.
  • The file selection dialog is displayed. Here, control is handed over to the user, who uses the dialog to select a file from the file system.
  • When the user exits the selection box, we check the return value to see whether or not we should save the text box. If so, it must be saved to the file obtained via the getSelectedFile method.

The code associated with the "Load" button is very similar to the code for the "Save" button.

  void btnCharger_actionPerformed(ActionEvent e) {
    // Select a file using a JFileChooser object

    // Set the initial filter
    jFileChooser1.setFileFilter(filterTxt);
    // display the selection dialog
    int returnVal = jFileChooser1.showOpenDialog(this);
    // Did the user select anything?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // put the file into the text field
       readFile(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

There are two differences:

  • To display the file selection dialog, we use the showOpenDialog method instead of the showSaveDialog method. The dialog displayed is similar to the one displayed by the showSaveDialog method.
  • If the user has successfully selected a file, we call the readFile method rather than the writeFile method.

5.4.1.1. JColorChooser and JFontChooser selection dialogs

We continue the previous example by adding two new buttons:

Image

No.
type
name
role
6
JButton
btnColor
to set the text color of the TextBox
7
JButton
btnFont
to set the font of the TextBox

The JColorChooser component, which displays a color selection dialog, can be found in the list of Swing components in JBuilder:

Image

We drop this component into the design window, but outside the form. It is not visible in the form but is nevertheless present in the window’s component list:

Image

The JColorChooser class is very simple. We display the color selection dialog using the int showDialog method:

static Color
showDialog(Component component, String title, Color initialColor)
Component component
the parent component of the color picker, typically a JFrame window
String title
the title in the title bar of the selection box
Color intialColor
The color initially selected in the color picker

If the user selects a color, the method returns a color; otherwise, it returns null. The code associated with the Color button is as follows:

  void btnColor_actionPerformed(ActionEvent e) {
    // Select a text color using the JColorChooser component
    Color color;
    if((color = jColorChooser1.showDialog(this, "Choose a color", Color.BLACK)) != null) {
      // Set the text color of the text box
      txtText.setForeground(color);
    }//if
  }

The Color class is defined in java.awt.Color. Various constants are defined there, including Color.BLACK for the color black. The selection dialog displayed is as follows

Image

Curiously enough, the Swing library does not provide a class for selecting a font. Fortunately, there are Java resources available online. By searching for the keyword "JFontChooser," which seems like a likely name for such a class, we find several options. The following example will give us the opportunity to configure JBuilder to use packages not included in its initial setup.

The retrieved package is called swingextras.jar and has been placed in the <jdk>\jre\lib\perso folder, where <jdk> refers to the installation directory of the JDK used by JBuilder. It could have been placed anywhere else.

Let’s look at the contents of the SwingExtras.jar package:

Image

It contains the Java source code for the components included in the package. It also contains the classes themselves:

Image

From this archive, note that the JFontChooser class is actually named com.lamatek.swingextras.JFontChooser. If you don’t want to write the full name, you’ll need to include the following at the beginning of your program:

import com.lamatek.swingextras.*;

How will the compiler and the Java Virtual Machine find this new package? In the case of direct use of the JDK, this has already been explained, and the reader can find the details in the section on Java packages. Here, we detail the method to use with JBuilder. Packages are configured in the Options/Configure JDKs menu:

Image

1
The Edit button (1) allows you to tell JBuilder which JDK to use. In this example, JBuilder came bundled with JDK 1.3.1. When JDK 1.4 was released, it was installed separately from JBuilder, and we used the Edit button to tell JBuilder to use JDK 1.4 from now on by specifying its installation directory
2
Base directory of the JDK currently used by JBuilder
3
list of Java archives (.jar) used by JBuilder. You can add more using the Add button (4)
4
The Add button (4) allows you to add new packages that JBuilder will use for both compiling and running programs. We used it here to add the SwingExtras.jar package (5)

Now JBuilder is properly configured to use the JFontChooser class. However, we would need access to the definition of this class to use it correctly. The swingextras.jar archive contains HTML files that could be extracted for use. This is unnecessary. The Java documentation included in the .jar files is directly accessible from JBuilder. To do this, configure the Documentation tab (6) above. The following new window appears:

Image

The Add button allows us to specify that the SwingExtras.jar file should be scanned for documentation. Once this is done, we can see that we do indeed have access to the SwingExtras.jar documentation. This provides several benefits:

  • if you start typing the import statement
import com.lamatek.swingextras.*;

you will see that JBuilder provides help:

Image

The com.lamatek package is successfully found.

  • Now, in the following program:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1 = null;
}  

If you press F1 on the keyword JFontChooser, you’ll see help for this class:

Image

We can see in status bar 1 that an HTML file from the swingextras.jar package is indeed being used. The example shown above is clear enough to allow us to write the code for the Font button in our application:

  void btnFont_actionPerformed(ActionEvent e) {
    // Select a text font using the JFontChooser component
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Select a font") == JFontChooser.ACCEPT_OPTION) {
      // change the font of the text box
      txtText.setFont(jFontChooser1.getSelectedFont());
    }//if
  }

The selection dialog displayed by the showDialog method above is as follows:

Image

5.5. The Tax Claculation graphical application

We return to the IMPOTS application, which we have already covered twice. We will now add a graphical user interface to it:

Image

The controls are as follows

No.
type
name
role
1
JRadioButton
rdYes
checked if married
2
JRadioButton
rdNo
Checked if not married
3
JSpinner
spinChildren
number of the taxpayer's children
Minimum=0, Maximum=20, Increment=1
4
JTextField
txtSalary
taxpayer's annual salary in F
5
JLabel
lblTaxes
amount of tax due
6
JTextField
txtStatus
status message field - not editable

The menu is as follows:

main option
secondary option
name
role
Taxes
   
 
Initialize
mnuInitialize
loads the data needed for the calculation from a text file
 
Calculate
mnuCalculate
calculates the tax due when all necessary data is present and correct
 
Clear
mnuClear
resets the form to its initial state
 
Exit
mnuExit
closes the application

Operating Rules

  • The Calculate menu remains disabled as long as the salary field is empty
  • If, when the calculation is run, the salary turns out to be incorrect, an error is reported:

Image

The program is shown below. It uses the *impots* class created in the chapter on classes. Some of the code automatically generated by JBuilder has not been reproduced here.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;

public class frmImpots extends JFrame {
  // Window components
  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem mnuInitialize = new JMenuItem();
  JMenuItem mnuCalculate = new JMenuItem();
  JMenuItem mnuClear = new JMenuItem();
  JMenuItem mnuExit = new JMenuItem();
  JLabel jLabel1 = new JLabel();
  JFileChooser jFileChooser1 = new JFileChooser();
  JTextField txtStatus = new JTextField();
  JRadioButton rdYes = new JRadioButton();
  JRadioButton rdNo = new JRadioButton();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSalary = new JTextField();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel lblTaxes = new JLabel();
  JLabel jLabel7 = new JLabel();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JSpinner spinChildren = null;
  FileFilter textFilter = null;

  // class attributes
  double[] limits = null;
  double[] coefficients = null;
  double[] coeffn = null;
  taxes objTaxes = null;

  //Build the form
  public frmTaxes() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // other initializations
    moreInit();
  }

  // form initialization
  private void moreInit(){
    // Calculate menu disabled
    mnuCalculate.setEnabled(false);
    // input fields disabled
    txtSalary.setEditable(false);
    txtSalary.setBackground(Color.WHITE);
    // status field
    txtStatus.setBackground(Color.WHITE);
    // Children spinner - between 0 and 20 children
    spinChildren = new JSpinner(new SpinnerNumberModel(0, 0, 20, 1));
    spinChildren.setBounds(new Rectangle(137, 60, 40, 27));
    contentPane.add(spinChildren);
    // *.txt filter for the file selection dialog
    txtFilter = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // Should we accept f?
        return f.getName().toLowerCase().endsWith(".txt");
      }//accept
      public String getDescription(){
        // filter description
        return "Text Files (*.txt)";
      }//getDescription
    };
    // Add the *.txt filter
    jFileChooser1.addChoosableFileFilter(textFilter);
    // we also want the filter for all files
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // Set the starting directory for the FileChooser
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

  // Initialize the component
  private void jbInit() throws Exception  {

................

  }

  //Replaced, so we can exit when the window is closed
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // exit the application
    System.exit(0);
  }

  void mnuInitialize_actionPerformed(ActionEvent e) {
    // load the data file
    // which we select using the JFileChooser1 dialog
    jFileChooser1.setFileFilter(filterTxt);
    if (jFileChooser1.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
      return;
    // process the selected file
    try{
      // read data
      readFile(jFileChooser1.getSelectedFile());
      // create the impots object
      objTaxes = new Taxes(limits, coeffr, coeffn);
      // confirmation
      txtStatus.setText("Data loaded");
      // The salary can be modified
      txtSalary.setEditable(true);
      // no further changes allowed
      mnuInitialize.setEnabled(false);
    } catch (Exception ex) {
      // problem
      txtStatus.setText("Error: " + ex.getMessage());
      // end
      return;
    }//catch
  }

  private void readFile(File file) throws Exception {
    // data arrays
    ArrayList aLimits = new ArrayList();
    ArrayList aCoeffR = new ArrayList();
    ArrayList aCoeffN = new ArrayList();
    String[] fields = null;

    // Open file for reading
    BufferedReader IN = new BufferedReader(new FileReader(file));
    // read the file line by line
    // they are in the form limit coeffr coeffn
    String line = null;
    int lineNumber = 0;           // current line number
    while((line = IN.readLine()) != null) {
      // one more line
      lineNumber++;
      // split the line into fields
      fields = line.split("\\s+");
      // 3 fields?
      if(fields.length!=3)
        throw new Exception("Invalid line " + numLine + " in data file");
      // retrieve the three fields
       aLimits.add(fields[0]);
       aCoeffR.add(fields[1]);
       aCoeffN.add(fields[2]);
    }//while
    // close file
    IN.close();
    // transfer data to bounded arrays
    int n = aLimits.size();
    limits = new double[n];
    coeffr = new double[n];
    coeffn = new double[n];
    for (int i = 0; i < n; i++) {
      limits[i] = Double.parseDouble((String)aLimits.get(i));
      coeffr[i] = Double.parseDouble((String)aCoeffR.get(i));
      coeffn[i] = Double.parseDouble((String)aCoeffN.get(i));
    }//for
  }

  void mnuCalculate_actionPerformed(ActionEvent e) {
    // tax calculation
    // check salary
    int salary = 0;
    try{
      salary = Integer.parseInt(txtSalary.getText().trim());
      if (salary < 0) throw new Exception();
    } catch (Exception ex) {
      // error message
      txtStatus.setText("Invalid salary. Please try again");
      // Focus on the incorrect field
      txtSalary.requestFocus();
      // return to the interface
      return;
    }
    // number of children
    Integer numberOfChildren = (Integer)spinChildren.getValue();
    // calculate tax
    lblTaxes.setText("" + objTaxes.calculate(rdYes.isSelected(), InbChildren.intValue(), salary));
    // clear status message
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
    // Salary has changed - update the "Calculate" menu
    mnuCalculate.setEnabled(!txtSalary.getText().trim().equals(""));
  }

  void mnuDelete_actionPerformed(ActionEvent e) {
    // Clear the form
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalary.setText("");
    mnuCalculate.setEnabled(false);
    lblTaxes.setText("");
  }
}

Here we used a component available only starting with JDK 1.4, the JSpinner. It is a spinner, which in this case allows the user to set the number of children. This Swing component was not available in the Swing component bar of JBuilder 6 used for testing. This does not prevent its use, even if things are a bit more complicated than for components available in the component bar. In fact, you cannot drop the JSpinner component onto the form during design time. You must do it at runtime. Let’s look at the code that does this:

    // Children spinner - between 0 and 20 children
    spinChildren = new JSpinner(new SpinnerNumberModel(0, 0, 20, 1));
    spinChildren.setBounds(new Rectangle(137, 60, 40, 27));
    contentPane.add(spinChildren);

The first line creates the JSpinner component. This component can be used for various purposes, not just as an integer spinner like here. The argument of the JSpinner constructor is a number spinner model that accepts four parameters (value, min, max, increment). The component has the following form:

Image

value
initial value displayed in the component
min
minimum value that can be displayed in the component
max
maximum value that can be displayed in the component
increment
increment value of the displayed value when using the component's up/down arrows

The component's value is obtained via its getValue method, which returns an Object type. Hence, some type casting is required to obtain the integer we need:

    // number of children
    Integer InbEnfants = (Integer)spinEnfants.getValue();
    // tax calculation
    lblTaxes.setText("" + objTaxes.calculate(rdYes.isSelected(),
      InbEnfants.intValue(), salary));

Once the JSpinner component is defined, it is placed in the window:

    spinEnfants.setBounds(new Rectangle(137, 60, 40, 27));
    contentPane.add(spinEnfants);

First and foremost, the user must use the Initialize menu option, which creates a tax object using the constructor

    public impots(double[] LIMITS, double[] COEFF, double[] COEFFN) throws Exception

of the impots class. Recall that this was defined as an example in the chapter on classes. Refer to that chapter if necessary. The three arrays required by the constructor are populated from the contents of a text file with the following format:

12620.0
0
0
13190
0.05
631
15,640
0.1
1,290.5
24,740
0.15
2,072.5
31,810
0.2
3,309.5
39,970
0.25
4900
48,360
0.3
6,898.5
55,790
0.35
9,316.5
92,970
0.4
12,106
127,860
0.45
16,754.5
151,250
0.50
23,147.5
172,040
0.55
30,710
195,000
0.60
39,312
0
0.65
49062

Each line contains three numbers separated by at least one space. This text file is selected by the user using a JFileChooser component. Once the *impots* object has been created, all that remains is to let the user enter the three pieces of information needed: married or not, number of children, annual salary, and call the calculate method of the impots class. The operation can be repeated multiple times. The *impots* object itself is created only once, when the *Initialize* option is used.

5.6. Writing applets

5.6.1. Introduction

Once you have written an application with a graphical user interface, it is fairly easy to convert it into an applet. Stored on machine A, it can be downloaded via a web browser from machine B over the internet. The original application is thus shared among many users, and this is the main benefit of converting an application into an applet. However, not every application can be converted in this way: to avoid causing problems for the user running an applet in their browser, the applet environment is restricted:

  • an applet cannot read from or write to the user’s disk
  • it can only communicate with the machine from which it was downloaded by the browser.

These are significant restrictions. They imply, for example, that an application needing to read information from a file or a database must request it through a relay application located on the server from which it was downloaded.

The general structure of a simple web application is as follows:

Image

  • the client requests an HTML document from the web server, usually using a browser. This document may contain an applet that will function as a standalone graphical application within the HTML document displayed by the client’s browser.
  • This applet may have access to data, but only to data located on the web server. It will not have access to the resources of the client machine running it, nor to those of other machines on the network other than the one from which it was downloaded.

5.6.2. The JApplet class

5.6.2.1. Definition

An application can be downloaded by a web browser if it is an instance of the java.applet.Applet class or the javax.swing.JApplet class. The latter derives from the former, which itself derives from the Panel class, which in turn derives from the Container class. Since an Applet or JApplet instance is of the Container type, it can therefore contain components (Component) such as buttons, checkboxes, lists, etc. Here are some notes on the role of the different methods:

Method
Role
public void destroy();
Destroys the Applet instance
public AppletContext getAppletContext();
retrieves the applet's execution context (the HTML document in which it is located, other applets in the same document, etc.)
public String getAppletInfo();
returns a string containing information about the applet
public AudioClip getAudioClip(URL url);
loads the audio file specified by URL
public AudioClip getAudioClip(URL url, String name);
loads the audio file specified by URL/name
public URL getCodeBase();
returns the applet's URL
public URL getDocumentBase();
returns the URL of the HTML document containing the applet
public Image getImage(URL url);
retrieves the image specified by the URL
public Image getImage(URL url, String name);
retrieves the image specified by URL/name
public String getParameter(String name);
retrieves the value of the "name" parameter contained in the <applet> tag of the HTML document containing the applet.
public void init();
This method is called by the browser when the applet is first launched
public boolean isActive();
applet status
public void play(URL url);
Plays the sound file specified by the URL
public void play(URL url, String name);
plays the sound file specified by URL/name
public void resize(Dimension d);
sets the size of the applet's frame
public void resize(int width, int height);
same
public final void setStub(AppletStub stub);
 
public void showStatus(String msg);
displays a message in the applet's status bar
public void start();
this method is called by the browser each time the document containing the applet is displayed
public void stop();
this method is called by the browser whenever the document containing the applet is abandoned in favor of another (user changes the URL)

The JApplet class has introduced several improvements to the Applet class, notably the ability to contain JMenuBar components (i.e., menus), which was not possible with the Applet class.

5.6.2.2. Executing an applet: the init, start, and stop methods

When a browser loads an applet, it calls three of its methods:

init
This method is called when the applet is initially loaded. It should therefore contain the initializations necessary for the application.
start
This method is called whenever the document containing the applet becomes the browser’s current document. Thus, when a user loads an applet, the init and start methods will be executed in that order. When the user leaves the document to view another one, the stop method will be executed. When the user returns to it later, the start method will be executed.
stop
This method is called every time the user leaves the document containing the applet.

For many applets, only the init method is necessary. The start and stop methods are only necessary if the application launches tasks (threads) that run in parallel and continuously, often without the user’s knowledge. When the user leaves the document, the visible part of the application disappears, but these background tasks continue to run. This is often unnecessary. We then take advantage of the browser’s call to the stop method to stop them. If the user returns to the document, we take advantage of the browser’s call to the start method to restart them.

Take, for example, an applet that has a clock in its graphical interface. This clock is maintained by a background task (thread). When the user leaves the applet’s page in the browser, there is no point in keeping the clock running since it has become invisible: in the applet’s stop method, we will stop the thread that manages the clock. In the start method, we restart it so that when the user returns to the applet’s page, they find a clock that is up to date.

5.6.3. Converting a graphical application into an applet

We assume here that this conversion is possible, meaning that it complies with the execution restrictions for applets. An application is launched by the *main* method of one of its classes:


public class application{
    
    public static void main(String arg[]){
        
    }
    
}// end of class

Such an application is converted into an applet as follows:

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// end class

Note the following points:

  1. The Application class now derives from the JApplet class
  2. the main method is replaced by the init method.

As an example, let’s revisit an application we’ve studied: list management.

Image

The components of this window are as follows:

No.
Type
name
role
1
JTextField
txtInput
input field
2
JList
jList1
list contained in a container jScrollPane1
3
JList
jList2
list contained in a jScrollPane2 container
4
JButton
cmd1To2
transfers the selected items from list 1 to list 2
5
JButton
cmd2To1
does the opposite
6
JButton
cmdRaz1
clears list 1
7
JButton
cmdRaz2
clear list 2

The application skeleton was as follows:

public class AppInterface extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtInput = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1 = new DefaultListModel();
  DefaultListModel v2 = new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

  /**Build the frame*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

  /**Initialize the component*/
  private void jbInit() throws Exception {
    ...
    txtInput.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
        // JList1 is placed in the jScrollPane1 container
    jScrollPane1.getViewport().add(jList1, null);
        // JList2 is placed in the jScrollPane2 container
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
  /**Replaced, so we can exit when the window is closed*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//class
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//transfer

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // clear list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // clear list 2
    v2.removeAllElements();
  }///cmd Raz2

To convert the application class into an applet, proceed as follows:

  • modify the previous interfaceAppli class so that it no longer extends JFrame but instead extends JApplet:
public class interfaceAppli extends JApplet {
  • Remove the statement that sets the title of the JFrame window. A JApplet does not have a title bar
    // this.setTitle("JList");
  • Change the constructor to an init method and, within this method, remove the window event handling (WindowListener, ...). An applet is a container that cannot be resized or closed.
  /**Construct the frame*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • The processWindowEvent method must be removed or commented out
  /**Replaced, so we can exit when the window is closed*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

Here is the complete applet code, excluding the part automatically generated by JBuilder

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceAppli extends JApplet {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtInput = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1 = new DefaultListModel();
  DefaultListModel v2 = new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

  /**Build the frame*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

  /**Initialize the component*/
  private void jbInit() throws Exception {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Your icon]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 308));
    // this.setTitle("JList");
    jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
    jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
    // the entered text has been validated
    // retrieve it with leading and trailing spaces removed
    String text = txtSaisie.getText().trim();
    // if it is empty, we don't want it
    if (text.equals("")) {
      // error message
      JOptionPane.showMessageDialog(this, "You must enter text",
        "Error", JOptionPane.WARNING_MESSAGE);
      // end
      return;
    }//if
    // if it is not empty, add it to the values in list 1
    v1.addElement(text);
    // and clear the input field
    txtInput.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transfer the selected items from list 1 to list 2
    transfer(jList1, jList2);
  }//cmd1To2

  private void transfer(JList L1, JList L2){
      // Transfer the selected items from List 1 to List 2
      // retrieve the array of indices for the selected items in L1
      int[] indices = L1.getSelectedIndices();
      // anything to do?
      if (indices.length == 0) return;
      // retrieve the values from L1
      DefaultListModel v1 = (DefaultListModel) L1.getModel();
      // and those from L2
      DefaultListModel v2 = (DefaultListModel) L2.getModel();
      for (int i = indices.length - 1; i >= 0; i--) {
        // add the values selected in L1 to L2
        v2.addElement(v1.elementAt(indices[i]));
        // the elements from L1 copied to L2 must be removed from L1
        v1.removeElementAt(indices[i]);
      }//for
  }//transfer

  private void display(String message) {
    // display message
      JOptionPane.showMessageDialog(this, message,
        "Tracking", JOptionPane.INFORMATION_MESSAGE);
  }// display

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transfer selected items from jList2 to jList1
      transfer(jList2, jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // Clear list 1
    v1.removeAllElements();
  }//cmd Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // clear list 2
    v2.removeAllElements();
  }//cmd Raz2

}//class

You can compile the source code for this applet. Here, we do it using the JDK, without JBuilder.

E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java

E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
06/12/2002  4:40 PM                6,148 interfaceAppli.java
06/12/2002  16:41                  527 interfaceAppli$1.class
06/12/2002  4:41 PM                  525 interfaceAppli$2.class
06/12/2002  4:41 PM                  525 interfaceAppli$3.class
06/12/2002  4:41 PM                  525 interfaceAppli$4.class
06/12/2002  4:41 PM                  525 interfaceAppli$5.class
06/12/2002  4:41 PM                4,759 interfaceAppli.class

The application can be tested using the JDK's AppletViewer program, which allows you to run applets, or a web browser. To do this, you must create the HTML document appli.htm, which will contain the applet:

<html>
    <head>
        <title>swing lists</title>
    </head>
    <body>
        <applet 
        code="interfaceAppli.class"
      width="400"
      height="300">
        </applet>
    </body>
</html>

This is a standard HTML document, except for the presence of the applet tag. It has been used with three parameters:

code="interfaceAppli.class"
name of the compiled Java class to load in order to run the applet
width="400"
width of the applet frame in the document
height="300"
height of the applet frame in the document

Once the appli.htm file has been created, it can be loaded using the appletviewer program from the JDK or a web browser. In a DOS window, type the following command in the folder containing the appli.htm file:

**appletviewer appli.htm**

We assume here that the directory containing the appletviewer.exe executable is in the DOS window’s PATH; otherwise, you would need to specify the full path to the appletviewer.exe executable. The following window appears:

Image

Stop the applet’s execution using the Applet/Quit option. Now let’s test the applet using a browser. The browser must use a Java 2 Virtual Machine to display Swing components. Until recently (2001), this requirement posed a problem because Sun released JDKs that browser vendors were slow to adopt. Finally, Sun resolved this issue by providing users with an application called the "Java plugin," which allows Internet Explorer and Netscape Navigator to use the very latest JREs produced by Sun (JRE = Java Runtime Environment). The following tests were performed using IE 5.5 with the Java 1.4 plugin.

One way to test the interfaceAppli.class applet is to load the HTML file appli.htm directly into the browser by double-clicking on it. The browser then displays the HTML page and its applet without the help of a web server:

Image

As seen from the URL (1), the file was loaded directly into the browser. In the following example, the appli.htm file was requested from an Apache web server running on port 81 of the local machine:

Image

5.6.4. The <applet> tag in an HTML document

We have seen that within an HTML document, the applet is referenced by the <applet> tag. This tag can have various attributes:

<applet
    code=
    width=
    height=
    codebase=
    align=
    hspace=
    vspace=
alt=
>
    <param name1=name1 value=val1>
    <param name2=name2 value=val2>
    text
>
</applet>

The meaning of the parameters is as follows:

Parameter
Meaning
code
required - name of the .class file to execute
width
required - width of the applet in the document
height
required - height …
codebase
optional - URL of the directory containing the applet to be executed. If codebase is not specified, the applet will be searched for in the directory of the HTML document that references it
align
optional - positioning (LEFT, RIGHT, CENTER) of the applet within the document
hspace
optional - horizontal margin surrounding the applet, expressed in pixels
vspace
optional - vertical margin surrounding the applet, expressed in pixels
alt
optional - text displayed in place of the applet if the browser cannot load it
param
optional - parameter passed to the applet specifying its name (name) and value (value). The applet can retrieve the value of the parameter name1 using val1=getParameter("name1")
You can use as many parameters as you want
text
optional - will be displayed by any browser unable to execute an applet, for example because it does not have a Java Virtual Machine.

Let’s take an example to illustrate passing parameters to an applet:

<html>
    <head>
        <title>applet parameters</title>
    </head>
    <body>
        <applet code="interfaceParams.class" width="400" height="300">
      <param name="param1" value="val1">
      <param name="param2" value="val2">      
        </applet>
    </body>
</html>

The Java code for the interfaceParams applet was generated as described earlier. We built a JBuilder application and then made the few changes mentioned above:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceParams extends JApplet {
  JPanel contentPane;
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel1 = new JLabel();
  DefaultListModel params = new DefaultListModel();
  JList lstParams = new JList(params);

  //Build the frame
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // other initializations
    moreInit();
  }

  // initializations
  public void moreInit(){
    // displays the values of the applet's parameters
    params.addElement("name=param1 value="+getParameter("param1"));
    params.addElement("name=param2 value="+getParameter("param2"));
  }//more Init

  //Initialize the component
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("Applet Settings");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

Running with AppletViewer:

Image

5.6.5. Accessing remote resources from an applet

Many applications need to access information stored in files or databases. We have noted that an applet does not have access to the resources of the machine on which it runs. This is a common-sense precaution. Otherwise, it would be possible to write an applet to "spy" on the hard drive of those who load it. The applet does, however, have access to the resources of the server from which it was downloaded, such as files. That is what we will look at now.

5.6.5.1. The URL Class

Any Java application can read a file located on a machine on the network using the java.net.URL class (URL = Uniform Resource Locator). A URL identifies a network resource, the machine on which it is located, as well as the protocol and communication port to use to retrieve it in the form:

protocol:port//machine/file

Thus, the URL http://www.ibm.com/index.html refers to the index.html file on the machine www.ibm.com. It is accessible via the HTTP protocol. The port is not specified: the browser will use port 80, which is the default port for the HTTP service.

Let’s take a closer look at some of the elements of the URL class:

public URL(String spec)
creates a URL instance from a string of the form "protocol:port//machine/file" - throws an exception if the string's syntax does not match a URL
  
public String getFile()
retrieves the file field from the "protocol:port//machine/file" string in the URL
  
public String getHost()
retrieves the "machine" field from the "protocol:port//machine/file" part of the URL
  
public String getPort()
retrieves the port field from the URL string "protocol:port//machine/file"
  
public String getProtocol()
retrieves the protocol field from the URL string "protocol:port//machine/file"
  
public URLConnection openConnection()
opens a connection to the remote machine getHost() on its port getPort() using the protocol getProtocol() in order to read the file getFile(). Throws an exception if the connection could not be opened
  
public final InputStream openStream()
Shortcut for openConnection().getInputStream(). Retrieves an input stream from which the contents of the file getFile() can be read. Throws an exception if the stream could not be obtained
  
public String toString()
displays the identity of the URL instance

There are two methods here that are of interest to us:

  • public URL(String spec) to specify the file to be processed
  • public final InputStream openStream() to process it

5.6.5.2. An example: a console-

We will write a Java program, without a graphical user interface, designed to display on the screen the content of a URL passed to it as a parameter. An example of a call could be the following:

    DOS> java urlcontent http://istia.univ-angers.fr/index.html

The program is relatively simple:


import java.net.*;             // for the URL class
import java.io.*;                // for streams

public class urlContent {

// displays the content of the URL passed as an argument
// this content must be text to be readable

  public static void main(String arg[]){
    // Check arguments
    if (arg.length == 0) {
      System.err.println("Syntax: pg url");
      System.exit(0);
    }
    
    try{
      // Create the URL      
      URL url = new URL(arg[0]);
      // read content
      try{
        // Create the input stream
        BufferedReader is = new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          // read text lines from the input stream
          String line;
          while((line = is.readLine()) != null)
            System.out.println(line);
        } catch (Exception e){
            System.err.println("Reading error: " + e);
        }
        finally{
          try { is.close(); } catch (Exception e) {}
        }
      } catch (Exception e){
          System.err.println("openStream error: " + e);
      }
    } catch (Exception e){
      System.err.println("Error creating URL: " + e);
    }
  }// end of main
}// end class

After verifying that there is indeed an argument, we attempt to create a URL with it:


// create the URL      
      URL url = new URL(arg[0]);

This creation may fail if the argument does not follow the URL syntax protocol:port//machine/file. If we have a syntactically correct URL, we attempt to create an input stream from which we can read lines of text. The input stream provided by a URL URL.openStream() provides an InputStream, which is a character-oriented stream: reading occurs character by character, and you must form the lines yourself. To read lines of text, you must use the readLine method of the BufferedReader or DataInputStream classes. Here, we have chosen BufferedReader. All that remains is to convert the URL’s InputStream into a BufferedReader stream. This is done by creating an intermediate InputStreamReader stream:


BufferedReader is = new BufferedReader(new InputStreamReader(url.openStream()));

This stream creation may fail. We handle the corresponding exception. Once the stream is obtained, all that remains is to read the lines of text from it and display them on the screen.


            String line;
         while((line = is.readLine()) != null)
                System.out.println(line);

Again, reading may throw an exception that must be handled. Here is an example of running the program that requests a local URL:

E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>

<head>


<title>Welcome to the Personal Web Server</title>
</head>

<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">

<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
                </table>
                </center></div></td>
            </tr>
        </table>
        </td>
    </tr>
</table>
</body>
</html>

5.6.5.3. An example of a graphical user

The graphical interface will look like this:

Image

Number
Name
Type
Role
1
txtURL
JTextField
URL to read
2
btnLoad
JButton
button to start loading the URL
3
JScrollPane1
JScrollPane
scrollable panel
4
lstURL
JList
list displaying the content of the requested URL

When executed, we get a result similar to that of the console program:

Image

The relevant code for the application is as follows:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;

public class interfaceURL extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtURL = new JTextField();
  JButton btnLoad = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel lines = new DefaultListModel();
  JList lstURL = new JList(lines);

  //Build the frame
  public interfaceURL() {
..............
  }

  //Initialize the component
  private void jbInit() throws Exception {
..............
  }

  //Replaced, so we can exit when the window is closed
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    // Sets the state of the Load button
    btnLoad.setEnabled(!txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // displays the content of the URL in the list
    try{
      displayURL(txtURL.getText().trim());
    } catch (Exception ex) {
      // display error
      JOptionPane.showMessageDialog(this, "Error: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void displayURL(String strURL) throws Exception {
    // displays the content of the URL strURL in the list
    // No exceptions are specifically handled. We simply propagate them

    // Create the URL
    URL url = new URL(strURL);
    // Create the input stream
    BufferedReader IN = new BufferedReader(new InputStreamReader(url.openStream()));
    // Read text lines from the input stream
    String line;
    while((line = IN.readLine()) != null)
      lines.addElement(line);
    // close the read stream
    IN.close();
  }
}

5.6.5.4. An applet

The previous graphical application is converted into an applet as has been demonstrated several times. The applet is embedded in an HTML document named appliURL.htm:

<html>
  <head>
    <title>Applet reading a URL</title>
  </head>
  <body>
    <h1>Applet reading a URL</h1>
    <applet
      code="appletURL.class"
      width="400"
      height="300"
    >
    </applet>
  </body>
</html>

Image

In the example above, the browser requested the URL http://localhost:81/Japplets/2/appliURL.htm from an Apache web server running on port 81. The applet was then displayed in the browser. In this example, we requested the URL http://localhost:81/Japplets/2/appliURL.htm again to verify that we were indeed getting the appliURL.htm file we had created. Now let’s try to load a URL that does not belong to the machine that served the applet (here, localhost):

Image

The URL was refused. Here we encounter the limitation associated with applets: they can only access network resources on the machine from which they were downloaded. There is a way for the applet to bypass this restriction, which is to delegate network requests to a server program located on the machine from which it was downloaded. This program will make the network requests on the applet’s behalf and send the results back to it. This is called a proxy program.

5.7. The Tax Calculation Applet

We will now convert the IMPOTS graphical application into an applet. This is of particular interest: the application will become available to any Internet user with a browser and a Java 1.4 plugin (due to the JSpinner component). Our application thus becomes global... This modification will require a bit more than the simple graphical application-to-applet conversion that has now become standard. The application uses an Initialize menu option designed to read the contents of a local file. However, if we consider a web application, we see that this approach no longer works:

Image

It is clear that the data defining the tax brackets will be on the web server and not on each client machine. The file to be read from the web server will be placed here in the same folder as the applet, and the "Initialize" option will need to retrieve it from there. The previous examples showed how to do this. Furthermore, to select the data file locally, we had used a JFileChooser component, which is no longer needed here.

The HTML document containing the applet will be as follows:

<html>
  <head>
    <title>Tax Calculation Applet</title>
  </head>
  <body>
    <h2>Tax Calculator</h2>
    <applet
      code="appletImpots.class"
      width="320"
      height="270"
    >

*&lt;param name=&quot;data&quot; value=&quot;impots.txt&quot;&gt;*

    </applet>
  </body>
</html>

Note the data parameter, whose value is the name of the file containing the tax bracket data. The HTML document, the appletImpots class, the impots class, and the impots.txt file are all in the same folder on the web server:

E:\data\serge\web\JApplets\impots>dir
06/12/2002  1:24 PM                  247 impots.txt
06/13/2002  10:17                  654 appletImpots$2.class
06/13/2002  10:17                  653 appletImpots$3.class
06/13/2002  10:17                  653 appletImpots$4.class
06/13/2002  10:17                  651 appletImpots$5.class
06/13/2002  10:06                  651 appletTaxes$6.class
06/13/2002  10:17                8,655 appletImpots.class
06/13/2002  10:17                  657 appletImpots$1.class
06/13/2002  10:24                  286 appletImpots.htm
06/13/2002  10:17                1,305 impots.class

The applet code is as follows (we have highlighted only the changes compared to the graphical application):

...........
import java.net.*;
import java.applet.Applet;

public class appletImpots extends JApplet {
  // window components
  JPanel contentPane;
............................

  // class attributes
  double[] limits = null;
  double[] coefficients = null;
  double[] coefficients = null;
  taxes objTaxes = null;
  String urlDATA = null;

  //Build the framework
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // other initializations
    moreInit();
  }

  // form initialization
  private void moreInit(){
    // Calculate menu disabled
    mnuCalculate.setEnabled(false);
................
    // retrieve the name of the tax schedule file
    String filename = getParameter("data");
    // error?
    if(filename == null){
      // error message
      txtStatus.setText("The applet's data parameter has not been initialized");
      // Disable the Initialize option
      mnuInitialize.setEnabled(false);
      // end
      return;
    }//if
    // Set the data URL
    urlDATA = getCodeBase() + "/" + filename;
  }//moreInit

  //Initialize the component
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // Exit the application
    System.exit(0);
  }

  void mnuInitialize_actionPerformed(ActionEvent e) {
    // load the data file
    try{
      // read data
      readDATA();
      // create the tax object
      taxObject = new Taxes(limits, coeffr, coeffn);
................
  }

  private void readData() throws Exception {
    // data arrays
    ArrayList aLimits = new ArrayList();
    ArrayList aCoeffR = new ArrayList();
    ArrayList aCoeffN = new ArrayList();
    String[] fields = null;

    // Open file for reading
    BufferedReader IN = new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // read the file line by line
....................
  }

  void mnuCalculate_actionPerformed(ActionEvent e) {
    // calculate the tax
......................
  }

  void txtSalary_caretUpdate(CaretEvent e) {
..........
  }

  void mnuDelete_actionPerformed(ActionEvent e) {
...............
  }
}

Here, we only comment on the changes resulting from the fact that the data file to be read is now on a remote machine rather than a local one:

The URL of the data file to be read is obtained using the following code:

    // retrieve the name of the tax table file
    String filename = getParameter("data");
    // error?
    if(filename==null){
      // error message
      txtStatus.setText("The applet's data parameter has not been initialized");
      // Disable the Initialize option
      mnuInitialize.setEnabled(false);
      // end
      return;
    }//if
    // Set the data URL
    urlDATA = getCodeBase() + "/" + filename;

Remember that the filename "impots.txt" is passed in the applet's data parameter:

    <param name="data" value="impots.txt">

The code above begins by retrieving the value of the data parameter while handling any potential errors. If the URL of the HTML document containing the applet is http://localhost:81/JApplets/impots/appletImpots.htm, the URL of the impots.txt file will be http://localhost:81/JApplets/impots/impots.txt. We need to construct this URL. The applet’s getCodeBase() method returns the URL of the directory where the HTML document containing the applet was retrieved, so in our example, http://localhost:81/JApplets/impots. The following statement therefore constructs the URL for the data file:

    urlDATA=getCodeBase()+"/"+filename;

In the lireFichier() method, which reads the content of the URL urlData, we find the creation of the input stream that will allow us to read the data:

    // open file for reading
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

From this point on, it is no longer possible to distinguish whether the data comes from a remote file rather than a local one. Here is an example of the applet in action:

Image

5.8. Conclusion

This chapter has provided

  • an introduction to building graphical user interfaces with JBuilder
  • the most common Swing components
  • applet development

We should note that

  • the code generated by JBuilder can be written by hand. Once this code is obtained in one way or another, a simple JDK is sufficient to run it, and JBuilder is then no longer essential.
  • Using a tool such as JBuilder can lead to significant productivity gains:
    • while it is possible to write the code generated by JBuilder by hand, this can be very time-consuming and offers little benefit, as the application’s logic is generally elsewhere.
    • The generated code can be instructive. Reading and studying it is a good way to discover certain methods and properties of components you are using for the first time.
    • JBuilder is cross-platform. You therefore retain your skills when switching between platforms. Being able to write programs that run on both Windows and Linux is, of course, a very important productivity factor. But this is due to Java itself, not to JBuilder.

5.9. JBuilder on Linux

All of the previous examples have been tested on Windows 98. One might wonder if the programs written are portable as-is to Linux. Provided that the Linux machine in question has the classes used by the various programs, they are. If, for example, you have installed JBuilder on Linux, the necessary classes are already on your machine. Here is an example of what happens when one of our programs is run on the JList component with JBuilder 4 on Linux:

Below, we describe the installation of JBuilder 4 Foundation on a Linux machine. Installing it on a Win9x machine poses no problems and is similar to the process described here. The installation of later versions is likely different, but this document may still provide some useful information.

JBuilder is available on the Inprise website at http://www.inprise.com/jbuilder

Image

This page contains links for Windows and Linux, among others. We will now describe the installation of JBuilder on a Linux machine running the KDE graphical interface.

When you follow the "JBuilder 4 for Linux" link, a form appears. Fill it out, and you will receive two files:

jb4docs_fr.tar.gz: JBuilder 4 documentation and examples

jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. This is a limited version of the commercial JBuilder 4 but is sufficient for educational purposes.

A software activation key will be sent to you via email. It will allow you to use JBuilder 4 and will be requested upon your first use. If you lose this key, you can return to the URL above and follow the "get your activation key" link. We will assume from here on that you are logged in as root and are located in the directory containing the two tar.gz files mentioned above. Unpack the two files:

[tar xvzf jb4fndlinux_fr.tar.gz]
[tar xvzf jb4docs_fr.tar.gz]
[ls -l]
drwxr-xr-x    3 nobody   nobody       4096 Oct 10  2000 docs
drwxr-xr-x    3 nobody   nobody       4096 Dec  5 13:00 foundation
[ls -l foundation]
-rw-r--r--    1 nobody   nobody       1128 Dec  5 13:00 deploy.txt
-rwxr-xr-x    1 nobody   nobody   69035365 Dec  5 13:00 fnd_linux_install.bin
drwxr-xr-x    2 nobody   nobody       4096 Dec  5 1:00 pm images
-rw-r--r--    1 nobody   nobody      15114 Dec  5 1:00 pm index.html
-rw-r--r--    1 nobody   nobody      23779 Dec  5 1:00 PM license.txt
-rw-r--r--    1 nobody   nobody      75739 Dec  5 1:00 PM release_notes.html
-rw-r--r--    1 nobody   nobody      31902 Dec  5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r--    1 nobody   nobody       1128 Oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 Oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 Oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 Oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 Oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 Oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 Oct 10  2000 whatsnew.html

In both generated directories, the .bin file is the installation file. Also, use a web browser to view the index.html file in each directory. They provide instructions for installing both products. Let’s start by installing JBuilder Foundation:

[cd foundation]
[./fnd_linux_install.bin]

The first installation screen appears. Many more will follow:

Image

Confirm. An explanation screen follows:

Image

Click [Next].

Image

Accept the license agreement and click [Next].

Image

Accept the suggested location for JBuilder (make a note of it; you’ll need it later) and click [Next]. The installation completes quickly.

Image

We’re ready for a first test. In KDE, launch the file manager to go to the JBuilder executable directory: /opt/jbuilder4/bin (if you installed JBuilder in /opt/jbuilder4):

Image

Click on the JBuilder icon above. Since this is your first time using JBuilder, you will need to enter your activation key:

Image

Fill in the Name and Company fields. Click [Add] to enter your activation key. Remember that this key should have been sent to you by email, and if you’ve lost it, you can retrieve it from the URL where you downloaded JBuilder 4 (see the beginning of the installation). Once your activation key is accepted, the license terms will be displayed:

Image

By clicking OK, you return to the information entry window you saw earlier:

Image

Click OK to complete this step, which runs only during the first execution. The JBuilder development environment will then appear:

Image

Exit JBuilder to install the documentation now. This will install a number of files that will be used in the JBuilder help, which is currently incomplete. Return to the directory where you extracted the JBuilder tar.gz files. The installation program is in the docs directory. Navigate to it:

[cd docs]
[ls -l]
-rw-r--r--    1 nobody   nobody       1128 Oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 Oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 Oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 Oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 Oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 Oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 Oct 10  2000 whatsnew.html

The installation file is doc_install.bin, but you cannot run it immediately. If you do, the installation will fail without you understanding why. Read the index.html file in a browser for a detailed description of the installation process. The installer requires a Java Virtual Machine (JVM); specifically, a program called java, which must be in your machine’s PATH. Note that PATH is a Unix variable whose value, in the form rep1:rep2:...:repn, specifies the directories repi that must be searched when looking for an executable. Here, the installer requests the execution of a Java program. You may have multiple versions of this program depending on the number of Java virtual machines you have installed here and there. Logically, we will use the one provided by JBuilder 4, which is located in /opt/jbuilder4/jdk1.3/bin. To add this directory to the PATH variable:

[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

We can now start the documentation installation:

[./doc_install.bin]
Preparing to install...

This is a graphical installation:

Image

It is very similar to the one for JBuilder Foundation. Therefore, we will not go into detail here. There is one screen you must not miss:

Image

The installer should normally find the location where you installed JBuilder Foundation on its own. Therefore, do not change the default settings unless, of course, they are incorrect.

Once the documentation is installed, we’re ready for another test of JBuilder. Launch the application as shown above. Once JBuilder is open, select Help > Help Topics. In the left pane, click the Tutorials link:

Image

JBuilder comes with a set of tutorials that will help you get started with Java programming. Below, we followed the "Building an Application" tutorial mentioned above.

Image

In JBuilder, go to File > New Project. A wizard will guide you through three screens:

Image

We are going to create a simple window with the title "Hello, everyone." We will call this project "hello." The example was run by root. JBuilder then offers to group all projects into a "jbproject" directory within the root login directory. The "hello" project will be placed in the "hello" directory (Project Directory Name field) within "jbproject." Click [Next].

Image

This second screen is a summary of the various paths in your project. There is nothing to change. Click [Next].

Image

The third screen asks you to customize your project. Fill in the details and click [Finish].

Now go to File/New:

Image

Select Application and click OK. A new wizard will display two screens:

Image

The Package field uses the project name. The Class field asks for the name to be given to the project’s main class. Use the name above and click [Next]:

Image

Our application includes a second Java class for the application window. Give this class a name. The Title field is the title you want to give this window. The Options pane offers options for your window. Select them all and click [Finish]. You will then return to the JBuilder environment, which has been updated with the information you provided for your project:

Image

In the top-left window (1), you see the list of files that make up your project. This includes the two .java classes we just named. In the right-hand window (2), you see the Java code for the coucouCadre class. , the bottom-left window shows the structure (classes, methods, attributes) of your project. It is ready to run. Click button 4 above, or select Run/Run Project, or press F9. You should see the following window:

Image

By clicking the Help option, you should see the information you provided to the creation wizards. We won’t go any further. It’s now time to dive into the tutorials.

Before we finish, let’s just show that you can use not JBuilder and its graphical interface, but the JDK that it brought with it and placed in /opt/jbuilder4/jdk1.3. Create the following essai1.java file:

import java.io.*;

public class test1{
    public static void main(String args[]){
        System.out.println("hello");
        System.exit(0);
    }
}

Let's compile and run it using the JBuilder JDK:

[ls -l *.java]
-rw-r--r--    1 root     root          135 May  9 21:57 test1.java
[/opt/jbuilder4/jdk1.3/bin/javac test1.java]
[/opt/jbuilder4/jdk1.3/bin/java test1]
Hello