Chapter 16: GUI

16.1: Component

java.awt.Component directly inherits from Object. A Component is an object having a graphical representation that can be displayed on the screen and that can interact with the user. Examples of components are the buttons, checkboxes, and scrollbars of a typical graphical user interface.

16.2: Painting Components on Graphics

Every Component has a graphical representation of itself. But this is just a representation, not painted on anything. Essentially when different components paint themselves, or when we draw an oval on a component, we are all painting on to the same physical displaying device, such as the screen or printer.

Therefore, to display itself, a component must have a connection to that physical displaying device. This connection is represented by java.awt.Graphics.

Some Components and Containers such as Button, TextField, Checkbox, Menu, Panel and Applet do not have that connection, and thus can not display themselves. While Window, Frame, Dialog etc. have that connection and can display themselves.

Non-displayable Components must be added into displayable containers to be displayed. When the displayable container's painting method is called by the OS, it will paint itself on the physical displaying device, and it will also call the painting methods of all its contained components, passing its connection to the displaying device to them, so that they can paint themselves onto the same displaying device too.

Notice that only after a displayable component is made visible by calling its show or setVisible method, is its own Graphics connection available. If you call its getGraphics method before calling show or setVisible, you will get a null pointer.

A Graphics object encapsulates state information needed for the basic rendering operations that Java supports. This state information includes the following properties:

1) The Component object on which to draw.

2) A translation origin for rendering and clipping coordinates.

3) The current clip.

4) The current color.

5) The current font.

6) The current logical pixel operation function (XOR or Paint).

7) The current XOR alternation color

You can set and get this properties. Especially, when you call its method drawString, you are drawing with a font which you set to the Graphics object by calling its method SetFont.

The following example shows how to draw on a Graphcis object:

   
   import javax.swing.*;
   import java.awt.*;
   import java.awt.event.*;
   
   class AnyImage extends JPanel {
       public void paintComponent(Graphics g)
       {
           g.drawLine(10,10,100,100);
       }
   }
   
   public class Test extends JFrame {
       Graphics graphics = null;
   
       public Test()
       {
           Container c = getContentPane();
           c.setLayout(new BorderLayout());
   
           AnyImage panel = new AnyImage();
           c.add(panel, BorderLayout.CENTER);
   
           setSize(200,200);
           setVisible(true);
   
           graphics = panel.getGraphics();
           graphics.drawOval(10,10,100,100);
       }
   
       public static void main(String [] s)
       {
           new Test();
       }
   }

The oval will be visible only for a transient moment. Because as soon as the Graphics has been changed, the OS will automatically call the component's repaint method.

Component's painting methods are:

called by method repaint. It does the following jobs:

1) Clears this component by filling it with the background color.

2) Sets the color of the graphics context to be the foreground color of this component.

3) Calls this component's paint method to completely redraw this component.

Because of the first two steps to clear the background, sometimes it causes flickering. When flickering happens, override update by simply calling paint. It may solve the problem.

Paints this component and all of its subcomponents.

Repaints this component. This method causes a call to this component's update method as soon as possible. Because you don't need to pass Graphics object to it, this method can be used to manually paint the component.

Prints this component. The default implementation of this method simply calls the paint method. Applications should override this method when it should work differently from paint.

16.3: Standard Components

All the standard components which belong to package java.awt are non-displayable components. They must be added into a displayable container eventually.

In old event model, when a relevant operation is performed on some of these components, such as when a checkbox is checked, a drop-down list item or a List item is chosen, a "standard" Event object will be generated, and this component's handleEvent will be called, which will call method action and pass the event to it.

* TextField

A TextField is a single-line area where you can write into it, or get the content of it. You can set it editable so that user can also write into it, or you can set it uneditable so that only the program can write into it. No event will be created when user is writing into it.

   
   import java.awt.*;
   import java.applet.*;
   
   public class TextField1 extends Applet {
       Button b1 = new Button("Get Text"),
              b2 = new Button("Set Text");
       TextField t1 = new TextField("Starting text", 30);
       String s = new String();
   
       public void init()
       {
           add(b1);
           add(b2);
           add(t1);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(b1))
           {
               showStatus(t1.getText());
               s = t1.getSelectedText();
              if(s. length() == 0) s = t1.getText();
               t1.setEditable(true);
           }
           else if(e1.target.equals(b2))
           {
             t1.setText("Inserted by button \"Set Text \": " + s);
               t1.setEditable(false);
           }
           else
             return super. action(e1, o1);
   
           return true;
       }
   }

* TextArea

The same as TextField except that it is a multi-line area. No event will be created when user is writing into it. You can control whether a TextArea has vertical or horizontal scrollbar by passing TextArea's constant to its constructor.

   
   import java.awt.*;
   import java.applet.*;
   
   public class TextArea1 extends Applet {
       Button b1 = new Button("Text Area 1"),
              b2 = new Button("Text Area 2"),
              b3 = new Button("Replace"),
              b4 = new Button("Insert");
       TextArea t1 = new TextArea("t1", 1, 30);
       TextArea t2 = new TextArea("t2", 4, 30);
       String s = new String();
   
       public void init()
       {
           add(b1);
           add(t1);
           add(b2);
           add(t2);
           add(b3);
           add(b4);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(b1))
               showStatus(t1.getText());
           else if(e1.target.equals(b2))
           {
               t2.setText("Inserted by Button 2");
               t2.appendText(": " + t1.getText());
               showStatus(t2.getText());
           }
            else if(e1.target.equals(b3))
            {
               String s = " Replacement ";
              t2.replaceText(s, 3, 3 + s. length());
           }
           else if(e1.target.equals(b4))
               t2.insertText(" Inserted ", 10);
           else
             return super. action(e1, o1);
   
           return true;
       }
   }

* Label

It is simply a piece of string where you can put on the panel or window.

   
   import java.awt.*;
   import java.applet.*;
   
   public class Label1 extends Applet {
       TextField t1 = new TextField("t1", 10);
       Label l1 = new Label("TextField t1");
       Label l2 = new Label("                                   ");
       Label l3 = new Label("                                    ", Label.RIGHT);
       Button b1 = new Button("Test 1");
       Button b2 = new Button("Test 2");
   
       public void init()
       {
           add(l1);
           add(t1);
           add(b1);
           add(l2);
           add(b2);
           add(l3);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(b1))
               l2.setText("Text set into Label");
           else if(e1.target.equals(b2))
           {
               if(l3.getText().trim().length() == 0)
                   l3.setText("label3");
               if(l3.getAlignment() == Label.LEFT)
                   l3.setAlignment(Label.CENTER);
               else if(l3.getAlignment() == Label.CENTER)
                   l3.setAlignment(Label.RIGHT);
               else if(l3.getAlignment() == Label.RIGHT)
                   l3.setAlignment(Label.LEFT);
           }
           else
               return super.action(e1, o1);
   
           return true;
       }
   }

* Checkbox

   
   import java.awt.*;
   import java.applet.*;
   
   public class CheckBox1 extends Applet {
       TextArea t1 = new TextArea(6, 20);
       Checkbox cb1 = new Checkbox("Check Box 1");
       Checkbox cb2 = new Checkbox("Check Box 2");
       Checkbox cb3 = new Checkbox("Check Box 3");
   
       public void init()
       {
           add(t1);
           add(cb1);
           add(cb2);
           add(cb3);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(cb1))
               trace("1", cb1.getState());
           else if(e1.target.equals(cb2))
               trace("2", cb2.getState());
           else if(e1.target.equals(cb3))
               trace("3", cb3.getState());
           else
               return super.action(e1, o1);
   
           return true;
       }
   
       void trace(String b, boolean state)
       {
           if(state)
             t1.appendText("Box " + b + " Set \n");
           else
             t1.appendText("Box " + b + " Cleared \n");
       }
   }

* Radio buttons

You first create a CheckboxGroup object, then create several checkboxes, passing this CheckboxGroup object to each of their constructors as the second argument and a boolean value as the third. Then when one of the checkboxes is checked, the rest will be automatically unchecked.

   
   import java.awt.*;
   import java.applet.*;
   
   public class RadioButton1 extends Applet {
       TextArea t1 = new TextArea(6,20);
       CheckboxGroup g = new CheckboxGroup();
       Checkbox cb1 = new Checkbox("Check Box 1", g, false);
       Checkbox cb2 = new Checkbox("Check Box 2", g, true);
       Checkbox cb3 = new Checkbox("Check Box 3", g, false);
   
       public void init()
       {
           t1.setEditable(false);
           add(t1);
           add(cb1);
           add(cb2);
           add(cb3);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(cb1))
               t1.appendText("Check box 1\n");
           else if(e1.target.equals(cb2))
               t1.appendText("Check box 2\n");
           else if(e1.target.equals(cb3))
               t1.appendText("Check box 3\n");
           else
               return super.action(e1, o1);
   
           return true;
       }
   }

* Drop-down list

The class is actually called Choice. It occupies only one line with a drop-down list. You can choose one from the options. You create a Choice object, then call its addItem method to add strings as its option items. Then you can call its getSelectedIndex to find out which option is chosen.

   
   import java.awt.*;
   import java.applet.*;
   
   public class Choice1 extends Applet {
       String [] options = {"New York", "Paris", "London", "Rome", "Belgium", 
                           "Carol", "Athens"};
       TextArea t1 = new TextArea(8,40);
       Choice c1 = new Choice();
       Button b1 = new Button("Add items");
       int count = 0;
   
       public void init()
       {
           for(int i = 0; i < 3; i++)
             c1.addItem(options[count ++]);
           t1.setEditable(false);
           add(t1);
           add(c1);
           add(b1);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(c1))
               t1.appendText("Index: "+ c1.getSelectedIndex()+" "+(String)o1+"\n");
           else if(e1.target.equals(b1))
             if(count < options. length)
                   c1.addItem(options[count++]);
           else
               return super.action(e1, o1);
   
           return true;
       }
   }

* List

A List is similar to a Choice, except that it occupies a designated number of lines, you can choose more.

   
   import java.awt.*;
   import java.applet.*;
   
   public class List1 extends Applet {
       String [] options = {"New York", "Paris", "London", "Roma", "Belgium", 
                           "Capetown", "Carow", "Athens", "San Fransisco", 
                           "Los Angelos"};
       TextArea t1 = new TextArea(5,30);
       List l1 = new List(5, true);
       Button b1 = new Button("Test");
       int count = 0;
   
       public void init()
       {
           for(int i = 0; i < 3; i++)
               l1.addItem(options[count++]);
           t1.setEditable(false);
           add(t1);
           add(l1);
           add(b1);
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(l1))
           {
               String [] items = l1.getSelectedItems();
               t1.setText("");
               for(int i = 0; i < items.length; i++)
                   t1.appendText(items[i] + "\n");
           }
           else if(e1.target.equals(b1))
               if(count < options.length)
                   l1.addItem(options[count++]);
           else
               return super.action(e1, o1);
   
           return true;
       }
   }

16.4: Container

Class java.awt.Container extends Component. It is used to hold Components.

Components added to a container are tracked in a list. The order of the list will define the components' front-to-back stacking order within the container. If no index is specified when adding a component to a container, it will be added to the end of the list (and hence to the bottom of the stacking order).

To add Components, simply call Container's add methods.

16.5: LayoutManager

To arrange Components in a Container, Java provides an interface java.awt.LayoutManager. Its sub classes include FlowLayout, BorderLayout, GridLayout, BoxLayout, CardLayout, GridBagLayout, etc. To set the layout manager for a container, call Container's setLayout method

Although one kind of LayoutManager can only arrange content pane in a certain way, by putting component in different panels with different LayoutManagers, then put these panels in another Frame or panel, you can achieve any complex layout.

By passing true or false to Component's setVisible method, a component can be shown or hidden at run time. When the layout is changed because of this, you can pass the content pane to LayoutManager's method layoutContainer to rearrange the layout. Suppose the following code is in a class which extends JFrame:

   
   BorderLayout border = new BorderLayout();
   Container c = getContentPane();
   c.setLayout(border);
   ...
   border.layoutContainer(c);

* FlowLayout

Most basic layout manager. GUI components are placed in the container from left to right. When the edge is reached, next compoenent will be placed in next line. The alignment of the whole layout can be changed at run-time by passing FlowLayout.LEFT /CENTER /RIGHT to its method setAlignment, then rearrange the layout by calling its method layoutContainer:

   
   JFrame frame = new JFrame();
   Container c1 = frame.getContentPane();
   
   FlowLayout layout = new FlowLayout();
   c1.setLayout(layout);
   
   layout.setAlignment(FlowLayout.CENTER);
   layout.layoutContainer(c1);

* BorderLayout

It devides the layout into north, south, west, east and center area. Components placed on the north and south does not change their height but extends horizontally. Components placed on the west and east do not change their width but extend veritcally. Component placed on the center extends on both directions. When a component is missing, other components will extend to fill its vacance.

Its constructor can take two integer arguments specifying the vertical and horizontal gap between components.

When adding a component into a container ruled by BorderLayout, pass BorderLayout.NORTH /SOUTH /WEST /EAST /CENTER as the second argument.

   
   JFrame frame = new JFrame();
   Container c1 = frame.getContentPane();
   
   BorderLayout layout = new BorderLayout(5, 5);
   c1.setLayout(layout);
   c1.add(new JButton(), BorderLayout.NORTH);
   

* GridLayout

GridLayout divides the layout equally into grids. Each component in the layout has the same height and width. Constructor arguments include number of rows and columns and optionally the horizontal and vertical gap. Later when you add components, they are placed in sequence from left to right, from top to down.

   
   JFrame frame = new JFrame();
   Container c1 = frame.getContentPane();
   
   GridLayout layout = new GridLayout(2, 3, 5, 5);
   c1.setLayout(layout);
   c1.add(new JButton());
   

* CardLayout

   
   JPanel deck = new JPanel();
   CardLayout cardLayout = new CardLayout();
   deck.setLayout(cardLayout);
   
   JPanel card1 = new JPanel();
   card1.add(...);
   deck.add(card1, "Name of card1");
   
   ...
   deck.add(card2, "Name of card2");
   
   cardLayout.first(deck);
   cardLayout.next(deck);
   cardLayout.previous(deck);
   cardLayout.last(deck);

* GridBagLayout

A content pane managed by GridBagLayout is not geographically divided into equal grids like GridLayout. Instead it is divided into columns and rows of components. If there are already two components horizontally, the third component placed next to the second one will have a position of column 3. The sizes of the components do not matter.

All components are aligned both vertically and horizontally in spite of their sizes. The height of a row is decided by the highest component in that row, and the width of a column is decided by the widest component in that column. Other smaller components in the same row or column can choose whether to span themselves to fill the gap, or to stay on the middle of the cell.

Class GridBagConstraints has some public fields representing all necessary position and space information to locate one component:

the column and row location of the component (its left upper corner, in case it occupies multiple columns and rows).

the number of columns and rows a component occupies.

Every component can have a weight factor on any direction. If all component's weight factors are 0, then all of them are clustered together in the center of the content pane, leaving all extra space surrounding them. If some of them have a weight factor greater than 0, then the extra space will be divided between them in propotion with their weight factors, and the group of components will expend to consume all space in that direction.

Have four possible values: GridBagConstraints.NONE /HORIZONTAL /VERTICAL /BOTH. Decides on which direction the component will expend to fill extra space.

Before putting one component into the content pane, you must first set GridBagConstraints's relevant fields, then pass it to GridBagLayout's setConstraints method.

   
           Container c1 = getContentPane();
           GridBagLayout gridBagLayout = new GridBagLayout();
           c1.setLayout(gridBagLayout);
   
           GridBagConstraints constraints = new GridBagConstraints();
           constraints.fill = GridBagConstraints.NONE;
           constraints.gridx = 0;
           constraints.gridy = 0;
           constraints.gridwidth = 2;
           constraints.gridheight = 1;
           constraints.weightx = 100;
           constraints.weighty = 1;
   
           JTextArea t1 = new JTextArea(5,5);
   
           gridBagLayout.setConstraints(t1, constraints);
           c1.add(t1);

16.6: Panel

Class java.awt.Panel is the simplest Container. A Panel provides space in which an application can attach any other component, including other Panels. The default layout manager for a Panel is the FlowLayout.

Panel is not displayable. It has to be added into a displayable window.

16.7: Applet and JApplet

Class java.applet.Applet extends a Panel. So it is a container which can hold a group of Components. Just like a panel, it can not be displayed by itself. It has to be added into a window or typically, a browser.

javax.swing.JApplet inherits from Applet.

An applet is not a stand-along application. It does not have a main method. It must be added into a window, which can be a web browser, an applet viewer or a Frame. It provides the following methods to be called to perform its function. The implementation of these methods provided by class Applet does nothing.

Called by the browser or applet viewer to inform this applet that it has been loaded into the system. It is always called before the first time that method start is called.

A subclass of Applet should override this method if it has initialization to perform. For example, an applet with threads would call the init method to create the threads, and call the destroy method to kill them. It may create a Socket in init and close it in destroy.

Called by the browser or applet viewer to inform this applet that it is being reclaimed, and that it should release any resources that it has allocated. Method stop will always be called before destroy.

Called by the browser or applet viewer to inform this applet that it should start its execution. It is called after the init method and each time the applet is revisited in a Web page.

A subclass of Applet should override this method if it has any operation that it wants to perform each time the Web page containing it is visited. For example, an applet with animation might want to use the start method to resume animation, and the stop method to suspend the animation.

Called by the browser or applet viewer to inform this applet that it should stop its execution. It is called when the Web page that contains this applet has been replaced by another page, and also just before the applet is to be destroyed.

Because an applet is a panel, the browser will automatically call its painting methods at approprite time.

16.8: Html Tag of Applet

An applet is embed into a Html file with an applet tag. The tag specifies the name and location of the applet's class file (if no location provided the browser will go to the locations specified by CLASSPATH), the size and alignment of the applet window. The applet tag can also pass some parameters to the applet.

Then when a web browser opens and displays that Html file and sees the applet tag, it will assign a window on its web page for it, go get the class file of the applet, run and display it at the place of the tag.

An Html applet tag may look like:

   
   <APPLET CODE="demoxx.class" CODEBASE="demos/" NAME="smily" ARCHIVE="name.jar" WIDTH="100" HEIGHT="50" ALIGN="Top" >
   <PARAM NAME="afg" VALUE="000000" >
   <PARAM NAME="RepeatTime" VALUE="16" > 
   </APPLET>

Explanation:

<APPLET the beginning of the Html applet code

CODE="demoxx.class" name of the applet code file (usually a 'class' file)

CODEBASE="demos/" location of the applet (relative as it is here, or a full URL)

NAME="smily" the name you want to give to this instance of the applet on this page. It is used when other applets or JavaScript invokes this applet.

ARCHIVE="name.jar" the JAR file which contains the class file.

WIDTH="100" physical width of the applet on your page

HEIGHT="50" physical height of the applet on your page

ALIGN="Top" align the applet window within its page space (top, bottom, right, center)

> end of the applet description

<PARAM specifies a parameter that can be passed to the applet (applet specific)

NAME="RepeatTime" the name known internally by the applet in order to receive this parameter

VALUE="16" the value you want to pass for this parameter

> end of this parameter

</APPLET> the end of the Html applet code

* Applet parameters

The parameter names can be anything specified by the applet's author. When you write the applet tag you have to know the parameter names used in that applet and the domain of that parameter. This information is typically supplied via the applet's documentation.

The web browser will pick the names and values of all parameters defined in the applet tag. When the applet is running, it will call the browser's method getParameter, passing the parameter name, to get the value of the parameter.

   
   int repeat = Integer.parseInt(getParameter("Repeat"));

Parameters are applet-specific and can be used to change an applet's appearance and/or to change its behavior; therefore parameters can make an applet very flexible and versatile. An applet can use none or more parameters.

16.9: An Example about Component, Container, LayoutManager and Applet

The following example demonstrates the use of standard components, containers, layout managers, applets and applet tags in Html files, and the mechanism of event handling method handleEvent( ) and action( ).

The code of the applet is:

   
   import java.awt.*;
   import java.applet.*;
   
   public class HandleEvent1 extends Applet {
       TextArea t1 = new TextArea(20,50);
       Button b1 = new Button("Do nothing");
   
       public void init()
       {
           t1.setEditable(true);
           add(t1);
           add(b1);
       }
   
       public boolean action(Event e1, Object o1)
       {
           t1.appendText("action() got called! \n");
           return super.action(e1, o1);
       }
   
       public boolean handleEvent(Event e1)
       {
           if(e1.id == Event.KEY_PRESS)
           {
             t1.appendText("Key pressed! \n");
               if(e1.key == 'a')
                   t1.appendText("The key is " + e1.key + "!\n");
           }
           else if(e1.id == Event.KEY_RELEASE)
              t1.appendText("Key released! \n");
           else if(e1.id == Event.KEY_ACTION)
           {
              t1.appendText("Non-ASCII key pressed! \n");
               if(e1.key == Event.F1)
              t1.appendText("F1 pressed! \n");
           }
           else if(e1.id == Event.MOUSE_DOWN)
              t1.appendText("Mouse Down! \n");
           else if(e1.id == Event.MOUSE_UP)
              t1.appendText("Mouse up! \n");
           else if(e1.id == Event.GOT_FOCUS)
              t1.appendText("Got focus! \n");
           else if(e1.id == Event.LOST_FOCUS)
              t1.appendText("Lost focus \n");
           else if(e1.id == Event.F1)
               t1.appendText("F1 key pressed!");
           else
           {
               //t1.appendText("handleEvent got called -- ");
               return super.handleEvent(e1);
           }
   
           return true;
       }
   }

The Html file contains nothing but an applet tag:

   
   <applet code = "HandleEvent1.class" width = 300 height = 300> 
   </applet>

The behavior of the applet is:

  1. When you click inside the boundary of the applet (defined in the applet tag, 300 by 300), "Got focus!" is shown in the text area
  2. No event will be displayed when the applet is out of focus
  3. When you press an ASCII key, "Key pressed!" is shown
  4. When you press a non-ASCII key, "Non-ASCII key pressed!" will be shown
  5. When you press or release the mouse button, "Mouse pressed!" or "Mouse released!" will be shown

16.10: Window

Class java.awt.Window can be shown or hidden, can get focus or lose focus, can have its owner or listeners, can be brought to the front or back. Its subclasses include java.awt.Frame and javax.swing.JFrame.

Most platforms allow a limitted number of windows to be displayed on the screen. So if a window is no longer used, its resources should be given back to the operating system. Method dispose will releases all of the native screen resources used by this Window, its subcomponents, and all of its owned children. But it does not release the memory it occupies. You can still call its methods to manipulate its fields.

To make a window displayed, call its show or pass true to setVisible method. Before that, you should call its setSize method to set its size.

Window generates WindowEvent which is sent to a WindowListener with following methods:

  1. windowActivated: window is made active by click on it
  2. windowDeactivated: another window is made active
  3. windowClosed: window is closed
  4. windowClosing: user initiates closing of the window
  5. windowIconified: window is minimized
  6. windowDeiconified: window is restored from minimized
  7. windowOpened: window is first-time displayed on the screen

16.11: Frame

Class java.awt.Frame extends Window. It has a title and a border. Whether it can be resized can be controlled and checked by getResizable and setResizable. You can also change the cursor over the window. The size of a Frame is set by resize.

16.12: Menu and JMenu

There are three layers of menu-related items:

one Frame can only have one MenuBar. It can be set at anytime with setMenuBar, or checked with getMenuBar.

one entry on the MenuBar, such as "File", "Edit", "View", etc. The same Menu can not be added into two or more MenuBars.

java.awt.CheckboxMenuItem and javax.swing.JCheckboxMenuItem

one entry under a Menu, such as "New", "Open", "Close" under "File". If there are more than three MenuItems, you can insert separator with method addSeparator.

CheckboxMenuItem is a MenuItem which have can be ticked or unticked and remembers its state, which you can get and check with getState and setState.

a menu item. When multiple JRadioButtonMenuItems are added into a ButtonGroup, only one of them can be selected.

Example:

   
   import java.awt.*;
   import java.awt.event.*;
   
   class Menu1 extends Frame {
       MenuBar mb1 = new MenuBar();
       Menu m1 = new Menu("Menu1");
       MenuItem m11 = new MenuItem("MenuItem 11");
       CheckboxMenuItem m12 = new CheckboxMenuItem("MenuItem 12");
   
       MenuBar mb2 = new MenuBar();
       Menu m2 = new Menu("Menu2");
       MenuItem m21 = new MenuItem("MenuItem 21");
       CheckboxMenuItem m22 = new CheckboxMenuItem("MenuItem 22");
   
       TextArea t1 = new TextArea("", 5, 30,TextArea.SCROLLBARS_BOTH);
       Button b1 = new Button("Swap MenuBar");
   
       public Menu1()
       {
           mb1.add(m1);
           m1.add(m11);
           m1.add(m12);
           m11.setActionCommand("Command 11");
           m12.setActionCommand("Command 12");
   
           mb2.add(m2);
           m2.add(m21);
           m2.add(m22);
           m21.setActionCommand("Command 21");
           m22.setActionCommand("Command 22");
   
           addWindowListener(new WindowAdapter()  // anonymous inner event handler
               {
                   public void windowClosing(WindowEvent e)
                   {  System.exit(0); }
               });
           m11.addActionListener(new ItemHandler1());
           m12.addItemListener(new CheckboxHandler1());
           m21.addActionListener(new ItemHandler1());
           m22.addItemListener(new CheckboxHandler1());
           b1.addActionListener(new ButtonHandler1());
   
           setTitle("Menu Testing Program");
           setMenuBar(mb1);
           setLayout(new FlowLayout());
           add(b1);
           add(t1);
           setResizable(false);
           setSize(300,200);  // new form of resize()
           show();
       }
   
       public class CheckboxHandler1 implements ItemListener { // Inner class
           public void itemStateChanged(ItemEvent i1)
           {
               CheckboxMenuItem temp = (CheckboxMenuItem)(i1.getSource());
               t1.setText("getLabel()= " + temp.getLabel()
                          + "\ngetActionCommand()= " + temp. getActionCommand());
               if(temp. getState())
                   t1.append("\nMenu checked");  // new form of appendText()
               else
                   t1.append("\nMenu unchecked");
           }
       }
   
       public class ItemHandler1 implements ActionListener{ //MenuItem only support
           public void actionPerformed(ActionEvent e1)      //ActionListener
           {
               MenuItem temp = (MenuItem)(e1.getSource());
               t1.setText("getLabel()= " + temp. getLabel()
                   + "\n getActionCommand()= " + temp. getActionCommand());
           }
       }
   
       public class ButtonHandler1 implements ActionListener {
           public void actionPerformed(ActionEvent e1)
           {
               MenuBar temp = getMenuBar();
               if(temp == mb1)
                   setMenuBar(mb2);
               else
                   setMenuBar(mb1);
           }
       }
   }
   
   public class TestMenu1 {
       public static void main(String [] argu)
       {
           Menu1 m1 = new Menu1();
       }
   }

Each MenuItem has two members: label and action command. They are both Strings and can be set and got. In most cases they are identical such as "Open", "Save", "Exit", etc. The reason to introduce two strings is: if we use the label is as display and the action command in coding, then when we change the operating system where this code is to be used, we only need to change the label and do not need to change those action commands in the code.

16.13: Dialog

Class java.awt.Dialog is a Window, just like a Frame. A dialog must have either a frame or another dialog defined as its owner when it's constructed. The owner does not need to be shown. When the owner of a visible dialog is hidden or minimized, the dialog will automatically be hidden from the user. When the owner window is re-opened, then the dialog is made visible to the user too.

A dialog can be either modaless (the default) or modal. A modal dialog is one which keeps the control of the computer, and blocks the main thread (except for any windows created by this dialog) until this dialog is closed. This feature is very useful in case when you create a new dialog, and can not continue your process until the operation in that dialog is finished, like a FileDialog. If the dialog can not hold the control, then the main program will go on without waiting for the result of the dialog. You control the modality by passing true or false to the Dialog constructor.

Dialogs are capable of generating the following window events: WindowOpened, WindowClosing, WindowClosed, WindowActivated, WindowDeactivated.

A dialog can not have MenuBar.

   
   import java.awt.*;
   
   class Dialog1 extends Dialog {
       static int count = 1;
       TextField width = new TextField(3);
       TextField height = new TextField(3);
       Button b1 = new Button("New Dialog");
   
       public Dialog1(Dialog parent, int w1, int h1)  // Dialog as owner
       {
           super(parent, "Dialog " + count, false); // Madaless!
           count++;
           setLayout(new FlowLayout());
           resize(w1, h1);
           add(width);
           add(height);
           add(b1);
       }
   
       public Dialog1(Frame parent, int w1, int h1)  // Frame as owner
       {
           super(parent, "Dialog " + count, true); // Madal!
           count++;
           setLayout(new FlowLayout());
           resize(w1, h1);
           add(width);
           add(height);
           add(b1);
       }
   
       public boolean handleEvent(Event e1)
       {
           if(e1.id == Event.WINDOW_DESTROY)
               dispose();
           else
               return super.handleEvent(e1);
           return true;
       }
   
       public boolean action(Event e1, Object o1)
       {
           if(e1.target.equals(b1))
           {
               Dialog1 d1 = new Dialog1(this,
   Integer.parseInt(width. getText()),
   Integer.parseInt(height. getText()));
               d1.show();
           }
           else
               return super.action(e1, o1);
           return true;
       }
   }
   
   public class TestDialog1 {
       public static void main(String [] argu)
       {
           Frame f1 = new Frame();
           Dialog1 d1 = new Dialog1(f1, 100, 100);
           d1.show();
           System.out.println("After t1.show()!");
       }
   }

In this example, both the root Frame and is children Dialogs have two TextFields which you can input the width and height of the new Dialog, and then press "New Dialog" button to create a new Dialog of the specified size.

Because the dialog created by the Frame in the main is madal, the "After t1.show( )!" will be shown only after the root dialog is closed.

16.14: FileDialog

Class java.awt.FileDialog is a special Dialog which calls the file-open or file-save dialog of the OS. It provides two text fields labeled "File name" and "File type", and lists the directory structure and the list of files in the chosen directory. You can either specify the filename in the text field, or use cursor to browse through the file hierarchy.

The FileDialog itself can not actually open or save a file. It just provide method setFile and setDirectory so that the program can write into the two text fields, and getFile and getDirectory to acquire your specified filename and directory name. Then you can use normal IO streams such as FileInputStream or FileWriter to read from or write into or open a file.

   
   import java.awt.*;
   
   public class TestFileDialog1 extends Frame {
       public static void main(String [] argu)
       {
           TestFileDialog1 t1 = new TestFileDialog1();
           FileDialog d1 = new FileDialog(t1, "What to open?");
           d1.setFile("*.java");
           d1.setDirectory(".");
           d1.show();
          System.out.println("\n The filename you chose to open is " + d1.getFile()
                             + "\n" + "The directory is " + d1.getDirectory());
   
           FileDialog d2 = new FileDialog(t1, "What to save?", FileDialog.SAVE);
           d2.setFile("*.java");
           d2.setDirectory(".");
           d2.show();
           System.out.println("\nThe filename you chose to save is " + d2.getFile()
                             + "\n" + "The directory is " + d2.getDirectory());
       }
   }

Output will be something like:

   
   The filename you chose to open is be2.tmp
   The directory is C:\TEMP\spss131\
   
   The filename you chose to save is be4.tmp
   The directory is C:\TEMP\spss131\

16.15: Class ToolKit

Class java.awt.ToolKit is the abstract superclass of all actual implementations of the Abstract Window Toolkit. Subclasses of Toolkit are used to bind or connect the various components to particular native toolkit implementations.

Class Window has a method

Toolkit getToolkit()

to return its own ToolKit.

Most applications should not call any of the methods in this class directly. The methods defined by Toolkit are designed to connect the platform-independent classes in the java.awt package with their counterparts in java.awt.peer. Some methods defined by Toolkit query the native operating system directly.

You can get lots of information about the native system with its get functions. Among them,

public abstract PrintJob getPrintJob(Frame frame, String jobtitle, Properties props)

is to get a PrintJob object which is the result of initiating a print operation on the toolkit's platform. Properties can be null.

16.16: Class Properties

Class java.util.Properties extends java.util.Hashtable, it is a list of keys and values which are all strings. It represents a persistent set of properties. It can be saved to a stream or loaded from a stream using method

   
   list(PrintStream)
   list(PrintWriter)
   store(OutputStream, String header)
   load(InputStream). 

The two list methods writes the content of the Properties object to the output stream. Method store writes the content in a format which is suitable for loading in with method load later. The header is just a commet line starting with "#".

When loading the key/element pairs from an InputStream, each pair should occupy one line terminated by "\n", "\r" or "\r\n", separated by "=" or ":". Whitespace characters are ignored unless acting as the separation. "\" in the end of a line joins this line with next line.

Method

   
   Object setProperty(String key, String value)

Adds new pairs into the Hashtable by calling Hashtable's put method.

Class Properties has a protected Properties member "defaults". Constructor "Properties(Properties)" assigns a Properties object to "defaults". When getProperty can not find a key, it will search the "default" member and get a value as a default value for that key.

Following is a file named "TestProperties.txt" and the code to load it in:

   
   #This is a comment line
   Name=Frank Liu
   Name=Ellen Xie
   Age=33
   Address=6//11 Adelaide St Murrumbeena Vic 3163
   
   
   import java.io.*;
   import java.util.*;
   
   public class TestProperties {
       public static void main(String [] s) throws IOException
       {
           FileInputStream f1 = new FileInputStream("TestProperties.txt");
           Properties p1 = new Properties();
           p1.load(f1);
           f1.close();
           System.out.println(p1.toString());
           System.out.println("Name = " + p1.getProperty("Name", "DefaultName"));
           System.out.println("Sex = " + p1.getProperty("Sex", "Male"));
       }
   }

Output will be:

   
   {Name=Ellen Xie, Age=33, Address=6//11 Adelaide St Murrumbeena Vic 3163}
   Name = Ellen Xie
   Sex = Male

From the example you can see that if the file contains duplicate keys, only the last one is taken.

16.17: Class Dimension

Class java.awt.Dimension holds two non-negative integers width and height, mainly used to describe the size of a window, so that some methods can return it the two integers as one object. If set to negative, some methods will have undefined behavior.

16.18: Class PrintJob

Class java.awt.print.PrintJob is an abstract class which initiates and executes a print job. It provides access to a print graphics object which renders to an appropriate print device with method getGraphics. It has an end method to end itself and do necessary clear up, and can return a Dimension object and the resolution of the page.

A PrintJob belongs to AWT. To get it, you can call Toolkit's getDefaultToolkit method, or call your window or frame's method getToolkit. Then you can call the Toolkit's method getPrintJob to get the PrintJob object. Then you can get the Graphics object from that PrintJob object, then call this Graphics object's draw methods to draw onto the paper space in the printer.

To force the printing, you have to call the Graphics object's dispose method and the PrintJob object's end method.

    
   import java.awt.*;
   import java.awt.event.*;
   
   public class Test extends Frame {
       public static void main(String [] argu)
       {
           Test test = new Test();
           Toolkit tk1 = test. getToolkit();
           // or Toolkit tk1 = Toolkit. getDefaultToolkit();  
           PrintJob pj1 = tk1.getPrintJob(test, "Printing Test", null);
           int pagewidth = pj1.getPageDimension().width;
           int pageheight = pj1.getPageDimension().height;
           Graphics g1 = pj1.getGraphics();
   
           g1.drawString("This is the string I want to print. ", 100, 100);
           g1.drawOval(200, 200, 80, 60);
   
           // You must do the following two things to force the printing
           g1.dispose();
           pj1.end();
   
           System.exit(0);
       }
   }

16.19: Class Color and JColorChooser

Class java.awt.Color has a set of constants representing basic color set including orange, pink, cyan, magenta, yellow, black, white, gray, lightGray, darkGray, red, green, blue. It's constructor takes three RGB integers or floats. It has methods such as getRed, getGreen, getBlue to get the color content.

Class Graphics has a getColor and setColor method to get and set the current color of the graphics context.

Class javax.swing.JColorChooser provides a dialog containing a color palette for choosing color.

   
   Color c1 = JColorChooser.showDialog(this, "Please choose a color", c1);

Method showDialog needs three arguments: a handle of the parent Component, a title for the dialog, and the initial color for the dialog. It returns the selected color.

16.20: Class Font

Class java.awt.Font's constructor takes the font name (such as "TimesRoman"), style (such as "Font.ITALIC") and size. Class Graphics has a getFont and setFont method.