BM214E Object Oriented Programming Lecture 12
Graphical User Interfaces -- overview -- essential elements Agenda Containers -- overview -- composition vs. inheritance Components -- examples Layout Managers -- examples
Graphical User Interfaces -- overview -- essential elements Agenda 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 Open Save Save As... Quit 40% Cancel Ok 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 an expanded version of the AWT, and provides greater control and convenience.
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. In Java, to create a GUI, you (1): Specify a Container, using... a Layout Manager to... place Components and/or Containers of Components... 1. TODAY I.e. UI form and appearance on the screen as desired. I.e. UI interaction and behavior LATER In Java, to make a GUI act as the interface for a program, you (2) Design human/computer dialog, using Listeners and componentgenerated events 2.
Graphical User Interfaces -- overview -- essential elements Agenda 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 Components -- the widgets or interactors (e.g., buttons) CLICK ME offset 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 2. Components CLICK ME offset 3. LayoutManagers offset
Graphical User Interfaces -- overview -- essential elements Agenda 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
import java.awt.*; public class HelloGUI { Hello GUI 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?
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.) Explanation while(true){ //get user input // handle event } 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 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.
Graphical User Interfaces -- overview -- essential elements Agenda 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 -- our class extends a container java.awt.frame 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 import java.awt.*; public class HelloComposition { Frame f; public HelloComposition(){ f = new Frame("Composition Test"); f.setsize(200,200); } f.setbackground(color.red); f.show(); We save our single inheritance Check the API } public static void main (String[] arg) { HelloComposition h = new HelloComposition(); } Will call constructor, so the show() method gets called
A few changes Example 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(); } }
Which One is Better? Inheritance Use up our single inheritance "Wasted inheritance" occurs where we subclass, but fail to override anything. Easier to change basic GUI behavior Composition Saves the single inheritance Useful when you want the "factory settings" for a GUI, with no changed 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
Graphical User Interfaces -- overview -- essential elements Agenda 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 in 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
Component Examples Component - generic widget that you can interact with Recall: A Container "is a" Component Button Canvas Checkbox Choice Container Panel Label List Scrollbar TextComponent - a widget that you can press - a widget that you can draw on - a widget that is checked or not checked - an option menu that drops down - a generic class that contains Components - a Container to be used inside another container; used to split an existing window - a single line of read-only text - a list of Strings - a horizontal or vertical scrollbar TextArea - multi-line editable text TextField - single-line editable text
Canvas: Components--Examples 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.
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. Components--Examples 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(); } }
Graphical User Interfaces -- overview -- essential elements Agenda 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 Note: Button s x and y coordinate starts from top left Click 25 pixels over 75 pixels down 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...
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: Layout Managers -- AWT Based 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 EAST SOUTH
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
Giving: LayoutManager: Example
WEST BorderLayout BorderLayout specifies the arrangement: NORTH CENTER EAST 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
Note: LayoutManager: No Constraints 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 2 3 4 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 CalcPad ti = new CalcPad(); ti.setsize(150,150); ti.show();
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(); ptemp.setlayout(new FlowLayout()); Here, we wrap ptemp.add(c); return ptemp; the components } 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?