Chapter 20 – Graphical User Interfaces
Chapter Goals
• To use layout managers to arrange user‑interface components in a
container
• To use text components to capture and display text in a graphical
application
• To become familiar with common user-interface components, such as
radio buttons, check boxes, and menus
• To browse the Java documentation effectively
Layout Management
• Build user interface by adding components into
containers.
• Use a layout manager to place the components.
• JFrame uses Flow layout by default.
Border Layout
Components are placed toward areas of a container NORTH, EAST, SOUTH,
WEST, or CENTER.
Specify one when adding components:
panel.setLayout(new BorderLayout());
panel.add(component, BorderLayout.NORTH);
Figure 1 Components Expand to Fill Space in the Border Layout
Grid Layout
Components are placed in boxes in a simple table
arrangement. Specify the size (rows then columns) of the grid.
Then add components which will be placed from the upper
left, across, then down.
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 3));
buttonPanel.add(button7);
buttonPanel.add(button8);
buttonPanel.add(button9);
buttonPanel.add(button4);
. . .
Figure 2 The Grid
Layout
Achieving Complex Layouts
Create complex layouts by nesting panels.
Give each panel an appropriate layout manager.
Panels have invisible borders, so you can use as many
panels as you need to organize components.
JPanel keypadPanel = new JPanel();
keypadPanel.setLayout(new BorderLayout());
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4, 3));
buttonPanel.add(button7);
buttonPanel.add(button8);
// . . .
keypadPanel.add(buttonPanel, BorderLayout.CENTER);
JLabel display = new JLabel("0");
keypadPanel.add(display, BorderLayout.NORTH);
Figure 3 Nesting
Using Inheritance
Use inheritance for complex frames. Design
a subclass of JFrame:
Store components as instance variables. Initialize
them in the constructor of your subclass.
Easy to add helper methods to organize code.
public class FilledFrame extends JFrame
{
// Use instance variables for components private JButton button;
private JLabel label;
private static final int FRAME_WIDTH = 300;
private static final int FRAME_HEIGHT = 100;
public FilledFrame()
{
// Now we can use a helper method
createComponents();
// It is a good idea to set the size in the frame constructor
setSize(FRAME_WIDTH, FRAME_HEIGHT);
}
private void createComponents()
{ button = new JButton("Click
me!");
label = new JLabel("Hello, World!");
JPanel panel = new JPanel();
panel.add(label);
panel.add(button);
add(panel);
}
}
Using Inheritance
FillledFrameViewer2 main
method:
public class FilledFrameViewer2
{
public static void main(String[] args)
{
JFrame frame = new FilledFrame();
frame.setTitle("A frame with two components");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Common Error 20.1
You add components like buttons or
labels:
panel.add(button);
panel.add(label);
panel.add(carComponent);
Default size for component is 0 by 0 pixels so car
component will not be visible.
Use setPreferredSize:
carComponent.setPreferredSize(new Dimension(CAR_COMPONENT_WIDTH, CAR_COMPONENT_HEIGHT));
Only needed for painted
components.
Processing Text Input
Dialog boxes allows for user input.
Popping up a separate dialog box for each input is not a natural
user interface.
Most graphical programs collect text input through text fields.
The JTextField class provides a text field.
Specify the width for the text field.
If the user exceeds this width, text will ‘scroll’ left.
final int FIELD_WIDTH = 10;
final JTextField rateField = new JTextField(FIELD_WIDTH);
Figure 4 An Application with a Text
Field
Add a Label and a Button
Add a label to describe the
field:
JLabel rateLabel = new JLabel("Interest Rate: ");
Add a button for user to indicate input is complete.
actionPerformed method can use getText to get input
as a
String.
Convert to a numeric value if used for
calculations.
class AddInterestListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
double rate = Double.parseDouble(rateField.getText());
double interest = balance * rate / 100;
balance = balance + interest;
resultLabel.setText("Balance: " + balance);
}
}
section_2_1/InvestmentFrame2.java
1 import java.awt.event.ActionEvent;
2 import
java.awt.event.ActionListener;
3 import javax.swing.JButton;
4 import javax.swing.JFrame;
5 import javax.swing.JLabel;
6 import javax.swing.JPanel;
7 import javax.swing.JTextField;
8 /**
9 A frame that shows the growth of an investment with variable interest.
10 */
11 public class InvestmentFrame2 extends JFrame
12 {
13 private static final int FRAME_WIDTH = 450;
14 private static final int FRAME_HEIGHT =
15 100;
16 private static final double DEFAULT_RATE = 5;
17 private static final double INITIAL_BALANCE =
18 1000;
19 private JLabel rateLabel;
20 private JTextField
21 rateField; private JButton
22 button; private JLabel
23 resultLabel; private double
24 balance;
25 public InvestmentFrame2()
26 {
27 balance = INITIAL_BALANCE;
28
29 resultLabel = new JLabel("Balance: " +
30 balance);
31 createTextField()
32 ;
33 createButton();
Text Areas
Create multi-line text areas with a JTextArea
object. Set the size in rows and columns.
final int ROWS = 10; // Lines of text
final int COLUMNS = 30; // Characters in each row
JTextArea textArea = new JTextArea(ROWS, COLUMNS);
Use the setText method to set the text of a text field or
text area.
textArea.append(balance + "\n");
Can use the text area for display purposes
only.
textArea.setEditable(false);
TextComponent Class
JTextField and JTextArea are subclasses of
JTextComponent.
setText and setEditable are declared in the
JTextComponent class.
Inherited by JTextField and JTextArea.
append method is only declared in JTextArea.
Figure 5 A Part of the Hierarchy of Swing User-Interface Components
Scrolling
To add scroll bars, use
JScrollPane:
JScrollPane scrollPane = new JScrollPane(textArea);
Figure 6 The Investment Application with a Text Area Inside Scroll Bars
section_2_2/InvestmentFrame3.java
1 import java.awt.event.ActionEvent;
2 import
java.awt.event.ActionListener;
3 import javax.swing.JButton;
4 import javax.swing.JFrame;
5 import javax.swing.JLabel;
6 import javax.swing.JPanel;
7 import javax.swing.JScrollPane;
8 import javax.swing.JTextArea;
9 import javax.swing.JTextField;
10 /**
11 A frame that shows the growth of an investment with variable interest,
12 using a text area.
13 */
14 public class InvestmentFrame3 extends JFrame
15 {
16 private static final int FRAME_WIDTH = 400;
17 private static final int FRAME_HEIGHT =
18 250;
19 private static final int AREA_ROWS = 10;
20 private static final int AREA_COLUMNS =
21 30;
22 private static final double DEFAULT_RATE = 5;
23 private static final double INITIAL_BALANCE =
24 1000;
25 private JLabel rateLabel;
26 private JTextField
27 rateField; private JButton
28 button; private JTextArea
29 resultArea; private double
30 balance;
31 public InvestmentFrame3()
32
C hoices
GUI components for selections:
Radio Buttons For a small set of mutually exclusive choices.
Check Boxes For a binary choice.
Combo Boxes For a large set of choices.
Radio Buttons
Only one button in a set can be selected.
Selecting a button clears previous
selection.
In an old fashioned radio, pushing down one station button released the others.
Create each button individually.
Add all buttons in the set to a ButtonGroup
object:
JRadioButton smallButton = new JRadioButton("Small");
JRadioButton mediumButton = new JRadioButton("Medium");
JRadioButton largeButton = new JRadioButton("Large");
ButtonGroup group = new ButtonGroup();
group.add(smallButton);
group.add(mediumButton);
group.add(largeButton);
Use isSelected to find out whether a button is selected,
like:
if (largeButton.isSelected()) { size = LARGE_SIZE; }
Radio Button Panels
Use a panel for each set of radio buttons.
The default border for a panel is invisible (no
border). You can add a border to a panel to make it
visible.
Also
JPaneladd
panel =anew
title.
JPanel();
panel.add(smallButton);
panel.add(mediumButton);
panel.add(largeButton);
panel.setBorder(new
TitledBorder(new
EtchedBorder(),"Size"));
User Interface Components
Figure 7 A Combo Box, Check Boxes, and Radio
Buttons
Check Boxes
A check box has two states: checked and
unchecked. Use for choices that are not mutually
exclusive.
For example in Figure 7, text may be Italic,
Bold, both or neither.
Because check box settings do not exclude each other, you
do not need to place a set of check boxes inside a button
group.
Radio buttons are round and have a black dot when selected.
Check boxes are square and have a check mark when
JCheckBox italicCheckBox = new JCheckBox("Italic");
selected. Construct a text box:
Use isSelected to find out whether a check box is
selected.
Combo Boxes
A combo box is a combination of a list and a text field.
Clicking the arrow to the right of the text field opens the list
of selections.
Use a combo box for a large set of choices.
Use when radio buttons would take up too much
space. It can be either:
Closed (shows one selection).
Open, showing multiple selections.
It can also be editable:
Type a selection into a blank line.
facenameCombo.setEditable();
Adding and Selecting Items
Add text ‘items’ to a combo box that will show in the
list:
JComboBox facenameCombo = new JComboBox();
facenameCombo.addItem("Serif");
facenameCombo.addItem("SansSerif");
. . .
Use the getSelectedItem method to return the selected
item (as an Object).
Combo boxes can store other objects in addition to strings, so
casting to a string may be required:
String selectedString = (String) facenameCombo.getSelectedItem();
Figure 8 An Open Combo
Box
Handling Input Events
Radio buttons, check boxes, and combo boxes generate an
ActionEvent when selected.
In FontViewer program, listener gets all events.
Simply check the state of each component using isSelected
and getSelectedItem methods.
Then redraw the label with the new font.
Font Vi ewer
Figure 9 The Components of the Font
Frame
section_3/FontViewer.java
1 import javax.swing.JFrame;
2
3 /**
4 This program allows the user to view font effects.
5 */
6 public class FontViewer
7 {
8 public static void main(String[] args)
9 {
10 JFrame frame = new FontFrame();
11 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
;
12 frame.setTitle("FontViewer");
13 frame.setVisible(true);
14 }
15 }
section_3/FontFrame.java
1 import java.awt.BorderLayout;
2 import java.awt.Font;
3 import java.awt.GridLayout;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import javax.swing.ButtonGroup;
7 import javax.swing.JButton;
8 import javax.swing.JCheckBox;
9 import javax.swing.JComboBox;
10 import javax.swing.JFrame;
11 import javax.swing.JLabel;
12 import javax.swing.JPanel;
13 import javax.swing.JRadioButton;
14 import
javax.swing.border.EtchedBorder;
15 import
/**
javax.swing.border.TitledBorder;
16 This frame contains a text sample and a control panel
17 to change the font of the text.
18 */
19 public class FontFrame extends JFrame
20 {
21 private static final int FRAME_WIDTH = 300;
22 private static final int FRAME_HEIGHT =
23 400;
24 private JLabel label;
25 private JCheckBox italicCheckBox;
26 private JCheckBox boldCheckBox;
27 private JRadioButton smallButton;
28 private JRadioButton
29 mediumButton; private
30 JRadioButton largeButton;
31 private JComboBox facenameCombo;
32 private ActionListener listener;
33 /**
34 Constructs the frame.
Designing a User Interface
Make a sketch of the component layout. Draw all the
buttons, labels, text fields, and borders on a sheet of graph
paper.
Find groupings of adjacent components with the same
layout. Look for adjacent components top to bottom or left
to right.
Identify layouts for each group:
For horizontal components, use flow layout.
For vertical components, use a grid layout with one column.
Group the groups together:
Look at each group as one blob.
Group the blobs together into larger groups.
Designing a User Interface
Write the code to generate the
layout.
JPanel radioButtonPanel = new JPanel();
radioButtonPanel.setLayout(new GridLayout(3, 1));
radioButton.setBorder(new TitledBorder(new EtchedBorder(), "Size"));
radioButtonPanel.add(smallButton);
radioButtonPanel.add(mediumButton);
radioButtonPanel.add(largeButton);
JPanel checkBoxPanel = new JPanel();
checkBoxPanel.setLayout(new GridLayout(2, 1));
checkBoxPanel.add(pepperoniButton());
checkBoxPanel.add(anchoviesButton());
JPanel pricePanel = new JPanel();
// Uses FlowLayout by default
pricePanel.add(new JLabel("Your Price:"));
pricePanel.add(priceTextField);
JPanel centerPanel = new JPanel(); // Uses
FlowLayout centerPanel.add(radioButtonPanel);
centerPanel.add(checkBoxPanel);
// Frame uses BorderLayout by default
add(centerPanel, BorderLayout.CENTER);
add(pricePanel, BorderLayout.SOUTH);
Use a GUI Builder
A GUI builder reduces the tedious work:
Drag and drop components onto a panel.
Customize fonts, colors, text, and so on with a dialog box.
Define event handlers by picking the event to process and provide the
code snippet for the listener method.
Powerful layout manager GroupLayout designed to be
used by GUI builders.
Use a GUI Builder
Try the free NetBeans development environment, available
from
http://netbeans.org.
Figure 10 A GUI
Builder
M enus
A frame can contain a menu
bar. Menu bar contains menus.
Menu contains submenus and
menu items.
Menu items can be added to each menu or
submenu.
public class First,
MyFrameadd theJFrame
extends menu bar to the frame:
{
public MyFrame()
{
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
. . .
}
. . .
}
M enus
Figure 11 Pull-Down
Menus
M enus
Add menus to the menu
bar:
JMenu fileMenu = new JMenu("File");
JMenu fontMenu = new
JMenu("Font");
menuBar.add(fileMenu);
menuBar.add(fontMenu);
Add menu items and
subitems:
JMenuItem exitItem = new JMenuItem("Exit");
fileMenu.add(exitItem);
JMenu styleMenu = new JMenu("Style");
fontMenu.add(styleMenu); // A
submenu
Add a listener to each menu item (not to menus or menu
bar):
ActionListener listener = new ExitItemListener();
exitItem.addActionListener(listener);
M enus
Use a separate method for each menu or set of related
menus:
public JMenu createFaceMenu()
{
JMenu menu = new JMenu("Face");
menu.add(createFaceItem("Serif"));
menu.add(createFaceItem("SansSerif"));
menu.add(createFaceItem("Monospaced"));
return menu;
}
M enus
createFaceItem method needs to set the font face:
Set the current face name.
Make the new font from the current face, size, and style, and apply it to
label.
Create a FaceItemListener class to listen for face
item name actions:
class FaceItemListener implements ActionListener
{
private String name;
public FaceItemListener(String newName) { name = newName; }
public void actionPerformed(ActionEvent event)
{
faceName = name; // Sets an instance variable of the frame class
setLabelFont();
}
}
Install a listener object with the appropriate
name:
public JMenuItem createFaceItem(String name)
{
JMenuItem item = new JMenuItem(name);
ActionListener listener = new FaceItemListener(name);
item.addActionListener(listener);
return item;
}
M enus
Better to make a local inner class in the createFaceItem
method.
actionPerformed method can access the name
parameter variable directly (rather than passing it).
public JMenuItem createFaceItem(final String name)
// Final variables can be accessed from an inner class method
{
class FaceItemListener implements ActionListener
// A local inner class
{
public void actionPerformed(ActionEvent event)
{
facename = name; // Accesses the local variable name setLabelFont();
}
}
JMenuItem item = new JMenuItem(name);
ActionListener listener = new FaceItemListener(name);
item.addActionListener(listener);
return item;
}
Same strategy used for the createSizeItem
and
createStyleItem methods.
section_4/FontViewer2.java
1 import javax.swing.JFrame;
2
3 /**
4 This program uses a menu to display font effects.
5 */
6 public class FontViewer2
7 {
8 public static void main(String[] args)
9 {
10 JFrame frame = new FontFrame2();
11 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
;
12 frame.setTitle("FontViewer");
13 frame.setVisible(true);
14 }
15 }
section_4/FontFrame2.java
1 import java.awt.BorderLayout;
2 import java.awt.Font;
3 import java.awt.event.ActionEvent;
4 import
java.awt.event.ActionListener;
5 import javax.swing.JFrame;
6 import javax.swing.JLabel;
7 import javax.swing.JMenu;
8 import javax.swing.JMenuBar;
9 import javax.swing.JMenuItem;
10 /**
11 This frame has a menu with commands to change the font
12 of a text sample.
13 */
14 public class FontFrame2 extends JFrame
15 {
16 private static final int FRAME_WIDTH = 300;
17 private static final int FRAME_HEIGHT =
18 400;
19 private JLabel label;
20 private String
21 facename; private int
22 fontstyle; private int
23 fontsize;
24 /**
25 Constructs the frame.
26 */
27 public FontFrame2()
28 {
29 // Construct text sample
30 label = new JLabel("Big Java");
31 add(label,
32 BorderLayout.CENTER);
33 // Construct menu
34 JMenuBar menuBar = new
35 JMenuBar();
Exploring the Swing Documentation
Consider an example application: Use sliders to set colors
of red, green and blue.
Swing user-interface toolkit provides a large set of
components. How do you know if there is a slider?
Buy a book that illustrates all Swing components.
Run the sample Swing application included in the Java Development Kit.
Look at the names of all of the classes that start with J and decide that
JSlider may be a good candidate.
Figure 12 A Color Viewer with
Sliders
JSlider Documentation and Use
Now ask some questions about JSlider:
How do I construct a JSlider?
How can I get notified when the user has moved it? How can I
tell to which value the user has set it?
Unfortunately, documentation for JSlider is
voluminous:
Over 50 methods in the JSlider class. Over 250
inherited methods.
Some of the method descriptions look downright
scary.
Concentrate on what you will need:
Constructors. Event
handling. Get the value.
SwingSet Demo
Figure 13 The SwingSet
JSlider Constructor Choice
We want a slider value between 0 and 255.
Find a constructor that will do what we
need:
public JSlider()
Creates a horizontal slider with the range 0 to 100 and an
initial value of 50.
public JSlider(BoundedRangeModel brm)
Creates a horizontal slider using the
specified
BoundedRangeModel.
public JSlider(int min, int max, int value)
Creates a horizontal slider using the specified min, max,
and value.
JSlider Event Handling
Goal: Add a change event listener to each
slider. There is no addActionListener
method.
Possible
public voidoption:
addChangeListener(ChangeListener l)
Looks like AddActionListener calls
stateChanged(ChangeEvent e) whenever the user
adjusts the slider.
Figure 14 A Mysterious Method Description from the API Documentation
JSlider Event Handling
So the plan is:
Setup three sliders and one ChangeListener object.
Use AddChangeListener, passing our ChangeListener to
each slider.
In the stateChanged method, check the values of the colors and
repaint the panel.
Figure 15 The Components of the Color Viewer
Frame
section_5/ColorViewer.java
1 import javax.swing.JFrame;
2
3 public class ColorViewer
4 {
5 public static void main(String[] args)
6 {
7 JFrame frame = new ColorFrame();
8 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
;
9 frame.setVisible(true);
10 }
11 }
section_5/ColorFrame.java
1 import java.awt.BorderLayout;
2 import java.awt.Color;
3 import java.awt.GridLayout;
4 import javax.swing.JFrame;
5 import javax.swing.JLabel;
6 import javax.swing.JPanel;
7 import javax.swing.JSlider;
8 import
javax.swing.event.ChangeListener;
9 import javax.swing.event.ChangeEvent;
10 public class ColorFrame extends JFrame
11 {
12 private static final int FRAME_WIDTH = 300;
13 private static final int FRAME_HEIGHT =
14 400;
15 private JPanel colorPanel;
16 private JSlider redSlider;
17 private JSlider
18 greenSlider; private
19 JSlider blueSlider;
20 public ColorFrame()
21 {
22 colorPanel = new JPanel();
23
24 add(colorPanel,
25 BorderLayout.CENTER);
26 createControlPanel();
27 setSampleColor();
28 } setSize(FRAME_WIDTH, FRAME_HEIGHT);
29
30 class ColorListener implements ChangeListener
31 {
32 public void stateChanged(ChangeEvent
33 event)
34 {
35 setSampleColor();