Graphical User Interfaces
Programming with Java’s Swing API
          February 4, 2003
   CMPS 109 ! Advanced Programming
Priorities
 Does your program do what it is supposed to?
   If the program doesn’t work, there’s no point to using it.
 Is the program’s use easy to understand for its
 intended audience?
   If the people you are writing the program for don’t understand how
   it works, they can’t use it.
 Does the program perform at an acceptable
 speed?
   If it takes forever to run, people will not want to use it.
Interfaces
 Interfaces are everywhere in programming
   Application Program Interface !API"
   Class interface
   Library interface
 User Interfaces !UIs" are how your program
 interacts with the outside world.
 Most UIs are bad.
   Programmers don’t have the training to create a good UI.
   Psychology is providing the framework for understanding what
   makes a good User Interface.
Graphical Interfaces
 Graphical User Interfaces !GUIs" provide the
 users with an easily understood metaphor for
 interacting with a computer.
 GUIs consist of “Windows” that are blocked
 off areas of the screen, and “Components” or
 “Widgets” within those Windows.
 Examples of Components:
   Labels, Buttons, Images, Text Entry boxes, Lists, Trees, Menus, etc.
AWT and Swing
 The Abstract Windowing Toolkit !AWT" was
 Java’s original GUI toolkit.
   It used “native” widgets.
   It was difficult to program.
   It did not support a wide range of widgets.
 Swing was introduced with Java 2 !the Java 1.2
 API"
   It only used native windows, all other widgets were drawn “by
   hand”.
   Swing supports a wider range of widgets, and is easily extended.
Java Swing
 Swing has its own
 “Look and Feel” that
 is distinct from the
 “native” look and
 feel of the systems it
 runs on.
    Many companies have
    developed their own
    Look and Feel so that
    users can’t see the
    difference.
A Small Sample
import java.awt.*;
import javax.swing.*;
class HelloButton {
    public static void main( String[] args )
    {
        JFrame frame = new JFrame( “Hello Button” );
        Container pane = frame.getContentPane();
        JButton hello = new JButton( “Hello, world!” );
        pane.add( hello );
        frame.pack();
        frame.show();
    }
}
What to import
import java.awt.*;
import javax.swing.*;
...
  You need to import both java.awt.* and
  javax.swing.* to get all the basic classes.
Creating a JFrame
...
   JFrame frame = new JFrame( “Hello Button” );
...
   Creating a JFrame gives you a “top level”
  container.
      “Top level” containers are backed by native UI components !usually
      Windows or Dialogs".
  The string passed to the constructor is the
  title of the window.
The Content Pane
...
   Container pane = frame.getContentPane();
...
  You can’t add components directly to a
  JFrame.
      JFrame uses different layers !panes" to support various Swing
      features !Drag and Drop, ToolTips, etc".
  Instead, you must add to the frame’s Content
  Pane.
      Call getContentPane!" to get the content pane.
Adding content
...
  JButton hello = new JButton( “Hello, world!” );
   pane.add( hello );
...
  Create another Swing component.
      In this case, a standard push%button is created with the label “Hello,
      World!”.
      This button doesn’t do anything when pushed.
  Call add() with the component as a parameter
  to add it to the frame’s content pane.
Resizing and showing
...
      frame.pack();
      frame.show();
...
      pack!" will resize the frame to the minimum
      size needed to display the items in the
      content pane.
      Calling show!" will show the JFrame.
         You must set the size of the frame !directly or with pack!"" before
         you show the frame.
Quitting your program?
 When you close the window, you might
 notice that your program does not quit.
 When the first Swing component is created, a
 new Thread is created also.
   Threads allow a single program to do two things “at the same time.”
   In Swing’s case, the new thread is created to track and capture
   events !mouse, keyboard, etc".
 We’ll cover how to handle quitting and
 threads in Swing a little later.
Swing Components
    Swing Provides the following Components:
Buttons:           Containers:         Lists:
      JButton             JPanel                  JList
     JCheckBox            JFrame                  JTree
    JRadioButton         JDialog                 JTable
Menus:             Miscellaneous:      Organizers:
     JMenuBar          JFileChooser         JSplitPane
       JMenu          JCollerChooser       JTabbedPane
    JMenuItem            JToolTip            JToolBar
Ranged Controls:   Scrolling:          Text:
      JSpinner            JScrollBar            JTextArea
       JSlider           JScrollPane            JTextField
    JProgressBar                                  JLabel
The Event Thread
 Threads are a way of separating the work that
 a program does into multiple execution paths.
   They are sometimes compared to mini%programs.
 In Swing, the Event thread is an infinite loop.
 You have to call System.exit(           0 );      to actually
 quit.
The Event Thread
 Each pass through the event loop, Swing
 looks for mouse movements, mouse button
 presses, keyboard presses, etc.
 If an event is found, Swing passes any
 appropriate data to the component most
 directly affected by the event.
   Keyboard events go to the component that has “focus”.
   Mouse events go to the component under the mouse !if any".
Listening for Events
 You can “listen” for events in components you
 create by adding “listeners”.
 Swing defines a number of listener interfaces:
   java.awt.event          javax.swing.event
     ActionListener           ChangeListener
     MouseListener           DocumentListener
   MouseMotionListener       TableModelListener
     WindowListener          TreeModelListener
      ItemListener
Listening for Events
 You can tell what kind of events a component
 can receive by looking for functions of the
 form addXYZListener(), and examining the
 type of listener the function expects as a
 parameter.
 addActionListener()  is used by a number of
 components and needs a parameter of
 ActionEventListener.
Event Listeners
 Any class can implement an event listener
 interface.
 Named inner classes are usually the best way
 to implement event listeners.
   Inner classes have direct access to the data stored in the outer class.
   You never have to wonder where the events are handled.
   Most event listeners are short functions !5 lines or less".
Event Listener Warnings
 Never use anonymous classes to implement an
 event listener.
 Do not try to do long processing in an event
 listener, or a function called by a listener.
 Do not try to share listeners between
 components.
A Sample Listener
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class HelloButton {
    public static void main( String[] args )
    {
        new HelloButton();
    }
    HelloButton()
    {
        JButton hello = new JButton( “Hello, world!” );
        hello.addActionListener( new HelloButtonListener() );
        JFrame frame = new JFrame( “Hello Button” );
        Container pane = frame.getContentPane();
        pane.add( hello );
        frame.pack();
        frame.show();
    }
A Sample Listener
      private class HelloButtonListener
          implements ActionListener
      {
          public void actionPerformed( ActionEvent e )
          {
              System.out.println( “The event was: “ + e );
          }
      }
 }
The event was:
java.awt.event.ActionEvent&ACTION_PERFORMED,cmd=Hello, world!' on
javax.swing.JButton&,0,0,141x27,layout=javax.swing.OverlayLayout,alignmentX=
0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource(CompoundBor
derUIResource@1d8ff06,flags=48,maximumSize=,minimumSize=,preferredSize=,
defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.Inset
sUIResource&top=2,left=14,bottom=2,right=14',paintBorder=true,paintFocus=tru
e,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,select
edIcon=,text=Hello, world!,defaultCapable=true'
Changes in the example
 The code to create the UI is now in the class
 constructor.
   Inner classes that are not static have to be created by class
   functions that are not static.
 The components that are added to the frame
 are created and configured before the frame is
 even created.
   Organizing the code to deal with only one component at a time
   makes it easier to read and change.
Adapters vs. Listeners
 Some listeners have many events they can
 listen for.
   MouseListener !5 events"
   WindowListener !7 events"
 Adapters are sometimes provided for these
 listeners.
   Implement the listener interface with empty functions.
   You can subclass the adapter if you don’t want to implement the
   entire listener.
   Just override the functions you want to work with.
Quitting Example
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class HelloButton {
    public static void main( String[] args )
    {
        new HelloButton();
    }
    HelloButton()
    {
        JButton hello = new JButton( “Hello, world!” );
        hello.addActionListener( new HelloButtonListener() );
        JFrame frame = new JFrame( “Hello Button” );
        frame.addWindowListener( new HelloButtonWindowListener() );
        frame.getContentPane().add( hello );
        frame.pack();
        frame.show();
    }
Quitting Example
    private class HelloButtonListener
        implements ActionListener
    {
        public void actionPerformed( ActionEvent e )
        {
            System.out.println( “The event was: “ + e );
        }
    }
    private class HelloButtonWindowListener
        extends WindowAdapter
    {
        public void windowClosed( WindowEvent e )
        {
            System.out.println( “Goodbye!” );
            System.exit( 0 );
        }
    }
}
Component Layout
 A Layout Manager determines where each
 component should be placed in the window
 or the container.
 The book has excellent examples for many of
 the common layout managers:
   FlowLayout places components in the window from left to right,
   like a word processor.
   GridLayout is like a table, all components are the same size.
   Border Layout splits the area into 5 predefined spaces like a
   compass.
JPanel and Nested
Containers
 JPanel is an empty component that does not
 have any visual representation.
 JPanels are used to split one container into
 smaller !more manageable" areas.
 Each JPanel has its own layout manager.
 You can assign a GridLayout to the JFrame,
 and put a JPanel with a BorderLayout in each
 cell.
Nested Container
Example
JPanelExample()
{
    JFrame frame = new JFrame( “JPanel Example” );
    frame.getContentPane().setLayout( new GridLayout( 2, 2 ) );
    for( int i = 0; i < 2; i ++ ) {
        for( int j = 0; j < 2; j++ ) {
            JPanel p = new JPanel();
            p.setLayout( new BorderLayout() );
            p.add( new JButton( “North” ), BorderLayout.NORTH );
            p.add( new JButton( “South” ), BorderLayout.SOUTH );
            p.add( new JButton( “East” ), BorderLayout.EAST );
            p.add( new JButton( “West” ), BorderLayout.WEST );
            p.add( new JButton( “Center” ), BorderLayout.CENTER );
            frame.getContentPane().add( p );
        }
    }
    frame.pack();
    frame.show();
}
Nested Container
    Example
BoxLayout
 BoxLayout is an easy to use layout manager
 that allows you to create complex
 containment schemes.
 It is more flexible than the other managers,
 but only slightly more complex than the
 FlowLayout.
 It requires you to use nested containers.
BoxLayout Example
BoxLayoutExample()
{
    JPanel p1 = new JPanel();
    p1.setLayout( new BoxLayout( p1, BoxLayout.X_AXIS ) );
    p1.add( Box.createHorizontalGlue() );
    p1.add( new JButton( “Right Aligned” ) );
    JPanel p2 = new JPanel();
    p2.setLayout( new BoxLayout( p2, BoxLayout.X_AXIS ) );
    p2.add( Box.createHorizontalGlue() );
    p2.add( new JButton( “Center Aligned” ) );
    p2.add( Box.createHorizontalGlue() );
    JFrame frame = new JFrame( “JPanel Example” );
    frame.getContentPane().setLayout(
        new BoxLayout( frame.getContentPane(), BoxLayout.Y_AXIS ) );
    frame.getContentPane().add( p1 );
    frame.getContentPane().add( Box.createVerticalStrut( 20 ) );
    frame.getContentPane().add( p2 );
    frame.pack();
    frame.show();
}
BoxLayout Example
Why BoxLayout is a
better layout
 You can set three size attributes of Swing
 Components: Minimum, Preferred, and
 Maximum
 Unlike most layout managers, BoxLayout
 respects the size attributes of its components.
 You get the a lot of flexibility with only a few
 functions.
Borders
 BorderFactory allows you to create borders
 for JComponent descendants !most of Swing".
   Call setBorder! BorderFactory.createXYZBorder!" ";
 Uses of Borders:
   Excellent for debugging layout issues when you have nested JPanels
   and resize problems.
   Empty borders can be used to create extra spacing around
   components where nothing is drawn.
   Compound borders can be used to stack borders on top of each
   other !for example, an empty area of 12 pixels on all sides, and then
   an etched border, or another compound border".
Text Input with Swing
 JTextField is a simple, single line text entry
 area.
 JTextArea allows multi%line input, but is much
 more complex.
Text Input Example
private JTextField textField;
private JLabel echoLabel;
TextFieldExample() {
    textField = new JTextField( “Enter text here...” );
    echoLabel = new JLabel( “...it will echo here.” );
    JFrame frame = new JFrame( “Text Field Example” );
    frame.getContentPane().setLayout( new GridLayout( 2, 1 ) );
    frame.getContentPane().add( textField );
    frame.getContentPane().add( echoLabel );
    frame.pack();
    frame.show();
}
private class TextFieldListener
    implements ActionListener
{
    public void actionPerformed( ActionEvent e ) {
        echoLabel.setText( textField.getText() );
    }
}
JOptionPane
 JOptionPane allows you to create simple
 dialog boxes:
   showConfirmDialog()   presents the user with up to three choices: Yes,
   No, and Cancel.
   showInputDialog()   gives the user a question and a text field to
   enter input.
   showMessageDialog()    is great for reporting errors !invalid input"
   and simple messages.
 Each function has multiple versions, with
 varying degrees of configuration.
Menu bars and Menus
 JFrame and JDialog both provide the
 setJMenuBar() function to specify the menu bar
 for that window.
 JMenuBar provides an add() function to add
 JMenus.
 JMenu provides an add() function for
 JMenuItems, Strings, and Components.
 JMenus can be added to other JMenus.
Menu Bar Example
private JFrame mbeFrame;
MenuBarExample() {
    mbeFrame = new JFrame( “Text Field Example” );
    mbeFrame.setJMenuBar( makeMenuBar() );
    mbeFrame.getContentPane().add( new JLabel( “Other Stuff Here.” ) );
    mbeFrame.pack();
    mbeFrame.show();
}
private class QuitItemListener
    implements ActionListener
{
    public void actionPerformed( ActionEvent e ) {
        if( JOptionPane.showConfirmDialog( mbeFrame,
            “Do you want to quit?”, “Confirm Quit”,
            JOptionPane.YES_NO_OPTION ) == JOptionPane.YES_OPTION ) {
            System.exit( 0 );
        }
    }
}
Menu Bar Example
private JMenuBar makeMenuBar() {
    JMenuItem quitItem = new JMenuItem( “Quit” );
    quitItem.addActionListener( new QuitItemListener() );
    JMenu fileMenu = new JMenu( “File” );
    fileMenu.add( new JMenuItem( “Item 1” ) );
    fileMenu.add( “Item 2” );
    fileMenu.addSeparator();
    JMenu fontMenu = new JMenu( “Font” );
    fontMenu.add( “Times” );
    fontMenu.add( “Courier” );
    fontMenu.add( “Script” );
    JMenu editMenu = new JMenu( “Edit” );
    editMenu.add( “Undo” );
    editMenu.addSeparator();
    editMenu.add( fontMenu );
    JMenuBar mbar = new JMenuBar();
    mbar.add( fileMenu );
    mbar.add( editMenu );
    return( mbar );
}
Demonstrations and
   Questions