Download No Slide Title

Document related concepts
no text concepts found
Transcript
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
Graphical User Interface
• A Graphical User Interface (GUI) is one variety of user interface.
.
• User interacts with objects on the screen (icons, buttons,
scroll-bars, etc.) via mouse clicks or keyboard actions.
Downloading libcrypt ...
File Edit
40%
Cancel
Open
Save
Save As...
Ok
Quit
Enter
GUI Popularity
• Popularized in 1980s by the Macintosh.
• Now state of the practice, and not final word in UI
• Intended to replace text-based "command line" and
"function key" interfaces.
• Despite similarities, GUIs are typically platformspecific (Windows 95/98/NT/1900, MacOS, X
Windows look-and-feel standards).
• Some graphical toolkits now provide cross-platform
APIs. E.g. wxWindows, GTK+, Java.
Java’s GUI Capabilities
Java provides essentially two related toolkits for
making GUIs:
1. The Abstract Windowing Toolkit ("AWT"), and
2. The Java Foundation Classes ("Swing")
Swing is merely an expanded version of the AWT,
and provides greater control and convenience.
Why Two Toolkits in Java?
AWT, then
JFC or "Swing"
MFC and
always "BSoD"
Well, it’s a long story. In short, JFC (swing) is Sun’s
answer to Microsoft’s MFC--a detailed toolkit library.
Cautionary Note
We’ve noted that Java has two flavors of toolkits: Swing
and AWT. It is not always wise to mix AWT and Swing
Components. For your first programs, stick with one
toolkit or the other.
In the following slides, we will use AWT Components to
show the basics. Then, we will switch to Swing
Components.
How do you tell them apart? Generally, but not always,
Swing Components will have a "J" in front of the class
name:
AWT
Swing
Button
JButton
Keep in Mind
• We are going to be describing graphical elements
in source code (text).
– There are drag and drop systems but usually
there is an underlying text-based system
– Eventually you need to get down to the text
level
• Java is designed to work across different
platforms.
– This poses special challenges
Steps to GUI Construction
We will learn GUI creation in two steps: the "view", and
then the "controls" or event handling.
1.
In Java, to create a GUI, you (1):
• Specify a Container, using . . .
• a Layout Manager to . . .
• place Components and/or
Containers of Components . . .
• on the screen as desired.
I.e. UI form and
appearance
TODAY
LATER
In Java, to make a GUI act as the
interface for a program, you (2)
I.e. UI interaction
and behavior
• Design human/computer dialog,
using Listeners and componentgenerated events
2.
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
GUI Design & Creation
There are three essential constructs in any GUI:
Containers
-- used to hold items (e.g., the frame)
File Edit
Help
offset
Components
-- the widgets or interactors (e.g., buttons)
CLICK ME
LayoutManagers
-- the hidden algorithm used to organize the
widgets inside the container
offset
Pop Quiz
(hint)
What are the three basic constructs
used in every GUI?
1.
Containers
File Edit
Help
offset
2.
Components
CLICK ME
3.
LayoutManagers
offset
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
Containers
Containers are special components that may
contain other components.
Examples of Containers:
AWT
• Panel
• Frame
• Applet
• Window
Swing
• JPanel
• JFrame
• Japplet
• JWindow
Note: Containment is not the same as inheritance extension.
A Frame may contain buttons,
but buttons are not subclasses of Frame.
Containers
A Container is a class that extends from
java.awt.Container
Object
As it turns out, the class "Container" is itself a
Component.
Component
Containers can have:
• Layouts set on them
Container
• Other components or containers added to them.
Example
Let’s make a simple
Frame.
When working with
GUIs, you often
have to consult the
API.
Note the
inheritance
structure of your
classes.
Example
So far, we’ve used the API to learn how to make a Frame.
We found constructors for:
public Frame ();
public Frame (String strTitle);
Now, how can we set the size of the Frame?
We again return to the API.
Example
The class java.awt.Frame does not contain a method to
set its size. But such a method was inherited from
java.awt.Component:
Example
Likewise, there’s no method in java.awt.Frame to make
the Frame visible. Instead, we find the method "show()"
was inherited from java.awt.Window
Hello GUI
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
("About to make GUI");
Frame f = new Frame ("Hello GUIs");
f.setSize( 200, 200 );
f.show();
System.out.println
("Finished making GUI");
}// main
}// class HelloGUI
(Demonstration)
What?
Our program runs, and the frame never goes away.
When we reach the end of main (as our print statement
indicates) why doesn’t the program end?
Explanation
When the Java VM created
our Frame, it entered into a
kind of ‘infinite loop’,
waiting for input and
events. (This is common
of graphical toolkits.)
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
("About to make GUI");
Frame f = new Frame ("Hello GUIs");
f.setSize( 200, 200 );
f.show();
System.out.println
("Finished making GUI");
}// main
}// class HelloGUI
while(true){
//get user input
// handle event
}
Since we didn’t
write any event
handlers, not even
the "window
disposal" button
will work.
Solution
To fix this problem, we’ll have to write some event
handling code. But in order to write some event
handling code, we have to create some components…
So, for now, you’ll just have to use Ctrl-C to end the
program. Once the basics of GUI construction are
covered, we’ll return to this problem.
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
Design Idea
We really have two choices when working with top-level
containers:
1. Inheritance
java.awt.Frame
-- our class extends a container
MyGUI
2. Composition
-- our class holds a container
MyGUI
java.awt.Frame
Design Note
HAS
-A
IS-A
But the tension between inheritance and
composition has been with us….
Example
We save our
single inheritance
import java.awt.*;
public class HelloComposition
{
Frame f;
public HelloComposition(){
f = new Frame("Composition Test");
f.setSize(200,200);
f.setBackground(Color.red);
Check the API
f.show();
}
public static void main (String[] arg)
{
HelloComposition h = new HelloComposition();
}
}
Will call constructor,
so the show() method gets called
Example
A few changes
allows us to
convert between
the two
import java.awt.*;
public class HelloInheritance extends Frame
{
Frame f;
public HelloInheritance(){
f = new Frame super("Composition Test");
f this.setSize(200,200);
f this.setBackground (Color.red);
f this.show();
}
public static void main (String[] arg)
{
HelloInheritance h = new HelloInheritance();
h.show();
}
}
Who’s Kung-Fu is Better
Inheritance
Use up our single
inheritance
Composition
Saves the single
inheritance
"Wasted inheritance"
occurs where we
subclass, but fail to
override anything.
Useful when you want
the "factory settings"
for a GUI, with no
changed behavior
Easier to change
basic GUI behavior
Often requires more
code, more references
Container Summary
Creating containers requires careful study of the
API. Watch the inheritance structure of the classes.
A top-level container, like a Frame, requires event
handlers (covered later).
There are many useful methods for customizing
containers. Just look them up in the API. E.g.:
myFrame.setBackground(Color.red);
An inherited
method
A class, also
in the API
Container Summary
We may often use "composition" where:
-- We don’t anticipate changing behaviors
-- We need to save our single inheritance
We may often use "inheritance" where:
-- We need to change basic GUI behaviors
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
Components
Most interactions in a Java GUI are with Components.
Another generic term for Component is other GUIs (e.g. X
Windows) is "widget".
Different types of components for different types of
interaction (e.g. buttons, etc.)
User interactions with components create events (thus, eventdriven programming)
As a rule, a Component cannot have other components inside
Exceptions to rule: pop up menus may have menu items
added to them. And Containers are themselves components
due to inheritance.
Component Examples
Demo: HelloWidget
Component Examples
Component
Recall:
A Container
"is a"
Component
- generic widget that you can interact with
Button
- a widget that you can press
Canvas
- a widget that you can draw on
Checkbox
- a widget that is checked or not checked
Choice
- an option menu that drops down
Container
- a generic class that contains Components
Panel
- a Container to be used inside another
container; used to split an existing window
Label
- a single line of read-only text
List
- a list of Strings
Scrollbar
- a horizontal or vertical scrollbar
TextComponent
TextArea - multi-line editable text
TextField - single-line editable text
Components--Examples
Canvas:
• typically a drawing surface on which shapes, graphs, pictures,
etc can be drawn.
• utilize mouse events and mouse motion events to interact with
the user to accomplish the drawing tasks.
TextField:
• a one-line data entry area
• theoretically infinite in length
• can generate Key events to indicate that the user has typed a key
• more typically, it generates an Action event when the user
finishes the data entry and hits Return in the TextField.
Components--Examples
Button:
• simply a clickable component
• appears as a standard button on whatever graphical
environment the user happens to be running at the time
• generates an Action event when clicked
Label:
• a one-line field of text.
• user cannot change this text directly; program changes text with
setText( ) method.
• usually not used to capture events (but could)
• usually used as a one-way information source to provide a
message to the user.
Joining Components & Containers
Containers have a method:
public void add (Component c)
that allows us to place items inside. Thus:
Panel p = new Panel();
Button b1 = new Button ("Example 1");
Button b2 = new Button ("Example 2");
p.add (b1);
p.add(b2);
In this example, two buttons are added to the panel.
Example
import java.awt.*;
public class HelloComponent
{
Frame f;
public HelloComponent(){
f = new Frame("Component Test");
f.setSize(200,200);
f.setBackground (Color.red);
Panel p = new Panel();
Button b = new Button ("Hello Components");
p.add(b);
f.add(p);
f.show();
}
public static void main (String[] arg)
{
new HelloComponent();
}
}
(Demonstration)
Agenda
Graphical User Interfaces
-- overview
-- essential elements
Containers
-- overview
-- composition vs. inheritance
Components
-- examples
Layout Managers
-- examples
LayoutManagers
We can now create Components and Containers.
But how can they be organized? We might be
tempted to call methods that set the x, y location of
a component in a container.
Consulting the API, we find some likely methods:
public void setLocation
(int x, int y);
public void setSize
(int width, int height);
Layout Managers -- Motivation
• To arrange items, one could specify the location of a
Component by specific x and y coordinates. The
Component class contains the method setLocation(int
width, int height):
Frame f = new Frame(); f.setSize(500,500);
Button myButton = new Button ("Click");
add(myButton);
myButton.setLocation(25, 75);
NOTE:
Origin 0,0
at top left
75 pixels down
Click
Note: Button’s
x and y coordinate
starts from top left
25 pixels over
What’s
wrong
with this
approach?
Layout Managers -- Motivation
Problems with specifying x, y coordinates for Component:
• This becomes tedious for even mildly complex GUIs.
• Addition of more components requires recalculation of every
component’s x, y coordinate
• If container resizes (e.g., user expands window), calculations
have to be redone!
Solution:
• Position components based on a percentage of available
container size. Or create an algorithm to place components . . .
But Java already does this for you . . .
Layout Managers -- AWT Based
• Java provides several layout managers.
• We will concentrate here on several of them:
• BorderLayout
• GridLayout
• FlowLayout
•BoxLayout
• To tell a container which layout manager to use, invoke the method:
setLayout( );
and specify a type of layout.
For example:
To specify a BorderLayout:
setLayout (new BorderLayout());
LayoutManagers:
Two General Flavors
• One can conceptually divide layout managers into
two types:
– Those that attach constraints to their
components.
– Those that do not.
• What does this mean, "attach constraints"?
If a manager attaches constraints to a component,
then information about a component’s location (e.g.,
compass points) is stored with the object.
LayoutManagers: Constraints
• BorderLayout specifies constraints corresponding to
compass regions of a container:
NORTH
WEST
CENTER
SOUTH
EAST
LayoutManagers: Constraints
• BorderLayout then appends constraint
information on all components, e.g.:
this.setLayout (new BorderLayout());
Button e = new Button ("East");
Button w = new Button ("West");
Button n = new Button ("North");
add(e, "East"); // deprecated
add("West", w); // works; deprecated
add(n, BorderLayout.NORTH); // better
LayoutManagers: Constraints
LayoutManagers:
Another Example
import java.awt.*;
public class Test extends Frame {
public Test() {
super ("BorderLayout Demo");
this.setSize(200,200);
this.setLayout(new BorderLayout());
this.add (new Button ("North"), BorderLayout.NORTH);
this.add (new Button ("South"), BorderLayout.SOUTH);
this.add (new Button ("East"), BorderLayout.EAST);
this.add (new Button ("West"), BorderLayout.WEST);
this.add (new Button ("Center"), BorderLayout.CENTER);
}
public static void main (String[ ] args) {
new Test().show();
}
} // test
LayoutManager: Example
Giving:
BorderLayout
BorderLayout specifies the arrangement:
CENTER
EAST
WEST
NORTH
SOUTH
• To add components to a BorderLayout, specify the position in
which the component will reside.
• Only one component (or container) can go in each of the five
positions.
BorderLayout--Example
setLayout (new BorderLayout());
add(new Label ("Hello!"), "North");
Canvas myCanvas = new Canvas();
// more about Canvas in a moment
add (myCanvas, "Center");
Hello!
{ a fresh canvas
for drawing here}
Simple Example
import java.awt.*;
public class HelloLayout {
public static void main(String[] args) {
Frame f = new Frame();
f.setSize(400,400);
BorderLayout bord = new BorderLayout();
f.setLayout(bord);
Button b = new Button ("Hello");
f.add(b, BorderLayout.SOUTH);
}
} // HelloLayout
Will this work?
Let’s run it
and find out...
(Demonstration)
Simple Example
import java.awt.*;
public class HelloLayout {
public static void main(String[] args) {
Frame f = new Frame();
f.setSize(400,400);
BorderLayout bord = new BorderLayout();
f.setLayout(bord);
Button b = new Button ("Hello");
f.add(b, BorderLayout.SOUTH);
f.show();
}
} // HelloLayout
Ahh.. We forgot to set our Frame
visible. Now it works.
Welcome to the exciting world
of GUI debugging.
LayoutManager:
No Constraints
• The second type of LayoutManager does not specify
constraints for the objects it holds.
• Examples:
– GridLayout()
– FlowLayout()
• Without constraints, you cannot accurately predict
layout behavior across platforms
LayoutManager: No Constraints
import java.awt.*;
public class FlowTest extends Frame {
String Labels[] = {"Short", "Short", "Long Label",
"Really Long Label", "Really, really long"};
public FlowTest(){
this.setSize(400,200);
setLayout(new FlowLayout());
for (int i = 0; i < Labels.length; i++){
Button temp = new Button (Labels[i]);
add (temp);
}
}
public static void main (String arg[]){
new FlowTest().show();
}
} //class test
LayoutManager: No
Constraints
Yields:
LayoutManager: No Constraints
And also:
Demonstration
LayoutManager:
No Constraints
• Note:
– Since pixels, fonts and insets vary with each platform,
layout without constraints will vary greatly.
• Lesson:
– Use layout managers without constraints only when you
have few components, or you’ve anticipated their
possible movement.
LayoutManager:
No Constraints
• Don’t think that layout managers without constraints
are not useful!
• One of the most useful constraint-free layout
manager is "GridLayout".
public GridLayout();
public GridLayout(int rows, int cols);
public GridLayout
(int rows, int cols, int hgap, int vgap);
GridLayout
GridLayout specifies a grid pattern via:
setLayout (new GridLayout (rows, columns));
For example:
setLayout (new GridLayout(2,3));
generates:
GridLayout
• To add components (or containers) to a GridLayout, particular
locations are not specified (unlike BorderLayout).
• Instead, the components (or containers) are positioned by the
sequence in which they are added, as indicated by numerals
below.
• Significantly, GridLayout is distortive(değiştirilebilir), meaning
components are stretched to fill the available space in the grid.
1
4
2
3
5
6
GridLayout
Optionally, two additional parameters may be used with
GridLayout to specify the horizontal and vertical spacing (in
pixels) between grid elements:
setLayout (new GridLayout (rows, columns, hspace, vspace));
where hspace specifies horizontal size,
and vspace specifies vertical size, e.g.,
setLayout (new GridLayout (2, 2, 7, 5));
GridLayout: Example
import java.awt.*;
public class CalcPad extends Frame {
public CalcPad() {
setLayout(new GridLayout(5,3));
int off[]={-2,2,0};
for (int i=9; i >= 1; i--)
add (new Button (""+(i+off[i%3])));
add (new Button ("."));
add (new Button ("0"));
add (new Button ("+/-"));
add (new Panel());
}
public static void main (String[] arg){
CalcPad ti = new CalcPad();
ti.setSize(150,150);
ti.show();
}
}//CalcPad
Box Layout: Motivation
Often, it is desirable to place items in horizontal
or vertical direction. A grid layout may not be the
best choice, since grid components are resized to fit
the available space--it distorts its contents.
container
component
Desired look
A (3, 1) grid forces
size changes
BoxLayout
A BoxLayout provides this feature. It resembles
a FlowLayout, but with directional control, and other
features
Horizontal and vertical flow control
BoxLayout: How
The BoxLayout has a single constructor:
BoxLayout(Container target, int axis);
The ‘target’ is the container we wish to layout.
The ‘axis’ is a static field:
BoxLayout.X_AXIS;
BoxLayout.Y_AXIS;
JPanel buttonPanel = new JPanel();
BoxLayout bLayout = new BoxLayout
(buttonPanel, BoxLayout.X_AXIS);
buttonPanel.setLayout(bLayout);
Questions?
Exercise
Please Log In
User Name
Password
Let’s design a simple class that displays a login prompt.
No events will be handled; let’s just experiment with
components, containers and layout managers.
Step 1: List Components
Please Log In
User Name
Password
Labels
Text Fields
Step 2: List Containers
Please Log In
User Name
Password
Panel (out container)
Panel (perhaps a grid?)
Step 3: Select Layouts
Please Log In
User Name
Password
Grid Layout
Step 3: Select Layouts (cont’d)
Please Log In
User Name
Password
BorderLayout
Step 4: Code
import java.awt.*;
public class LoginPanel extends Panel {
TextField password, username;
Panel innerPanel;
public LoginPanel () {
this.setLayout(new BorderLayout());
innerPanel = new Panel();
innerPanel.setLayout(new GridLayout(2,2));
innerPanel.add(new Label("User Name"));
username = new TextField(10);
innerPanel.add(username);
innerPanel.add(new Label("Password"));
password = new TextField(10);
innerPanel.add(password);
this.add(innerPanel,
BorderLayout.CENTER);
this.add(new Label("Please Log In"),
BorderLayout.NORTH);
}
// class LoginPanel (con’td)…
public static void main(String[] args) {
Frame f= new Frame();
f.setSize(400,400);
f.add(new LoginPanel());
f.show();
}
} // LoginPanel
Demonstration
Step 5: @%#&$&!
What
happened?
Analysis
Recall that grid layout distorts, and stretches the cell
contents to fit the maximum allowed space.
Revision #1
User Name
Password
Since the grid was distortive, we’ll wrap the contents
in an inner panel. The wrapping panel will get stretched,
but not its contents.
import java.awt.*;
public class LoginPanel extends Panel {
TextField password, username;
Panel innerPanel;
public LoginPanel () {
this.setLayout(new BorderLayout());
innerPanel = new Panel();
innerPanel.setLayout(new GridLayout(2,2));
innerPanel.add(wrapInPanel(new Label("User Name")));
username = new TextField(10);
innerPanel.add(wrapInPanel(username));
innerPanel.add(wrapInPanel(new Label("Password")));
password = new TextField(10);
innerPanel.add(wrapInPanel(password));
this.add(innerPanel, BorderLayout.CENTER);
this.add(new Label("Please Log In"),
BorderLayout.NORTH);
}
public Panel wrapInPanel(Component c){
Panel pTemp = new Panel();
Here, we wrap
pTemp.setLayout(new FlowLayout());
the components
pTemp.add(c);
return pTemp;
before adding
}
/* Revised LoginPanel class (cont’d)
*/
public static void main(String[] args) {
Frame f= new Frame();
f.setSize(400,400);
f.add(new LoginPanel());
f.show();
}
} // LoginPanel
Demonstration
Result: Hmmm.
This time,
it’s the BorderLayout
that’s distorting
the grid panel
Our solution so far
has been adequate
for a basic GUI. But
let’s see how to
really solve this
problem.
The Fix
We want the components to have their natural size:
User Name
A box layout (X_AXIS) will do this.
We also want the sets of widgets
to take up their proper
vertical position, as if there were
springs forcing the components
away from the top/bottom.
User Name
Password
Solution
As it turns out, there’s an API call for creating this
‘spring’ effect:
myContainer.add
(Box.createHorizontalGlue());
myContainer.add(new Button ("hi"));
Hi
Horizontal glue pushes the component away
import java.awt.*;
import javax.swing.*;
public class LoginBoxPanel extends Panel{
TextField password, username;
public LoginBoxPanel () {
password = new TextField(10);
username = new TextField(10);
Panel pInner = new Panel();
pInner.setLayout
(new BoxLayout(pInner, BoxLayout.Y_AXIS));
Panel pUser = getPanelPair(new Label("User Name"),
username);
Panel pPass = getPanelPair(new Label("Password"),
password);
pInner.add(pUser);
pInner.add(pPass);
// constructor (cont’d)...
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Panel prompt = new Panel();
prompt.setLayout(new FlowLayout(FlowLayout.LEFT));
prompt.add(new Label ("Please Log In"));
this.add(prompt);
this.add(Box.createVerticalGlue());
this.add(pInner);
this.add(Box.createVerticalGlue());
}
public Panel getPanelPair
(Component first,Component second){
Panel pTemp = new Panel();
pTemp.setLayout
(new BoxLayout(pTemp, BoxLayout.X_AXIS));
pTemp.add(first);
pTemp.add(second);
Panel pWrapper = new Panel();
pWrapper.setLayout(new FlowLayout());
pWrapper.add(pTemp);
return pWrapper;
}
public static void main(String[] args) {
Frame f= new Frame();
f.setSize(400, 200);
f.add(new LoginBoxPanel());
f.show();
}// main
} // LoginBoxPanel
Demonstration
Ulcer Check
Confused by the preceding? Yea, it’s a lot to take in.
BUT THE POINT IS THAT YOU CAN PLACE CONTAINERS
INSIDE OTHER CONTAINERS, and thereby create a novel
layout.
For now, stick with the simple layouts (e.g., the simple
BorderLayout/GridLayout), and become comfortable
with components.
Questions?