Transcript Chapter 11
Building Graphical User
Interfaces
5.0
Overview
•
•
•
•
Constructing GUIs
Interface components
GUI layout
Event handling
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
2
GUI Principles
• Components: GUI building blocks
– Buttons, menus, sliders, etc
• Layout: arranging components to
form a usable GUI
– Using layout managers
• Event handling: reacting to user input
– Button presses, menu selections, etc
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
3
GUI libraries
AWT and Swing
AWT (Abstract Window Toolkit): original Java API
Swing: use some AWT, replace some AWT, and
adds many new classes
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
4
Elements of a frame
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
5
Creating a frame
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ImageViewer
{
private JFrame frame;
// import 3 packages
// completely for GUI
// Swing applications
// variable holds the frame
/**
* Create an ImageViewer show it on screen.
*/
public ImageViewer()
{
makeFrame();
// handling GUI construction
}
// rest of class omitted.
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
6
The content pane
/**
* Create the Swing frame and its content.
*/
private void makeFrame()
{
frame = new JFrame("ImageViewer");
// creates new frame
Container contentPane = frame.getContentPane();
// gets Content Pane
JLabel label = new JLabel(”I am a label. I can display some text.");
contentPane.add(label);
frame.pack();
frame.setVisible(true);
// label created and added to Content Pane
// arranges frame components & resizes
// makes frame visible after construction
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
7
Adding menus
• JMenuBar
– Displayed below the title
– Contains the menus
• JMenu
– (e.g. File) Contains the menu items
• JMenuItem
– (e.g. Open) Individual items
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
8
The menu bar
private void makeMenuBar(JFrame frame)
{
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu fileMenu = new JMenu("File"); // create File menu
menubar.add(fileMenu);
// add to menubar
JMenuItem openItem = new JMenuItem("Open"); // create Open item
fileMenu.add(openItem);
// add to File menu
JMenuItem quitItem = new JMenuItem("Quit"); // create Quit item
fileMenu.add(quitItem);
// add to File menu
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
9
Event handling
• Events correspond to user interactions with
components
• Components are associated with different
event types
– Frames are associated with WindowEvent
• i.e.
frame closed or iconified
– Menus are associated with ActionEvent
• i.e.
button clicked or menu item selected
– Mouses are associated with MouseEvent
• i.e.
mouse clicked or moved
• Objects can be notified when event occurs
– Such objects are called listeners
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
10
Centralized event receipt
• A single object handles all events
– Implements the ActionListener interface
– Defines an actionPerformed method
• It registers as a listener with each
component
– item.addActionListener(this)
• It has to work out which component has
dispatched the event
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
11
ActionListener
public interface ActionListener
{
public void actionPerformed(ActionEvent e);
}
Makes ImageViewer object a single listener to all menu events:
public class ImageViewer implements ActionListener
{
…
public void actionPerformed(ActionEvent e)
{
String command = e.getActionCommand();
if(command.equals("Open")) {
…
}
else if (command.equals("Quit")) {
…
}
…
}
…
private void makeMenuBar(Jframe frame)
{
…
openItem.addActionListener(this);
…
}
}
12
public class ImageViewer implements ActionListener
{
// ensures object is a subtype of ActionListener
…
public void actionPerformed(ActionEvent e)
{
String command = e.getActionCommand();
if(command.equals("Open")) {
…
}
else if (command.equals("Quit")) {
…
}
…
}
…
private void makeMenuBar(Jframe frame)
{
…
openItem.addActionListener(this);
…
// registers ImageViewer object as
}
//
a listener for the menu item
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
13
Registering as a listener
JMenuItem openItem = new JMenuItem(“Open”);
openItem.addActionListener(this);
• Menu item openItem is created
– new JMenuItem(“Open”)
• Current object ImageViewer is registered as an
action listener by passing this
– addActionListener(this)
public void actionPerformed(ActionEvent e)
• Activated menu item within a registered
listener object will:
– invoke own actionPerformed method
– menu item passes parameter ActionEvent e
°event details (i.e. time, key states, command string, …)
°command string identifies component that caused event
> event.getActionCommand() retrieves command string
14
Centralized event handling
• The approach works
• It is used, so you should be aware of it
• However …
– It does not scale well
– Identifying components by their text is fragile
– Maintenance and expandability difficult
• An alternative approach is preferred
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
15
Inner classes
public class Enclosing
{
…
private class Inner
{
…
}
}
• Class definitions may be nested
• Instances of inner class are localized inside
the enclosing class
– inner class can only exist within enclosing instance
• Instances of inner class have access to
private fields and methods of the enclosing
class
– tightly coupled inner class considered part of the
enclosing class (just like enclosing class’s methods)
16
actionPerformed method
class ImageViewer
{ … // style guides inner classes written at the end
class OpenActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// perform open action
}
}
class QuitActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
// perform quit action
}
}
}
ImageView no longer implements ActionListener &
actionPerformed is now implemented by inner classes
JMenuItem openItem = new JMenuItem(“Open”);
openItem.addActionListener(new OpenActionListener());
…
JMenuItem quitItem = new JMenuItem(“Quit”);
quitItem.addActionListener(new QuitActionListener());
17
Now create inner class instances the same way as any other class
actionPerformed method
JMenuItem openItem = new JMenuItem(“Open”);
openItem.addActionListener(new OpenActionListener());
…
JMenuItem quitItem = new JMenuItem(“Quit”);
quitItem.addActionListener(new QuitActionListener());
• Separate listener object for each possible event
• Each listener listens to only one single event type
• Each listener has its own actionPerformed method
– specific handling code for that event only
– makes full use of enclosing class’s private fields &
methods
Only menu items have a reference to the listener object!
Only a single object created from the specialized inner class!
Listener objects NOT stored in variables … Anonymous Objects
18
Anonymous inner classes
• Obey the rules of inner classes
• Uses inner class exactly once to create a
single, unnamed instance of the object
• Same as defining separate named classes for
the listeners, but NO class name is required
• Listener methods are now closer to the
listener registration of the menu item
• Anonymous class has access to fields &
methods of the enclosing class
• Also, access to local variables & parameters
of method that the class is defined inside of
– BUT, local variables must be declared FINAL
• Uses a special syntax
19
Anonymous class elements
Anonymous object creation
openItem.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
openFile();
}
}
);
Class definition
Actual parameter
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
20
Anonymous action listener
JMenuItem openItem = new JMenuItem("Open");
openItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {openFile();}
});
Syntactical shortcut in one statement to:
• Define unnamed class with its superclass type
– body of class between the outer braces { }
– includes implementation for its abstract methods
°method definition and {action body} if event occurs
• Create an object of the anonymous class
– using new to create the single instance
• Pass object to menu item’s addActionListener
– in the (parameter) to register the object as an
action listener for the menu item … where
°openFile( ) of enclosing class is invoked when activated
21
BlueJ Scope coloring
• Green = class
• Yellow = method definition
•
= method body
22
Anonymous inner classes
• Cohesion
– creates separate custom-made action listeners
for each individual menu item
– directly calls method implementing the
corresponding function for the even
• Extendability
– removed central actionPerformed method which
implemented functions for all the menu items
– adding additional menu items is localized
• Harder to read
– use only for very short classes
• Often used when only 1 instance of the
implementation is required
– associated actions unique to that particular item
– instance always referred to via its supertype
°less need for a name … hence it is anonymous
23
Exit on window close
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
WindowAdapter provides a no-operation
implementation of the WindowListener
interface. It then allows implementation of
methods for only the events you care about.
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
24
The imageviewer project
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
25
Image processing
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
26
Class responsibilities
• ImageViewer
– Sets up the GUI structure
• ImageFileManager
– Static methods for image file loading and
saving
• ImagePanel
– Displays the image within the GUI
• OFImage
– Models a 2D image
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
27
Class OFImage
• Custom format representing an image
in memory as a 2D array of pixels
• Our subclass of BufferedImage
– from package java.awt.image
– gives necessary functionality except
set/get pixel using a Color object
• Important methods:
– read/modify pixels: getPixel,
setPixel
– find image size: getWidth, getHeight
• Each pixel has a color
– represented by java.awt.Color
• Treat like a library class
28
Class ImageFileManager
• Offers 3 methods:
– one reads a named image file from disk
and return it as an OFImage
– one writes an OFImage file to disk
– one opens a file-chooser dialog for user to
select an image to open
• Methods can:
– read files in standard JPEG & PNG formats
– write files in JPEG format
• Done using standard Java image I/O
methods from ImageIO class:
– package javax.imageio
29
Class ImagePanel
• Implements custom-made Swing
components to display the image
– custom components easily created with a
subclass of an existing component
– then, inserted into a Swing container and
displayed in our GUI like another
component
• ImagePanel is a subclass of JComponent
– method setImage takes OFImage as a
parameter to display any given OFImage
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
30
Adding an ImagePanel
public class ImageViewer
{
private JFrame frame;
private ImagePanel imagePanel;
…
private void makeFrame()
{
Container contentPane = frame.getContentPane();
imagePanel = new ImagePanel();
contentPane.add(imagePanel);
}
…
}
In makeFrame, create & add ImagePanel
component instead of previous JLabel
– instance of ImagePanel object stored in
a field for access later
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
31
Loading an image
public class ImageViewer
{
private JFrame frame;
private ImagePanel imagePanel;
…
private void openFile()
{
File selectedFile = …;
OFImage image =
ImageFileManager.loadImage(selectedFile);
imagePanel.setImage(image);
frame.pack();
}
…
}
Now openFile actually opens & displays an
image file using our image-processing classes
– ImageFileManager can select & open image
– ImagePanel can display that image
– frame.pack necessary with image size change
• recalculates frame layout and redraws frame
32
Layout managers
• Swing uses layout managers to arrange
the layout of components in a GUI
– each Container (i.e. content pane) has an
associated layout manager to take care of
arranging the components within itself
• Manage limited space for competing
components
– FlowLayout, BorderLayout,
GridLayout, BoxLayout,
GridBagLayout
• Each imposes its own style
– components are positioned differently
– available space distributed differently
33
FlowLayout
• Arranges all components left to right
• Centers horizontally
– if there is not enough horizontal space,
it wraps around to a second line
• Leaves components its preferred size
• Thus, NO spare space around
components if window is resized
34
BorderLayout
• Places up to 5 components in arranged pattern
– space distributed (unevenly) between components
• Each of these positions may be empty (<=5)
• No leftover space if window is resized
–
–
–
–
–
CENTER(center) = stretches in both height & width
NORTH (top) = keeps height & stretches in width
SOUTH (bottom) =
“
EAST (right) = stretches in height & keeps width
WEST (left) =
“
35
GridLayout
• Lay out components in an evenly spaced grid
– specified number of rows & columns
• All components always kept the same size
• Useful to keep buttons the same width
– JButton width initially determined by text on button
– button insertion into GridLayout results in ALL
buttons resized to width of the widest button
• Odd number of equal-sized grid components
– may result in spare space
36
BoxLayout
NOTE: No component resizing
•
•
•
•
Lay out components vertically or horizontally
Components are not resized
Layout will not wrap when resized
Nesting multiple BoxLayouts inside each other
– sophisticated 2-dimensionally aligned layouts
37
Nested containers
• Sophisticated layouts by nesting containers
– many Swing components are containers
– such as JFrame, JPanel, JWindow, …
• Containers may contain multiple components
– such as JPanel, JLabel, JButton, …
• JPanel container is most often used
– insert as a component in the frame’s content pane
– with more components laid out inside the JPanel
• buttons, labels, etc…
– each may have its own layout
• Container & layout manager work together
– container holds components
– layout manager decides exact arrangement
• Each container has its own layout manager
– BorderLayout, FlowLayout, GridLayout, BoxLayout, …
– each container has different default (if not set)
• JFrame = BorderLayout
• JPanel = FlowLayout
38
Nested containers
Content Pane (BorderLayout)
CENTER
– ImagePanel (user-defined in ImageViewer)
Interface arrangement
similar to the
BlueJ Main Window
NORTH
– JPanel (FlowLayout - horizontal)
• 4 toolbar button components
SOUTH
– JPanel (FlowLayout - horizontal)
• 3 object components
WEST
– JPanel (FlowLayout - vertical)
• JPanel (GridLayout - 1 column)
°4 button components
EAST
– unused
39
ImageViewer example
Content Pane (BorderLayout)
CENTER
– ImagePanel (user-defined in ImageViewer)
NORTH
– JLabel: image filename
SOUTH
– JLabel: status text
WEST
– unused
EAST
– unused
40
ImageViewer example
• setLayout used on contentPane to set layout manager
– layout manager itself is the object
– create instance of BorderLayout to pass to setLayout
• Container component with BorderLayout set differently
– overloaded add method has 2nd parameter with public
constant defined in the BorderLayout class
°NORTH, SOUTH, EAST, WEST or CENTER
41
Glue, Rigid Areas & Struts
NO spacing between buttons
• Invisible components used as spacing
• Available from the Box class
• Glue: fills available space
– Component createHorizontalGlue()
– Component createVerticalGlue()
Glue
stretchy & expandable
• Rigid Area: fixed size (horizontal AND vertical)
– Component createRigidArea(new Dimension(20,0)));
Rigid fixed-sized space between buttons
• Strut: fixed size (horizontal OR vertical - 1 direction)
– Component createHorizontalStrut(int width)
– Component createVerticalStrut(int height)
42
Dialogs
Pop-up informational display
• Modal dialogs block all other
interaction
– Forces a response from the user
• Non-modal dialogs allow other
interaction
– This is sometimes desirable
– May be difficult to avoid inconsistencies
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
43
JOptionPane standard dialogs
• Message dialog
– Message text
– OK button to confirm
• Confirm dialog
– Asks a question
– Yes, No, Cancel button options
• Input dialog
– Message prompt
– Input text field
• Variations are possible
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
44
A message dialog
private void showAbout()
{
JOptionPane.showMessageDialog(frame,
"ImageViewer\n" + VERSION,
"About ImageViewer",
JOptionPane.INFORMATION_MESSAGE);
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
45
Displaying text
• JLabel
– short text string display area
– usually not editable
• JTextField
– single line display area for plain text
– allows editing
• JTextArea
– multi-line display area for plain text
– allows editing
– make scrollable within a JScrollPane
46
Image filters
• First step toward image manipulation
• Function applied to the whole image
– darker: makes whole image darker
– lighter: makes whole image lighter
– threshold: turns image into grayscale (3-levels)
°white = upper-third pixel value range
°black = lower-third pixel value range
°gray = middle third
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
47
ImageViewer example
int height = getHeight();
int width = getWidth();
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
Color pixel = getPixel(x, y);
alter the pixel's color value;
setPixel(x, y, pixel);
}
}
• Menu items for each filter with a menu listener
– new JMenu named Filter added to the menu bar
°added new JMenuItems named Darker, Lighter, & Threshold
> new ActionListoner anonymous class for each menu item
~ invoking makeDarker, makeLighter, & threshold upon event
• Implement each actual filter operation
– simple filter iterate over entire image
– make change of some sort to the color of each pixel
– more complicated filters may use neighboring pixel value
48
Adding further filters
private void makeLighter()
{
if(currentImage != null) {
currentImage.lighter();
frame.repaint();
showStatus("Applied: lighter");
}
else {
showStatus("No image loaded.");
}
}
Code duplication in
activation methods?
Refactor!
private void threshold()
{
if(currentImage != null) {
currentImage.threshold();
frame.repaint();
showStatus("Applied: threshold");
}
else {
showStatus("No image loaded.");
}
}
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
49
imageviewer2-0
•
•
•
•
Define a Filter superclass (abstract)
Create function-specific subclasses
Create subclass instances in ImageViewer
Define a generic applyFilter method
50
Buttons and nested layouts
2 instances of JButton in the WEST area
In BorderLayout
- FlowLayout default
GridLayout (0 ,1)
in BorderLayout
- GridLayout resizes
GridLayout
in FlowLayout
in BorderLayout
- FlowLayout leaves space
51
Borders
• Adds decoration around components
• Used to group components or add space
• Every Swing component can have borders
• Some layout managers have border
parameters to create requested spacing
• Defined in javax.swing.border
– BevelBorder, CompoundBorder,
EmptyBorder, EtchedBorder,
TitledBorder
Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
52
Adding spacing
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(6, 6));
imagePanel = new ImagePanel();
imagePanel.setBorder(new EtchedBorder());
contentPane.add(imagePanel, BorderLayout.CENTER);
• Add empty space around outside of frame
– setBorder of content pane with EmptyBorder parameter
– cast the contentPane to a JPanel
°supertype Container does not have setBorder method
• Add extra spacing around the frame components
– by creating BorderLayout with 2 int parameters
• Add an “etched” line around the image (CENTER)
– setting an EtchedBorder for imagePanel
53
Before
After
• Add empty space around outside of frame
– JPanel contentPane = (JPanel)frame.getContentPane();
– contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
• Add extra spacing around the frame components
– contentPane.setLayout(new BorderLayout(6, 6));
• Add an “etched” line around the image (CENTER)
– imagePanel.setBorder(new EtchedBorder());
54
Other components
• Slider
– allows user to easily enter a numeric value
bounded by a minimum and maximum value
• Spinner
– allows user to choose via arrows or keys
from a range of values (does not wrap
around min-max values)
– can also automatically complete user typed
input
• Tabbed pane
– allows several components (i.e panels) share
the same space
– user chooses component by selecting
corresponding tab
• Scroll pane
– provides a scrollable
view of a component
55
Programming GUI with Swing
• Many different types of components, containers
and layout managers
– each has many attributes and methods
• Covered important concepts with details
– still large amount of functionality beyond our scope
• Many sources of information to further discover
– API documentation for the Swing classes
– Oracle Java Swing Tutorial
°http://docs.oracle.com/javase/tutorial/uiswing
56
Review
• Aim for cohesive application structures
– Endeavor to keep GUI elements separate from
application functionality
• Pre-defined components simplify creation
of sophisticated GUIs
• Layout managers handle component
juxtaposition
– Nest containers for further control
• Many components recognise user
interactions with them
• Reactive components deliver events to
listeners
• Anonymous inner classes are commonly
used to implement listeners
57