CS136, Lecture 18

  1. Using Layout managers to build nice interfaces
    1. Panels
    2. Canvases
    3. Example of Layout of GUI components
  2. Event-Driven Programming 
    1. Events
    2. Event Handling with Listeners
    3. Who can be a listener?
    4. Summary of event handling in Java

Using Layout managers to build nice interfaces

Panels

A Panel is a type of container. GUI components can be added to a panel, which can itself be added to an applet (or indeed another Panel).

The constructor for a panel is:

public Panel()

Canvases

A Canvas is a component on which graphics can be drawn and that can receive mouse events.

Its constructor is:

public Canvas()

Both Panel and Canvas have method:

public void setSize(int width, int height)

Canvases must be resized or they will be set to have size (0,0). You can try to resize panels, but the layout manager may stretch them to a somewhat different size.

Example of Layout of GUI components

Here is an example of an application which lays out components like the Josephus applet. The full program can be found in the folder Josephus Applic in the class examples folder on Cider Press.

public Josephus extends Frame 
                            implements ActionListener, ItemListener {
    ...  // omitted constant & instance variable defs
            // fields for number of people
    protected Label numLabel 
                            = new Label("  Number of people (<= 26)");
    protected TextField number = new TextField("26");
    
            // fields for # soldiers to skip btn elimination
    protected Label countLabel = new Label("  Number to skip");
    protected TextField countOff = new TextField("7");
    protected int numSkip;
    
            // Button to start finding messenger
    protected Button start = new Button("Start");       
            // Choice button to set speed
    protected Choice speed = new Choice();
    
    // Panels and canvases for Applet
        // holds data entry fields
    Panel input = new Panel();  
        // for displaying animation of selection process
    Canvas diagram = new Canvas();  
        // holds start button and speed selector
    Panel startPanel = new Panel();             
    
// constructor
    public Josephus() {
                // sets gap of 5 pixels between components
        setLayout(new BorderLayout(5,5));

                // Set up input fields in two rows and two cols
                // using GridLayout (and leave gap of 5 pixels)
        input.setLayout(new GridLayout(2,2,5,5)); 
                // Add label and number field to input
        input.add(numLabel);    
        number.setBackground(Color.white);
        input.add(number);
        
                // Add label and field for number to skip
        input.add(countLabel);                      
        countOff.setBackground(Color.white);
        input.add(countOff);
        
                // Add input to top of frame
        add("North",input);                         
        
                // Set up canvas and add to center of frame
        diagram.setSize(200,400);                       
        add("Center",diagram);
        
                // Set up panel with start button and speed control
                // Since no explicit layout manager uses FlowLayout
        start.setBackground(Color.cyan);                
        startPanel.add(start);

                // Let this class listen to the buttons!
        start.addActionListener(this);
                // Set up speed choice button
        speed.addItem("Slow");
        speed.addItem("Medium");
        speed.addItem("Fast");
        speed.addItemListener(this);
        startPanel.add(speed);
                // Add startPanel at bottom of frame
        add("South",startPanel);
    }

See the calculator program for another relatively complex example of laying out buttons and a label.

Event-Driven Programming 

In lab we have seen how to pop up windows, use GUI components, and set up action listeners.

Event driven programming is based on an explicit or implicit loop and event queue. The idea is that the queue holds all events that have occurred and each time through the loop one event is removed from the queue and processed. Concurrently various devices generate events which are added to the queue. If the queue is ever empty the processing loop suspends until an event is added to the queue.

The event handling is built into Java and the programmer need not provide either the loop or queue. Instead events are delivered to objects which handle them.

If you really want to see the event queue, it is accessible by invoking Toolkit classes getSystemEventQueue(). One can also postEvent's and getNextEvent from an EventQueue.


Events

Events include such things as clicking on a button, making a selection from a list, clicking a mouse button, moving the mouse, depressing a key, etc.

All events inherit from Event from package java.awt. One subclass is AWTEvent. It and its subclasses can be found in the package java.awt.event.

For example there is a class PaintEvent. Objects of this class are generated any time an awt component needs to be repainted and causes the paint(Graphics g) method to be automatically called with parameter the current Graphics context (don't worry about Graphics objects for now - they are used for drawing).

Thus every Java component has a paint method which is automatically called everytime that component needs to be repainted (e.g., another object obscured part of it, but has now moved out of the way). Interestingly Java programmer guidelines forbid the programmer from explicitly calling this method. However you can override it in subclasses to make sure that repainting does what you want it to do.

The only way one is allowed to explicitly trigger repainting the screen is to execute the method:

    public void repaint()
which itself first schedules a call to the objects update method which erases the background and then calls paint with the appropriate Graphics parameter. Many of the sample programs (like Josephus) include code that overrides the paint method and that invokes the paint method indirectly through calls to repaint().

Event Handling with Listeners

Java event handling is based on a delegation model. Every time an event occurs, all registered listeners are notified. Each event type has an associated listener type and there is an associated method for attaching listeners to each component.

For example, ActionEvents are sent to Action listeners, which are registered by executing an addActionListener(...) method.

Here are examples of AWT Events, their listeners, the components generating these events and the methods of the listener class for handling the events. More are available.

Event Type   Listener Interface  Item generating    Method


ActionEvent     ActionListener        Button, MenuItem,   actionPerformed     
                                      List, TextField    
                                                           
ItemEvent       ItemListener          Choice, CheckBox,   itemStateChanged    
                                      CheckboxMenuItem    
                                                          
WindowEvent     WindowListener        Dialog, Frame       windowClosing, ...
  
MouseEvent      MouseMotionListener   Canvas, Frame,      mouseDragged,       
                                      Panel, Dialog       mouseMoved     
                                           
MouseEvent      MouseListener         Canvas, Frame,      mousePressed,       
                                      Panel, Dialog       mouseReleased,      
                                                          mouseClicked, ... 
                                                            
KeyEvent        KeyListener           Component           keyPressed,         
                                                          keyReleased,        
                                                          keyTyped            

An important feature of the new Java 1.1. event model is that the container responsible for displaying a component (e.g., the frame containing a button) need not be responsible for handling events generated by that object. By assigning a listener to an object we can explicitly delegate responsibility for handling the events generated by the object.

Who can be a listener?

So far we have seen how to do this using inner classes and using separate listener classes. It is also possible to have the class containing the component be the listener. We have done this in the Josephus class above. Note that it implements ActionListener and ItemListener. (There is no difficulty having a class implement more than one interface.)

All that is necessary is to ensure that the class provides an implementation for all methods contained in the interface. Because Josephus implements ActionListener and ItemListener, we see from the table above that it needs to provide methods actionPerformed and itemStateChanged. Here is the skeleton of these methods from the Josephus class:

    /** Post: if start button pushed run simulation & select 
                messenger, otherwise don't do anything.     */
    public void actionPerformed(ActionEvent evt)
      {
        if (evt.getSource() == start) {
            ... // code omitted
          // Ensure input fields legal or don't run.
          numPeople = Integer.parseInt(number.getText());
          if (numPeople <= 0 || numPeople > 26) 
            System.out.println("No more than 26 people");
          else {
              numSkip = Integer.parseInt(countOff.getText());
              if (numSkip < 1) 
                System.out.println("Error ...");
              else {
                    ... // do appropriate stuff
              }
                }
        }
      }

      public void itemStateChanged(ItemEvent evt){
    if (evt.getSource() == speed){
            String selection = (String)evt.getItem();
            if (selection.equals("Slow"))
                sleepTime = slowDelay;
            else if (selection.equals("Medium"))
                sleepTime = mediumDelay;
            else if (selection.equals("Fast"))
                sleepTime = fastDelay; 
    } 
  }

Java also supports the creation of "anonymous classes" which may be used as listeners, but we won't discuss that in this class. (They can save keystrokes in typing, but I find them hard to read.)

Summary of event handling in Java

The main point I want to leave you with is that the Java AWT and Event classes are very powerful and allow you to do almost anything you might want to do with GUI's in a fairly straightforward way. Moreover, these GUI's (at least theoretically) behave the same way on all platforms, though using the look of GUI components from the host computer (throught the use of so-called "peer" components from the host). Thus on a Mac you will get Mac-like windows and buttons, while on Windows they will look like the native windows and buttons.

In practice there are minor variations that can sometimes screw up the look of components on windows (e.g., the fact that buttons lose their colors in Internet Explorer 4.x). Partially as a result, Sun is also introducing a new set of libraries (the Swing libraries) which will provide exactly the same look on all platforms.

I hope this brief discussion of the Java GUI and event system has provided you with some insight into how to program with it. There is no way that I can provide detailed instruction into the use of these libraries in this course, but I hope this brief introduction will provide you with enough information that you can read in more depth to see how to accomplish more complex tasks.