Chapter 18: Swing GUI

18.1: Swing Components

AWT components are directly tied to the window system of the local platform. They look the same as other windows of the local platform. On different platforms they have different appearances and sometimes even different interactions. They are heavy-weight components because of the complex GUI capabilities of the local platform.

Compared with awt components, Swing components in package javax.swing are light-weight. They are written totally in Java. They are platform independent. However, they provide a look-and-feel functionality to match their apearances with different platforms.

All swing components inherits from JComponent, whose super classes are

java.awt.Container <= java.awt.Component <= java.lang.Object.

It has a method setToolTipText to set a tip on a component, so that when the cursor is placed upon a component a tip can be shown for a short time.

Every JComponent has an object of class EventListenerList called listenerList. All registered listeners are stored in the listenerList.

18.2: Painting a JComponent

When JComponent's repaint method is called, it calls method paintComponent, not like awt components which call method update and update calls method paint.

Combining swing components and drawing in one window often results in improper display. The solution is to have a dedicated drawing areas provided by a separate JComponent such as JPanel. To draw to such a JComponent, override its paintComponent method and call its super class's paintComponent at the first line.

Most swing components are transparent by default. The transparent state can be set by passing true or false to JComponent's method setOpaque. If a JComponent is opaque, when paintComponent is called, its background will be cleared.

   
   import javax.swing.*;
   import java.awt.*;
   
   public class OvalAndRect extends JPanel {
       public final static int CIRCLE = 1, SQUARE = 2;
       private int shape;
       private int size;
   
       public void paintComponent(Graphics g)
       {
           super.paintComponent(g);
   
           if(shape == CIRCLE)
               g.fillOval(50, 10, size, size);
           else if(shape == SQUARE)
               g.fillRect(50, 10, size, size);
       }
   
       public void draw(int sh, int si)
       {
           shape = sh;
           size = si;
           repaint();
       }
   }

18.3: ImageIcon

ImageIcon belongs to package javax.swing and implements interface Icon. It supports two image formats: gif and jpeg. To create an ImageIcon:

   
   Icon icon = new ImageIcon("car1.gif");

The image file is assumed to be in the same directory as the program.

18.4: JLabel

JLabel can have an ImageIcon. Suppose "icon" is an ImageIcon:

   
   JLabel l1 = new JLabel("Label content", icon, SwingConstants.LEFT);

By default, the text appears to the right of the icon. This alignment can be set with method setHorizontalAlignment and setVerticalAlignment.

18.5: JFrame

To add any component into JFrame, you have to first call getContentPane to acquire a Container, call the container's setLayout and add method.

18.6: JButton

JButton's constructor can take an ImageIcon as an argument. You can also link another ImageIcon with it using method setRolloverIcon, so that when the mouse is over the JButton, the image will change to the second one.

18.7: JTextArea

A JTextArea does not have scrollbar or border. It simply appears to be a blank space. To provide scrollbar to it, wrap JScrollPane around it.

18.8: Example about ImageIcon, JFrame, JButton and JTextField

   
   import javax.swing.JFrame;
   import javax.swing.JButton;
   import javax.swing.JTextField;
   import javax.swing.SwingConstants;
   import javax.swing.ImageIcon;
   
   import java.awt.event.ActionEvent;
   import java.awt.event.ActionListener;
   import java.awt.event.WindowEvent;
   import java.awt.event.WindowAdapter;
   import java.awt.Container;
   import java.awt.FlowLayout;
   
   
   public class SwingComponents extends JFrame {
       JTextField t1 = null;
       JButton b1 = null;
   
       public SwingComponents()
       {
           super("Swing components");
           addWindowListener(new WListener());
           Container c1 = getContentPane();
           c1.setLayout(new FlowLayout(SwingConstants.LEFT));
   
           ImageIcon ii1 = new ImageIcon("Frank.jpg");
           ImageIcon ii2 = new ImageIcon("Ellen.jpg");
   
           t1 = new JTextField(30);
           t1.addActionListener(new AListener());
           c1.add(t1);
   
           b1 = new JButton("Button1", ii1);
           b1.setRolloverIcon(ii2);
           b1.addActionListener(new AListener());
           c1.add(b1);
   
           setSize(400, 500);
           show();
       }
   
       private class AListener implements ActionListener {
           public void actionPerformed(ActionEvent e)
           {
               if(e.getSource() == t1)
                   t1.setText("Enter key pressed");
               else if(e.getSource() == b1)
                   t1.setText("Button pressed");
           }
       }
   
       private class WListener extends WindowAdapter {
           public void windowClosing(WindowEvent e)
           {
               dispose();
               System.exit(0);
           }
       }
   
       public static void main(String [] args)
       {
           new SwingComponents();
       }
   }

18.9: JComboBox

A JComboBox is a drop-down list. Method setMaximumRowCount sets the maximum number of rows that can be displayed. If there are more rows, it automatically provides a scrollbar. Method getSelectedIndex returns the index of the selected item. It generates ItemEvents.

You can either create a JComboBox wrapping around an array of items such as Strings, or an empty one and add items later.

18.10: JList

A list of items to be selected. It does not automatically provide a scrollbar when the number of items are bigger than its size. To acquire a scroll bar you have to wrap a JScrollPane around it.

When one is selected, a ListSelectionEvent is generated and passed to a ListSelectionListener.valueChanged.

Class ListSelectionModel defines three constants: SINGLE_SELECTION - only one item is allowed to be selected at one time; SINGLE_INTERVAL_SELECTION - allows multiple items which are adjacent to each other to be selected; MULTIPLE_INTERVAL_SELECTION - allows any multiple items to be selected. One of these constants can be passed to JList's method setSelectionMode to set the selection model.

You can either create a JList wrapping around an array of items such as Strings, or an empty one and add items later.

18.11: JScrollPane

JScrollPane is used to wrap around a Component, which provide a view port into that component. The horizontal and vertical scrollbars can have three possible policies: always shown, shown when needed, never shown. It has six constants to represent these policies:

   
   VERTICAL_SCROLLBAR_ALWAYS
   VERTICAL_SCROLLBAR_AS_NEEDED
   VERTICAL_SCROLLBAR_NEVER
   
   HORIZONTAL_SCROLLBAR_ALWAYS
   HORIZONTAL_SCROLLBAR_AS_NEEDED
   HORIZONTAL_SCROLLBAR_NEVER

To set the policy for a JScrollPane, call its method setVerticalScrollBarPolicy and setHorizontalScrollBarPolicy.

   
   import javax.swing.JList;
   import javax.swing.JScrollPane;
   import javax.swing.JFrame;
   import javax.swing.SwingConstants;
   import javax.swing.ListSelectionModel;
   
   import java.awt.Container;
   import java.awt.FlowLayout;
   
   public class TestJScrollPane {
        public static void main(String [] args)
        {
             JFrame jf1 = new JFrame("Testing JScrollPane");
             Container c1 = jf1.getContentPane();
   
             String [] names = 
                {"Frank", "Ellen", "Junie", "Tony", "Ben", "Crazy Bush"};
             JList jl1 = new JList(names);
             jl1.setVisibleRowCount(4);
             jl1.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
   
             JScrollPane jsp1 = new JScrollPane(jl1);
   
             c1.add(jsp1);
             c1.setLayout(new FlowLayout(SwingConstants.CENTER));
             jf1.setSize(100, 200);
             jf1.show();
        }
   }

18.12: Box & BoxLayout

Class javax.swing.Box is a light-weight container which uses javax.swing.BoxLayout as its LayoutManager.

There are two kinds of BoxLayout managers: horizontal and vertical BoxLayout. They arrange GUI components along the X-axis or Y-axis of the container on one line.

Box has several static methods:

returns a Box with horizontal/vertical BoxLayout. E.g.:

Glue is an invisible GUI component with variable height or width or both, to be placed between fixed-size components to occupy additional space.

Strut is an invisible GUI component with a fixed pixel height or width, to guarantee the fixed amount of space between components.

Rigid area is an invisible GUI component with vixed pixel height and width.

Example:

   
   Box b1 = Box.createHorizontalBox();
   b1.add(new JButton("B1"));
   b1.add(Box.createHorizontalStrut(25));
   b1.add(Box.createGlue());
   b1.add(Box.createRigidArea(12,8));
   frame.add(b1);

18.13: JSlider

A JSlider presents a slider with a thumb on it. Its constructor takes four arguments:

   
   JSlider j1 = JSlider(SwingConstants.HORIZONTAL, 0, 200, 10)

they are the orintation of the JSlider, the minimum and maximum value on the slider, the initial position of the thumb. To switch the maximum and mininum value positions, pass true to JSlider's method setInverted.

When the thumb is moved, it generates a ChangeEvent, which is sent to a ChangeListener's stateChanged method.

18.14: JFrame

Although JFrame belongs to package javax.swing, it inherits from java.awt.Window, not JComponent. So it is platform-dependent and it is a heavy-weight component.

JFrame supports three options when user closes the window. It is set by passing one constant in interface WindowConstants in package javax.swing to JFrame's method setDefaultCloseOperation. The constants are DISPOSE_ON_CLOSE, DO_NOTHING_ON_CLOSE and HIDE_ON_CLOSE (the default).

To use a JMenuBar, call its method setJMenuBar.

18.15: JPopupMenu

   
   import java.awt.Container;
   import java.awt.event.MouseEvent;
   import java.awt.event.MouseAdapter;
   
   import javax.swing.JPopupMenu;
   import javax.swing.JFrame;
   import javax.swing.JButton;
   
   
   public class Test {
       private static JPopupMenu popup = new JPopupMenu();
   
       public static void main(String [] s)
       {
           popup.add("String item");
           popup.add(new JButton("JButton Item"));
           JFrame f1 = new JFrame();
           f1.addMouseListener(new PopupListener());
           f1.setSize(300,300);
           f1.setVisible(true);
       }
   
       static private class PopupListener extends MouseAdapter {
           public void mouseReleased(MouseEvent e1)
           {
               if(e1.isPopupTrigger())
               popup.show(e1.getComponent(), e1.getX(), e1.getY());
           }
       }
   }

18.16: Look and Feel

   
   UIManager.LookAndFeelInfo [] look = UIManager.getInstalledLookAndFeels();
   UIManager.setLookAndFeel(look[2].getClassName());
   SwingUtilities.updateComponentTreeUI(this);

The first line gets an array of class LookAndFeelInfo (which is an inner class of class javax.swing.UIManager) from the local platform which represents all look-and-feels the platform supports. LookAndFeelInfo's method getClassName returns the name of the corresponding javax.swing.LookAndFeel class. UIManager's method setLookAndFeel takes the name of the LookAndFeel class and sets the default look-and-feel of the UIManager. The last line updates the component to the default look-and-feel.

18.17: JDeskTopPane & JInternalFrame

A JDeskTopPane (in package javax.swing) inherits from JLayeredPane, which inherits from JComponent. It manages its child windows JInternalFrame (in package javax.swing). JInternalFrame inherits from JComponent and provides many of the features of a JFrame.

Suppose the following code is in a class which inherits from JFrame:

   
   JDeskTopPane deskTop = new JDeskTopPane();
   getContentPane().add(deskTop);
   
   JInternalFrame internal = new JInternalFrame("Title", true, true, true, true);
   Container c1 = internal.getContentPane();
   c1.add(...);
   c1.add(...);
   
   deskTop.add(internal);

The four boolean arguments of JInternalFrame constructor are

  1. Whether the child window is resizable;
  2. closable;
  3. maximizable;
  4. minimizable