Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
SYSC 1101 Object-Oriented Software Development Building Graphical User Interfaces with Java: Introduction to AWT and Swing • • Copyright © 1998-2005 D.L. Bailey, Systems and Computer Engineering, Carleton University revised March 30, 2005 1 What's In This Part of the Course? • We are going to introduce you to building applications with graphical user interfaces (GUIs), using Java's Abstract Windowing Toolkit (AWT) & Swing toolkit • These toolkits also serve as an example of a fairly large class hierarchy that exploits the fundamental O-O concepts supported by Java (classes, objects, inheritance, polymorphism, abstract classes, interfaces) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 2 1 What's In This Part of the Course? • Looking at all of the classes in the AWT & Swing would take an entire course (or longer) – we introduce enough classes to illustrate the key concepts, but you'll have more opportunities to use these toolkits in later courses • We won't spend much time in lectures looking at the details of the API for these classes SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 3 What's In This Part of the Course? • Suggestion: experiment! – run the example programs, use the Java Platform API specification to understand each method invocation in the example programs, then modify these programs & observe the changes in their appearance & behaviour • For more info, see the "Creating a GUI with JFC/Swing" trail in "The Java Tutorial": http://java.sun.com/docs/books/tutorial/uiswing/index.html SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 4 2 java.awt - The Abstract Windowing Toolkit • Introduced with Java 1.0 • Classes are divided into 3 main categories: – graphics (colours, fonts, shapes, etc.) – components (GUI components: windows, buttons, menus, etc.) – layout managers (control the positioning of components on the screen) • Each component corresponds to a “peer” component provided by the native GUI toolkit on the target platform (Windows, Sun Solaris, etc.) • Here is a subset of the AWT class hierarchy: SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing Classes for building menus are subclasses of Object Most AWT components; e.g., Button, Canvas, CheckBox, Choice (a pop-up menu of choices), Label, List (a list of Strings), Scrollbar, TextArea and TextField, are subclasses of Component Component Container Window Frame Object Dialog FileDialog 5 Panel Applet ScrollPane SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 6 3 java.awt - The Abstract Windowing Toolkit • Component – an abstract class – superclass of all GUI components except menu components and class CheckboxGroup • Container – the superclass for all components that contain other components – defines add(), for adding components to a container SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 7 java.awt - The Abstract Windowing Toolkit • Window – a top-level window with no border or menu bar – rarely instantiated (its subclasses are more useful) • Frame – a window with a border and a title bar – can have a menu bar – top-level window for Java AWT-based applications • typically, main() creates an instance of Frame as its top-level application window, then adds GUI components to the frame SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 8 4 java.awt - The Abstract Windowing Toolkit • Dialog – a dialog window, a.k.a. dialog box • FileDialog – a dialog window that allows a user to select a file • ScrollPane – a container that contains a single child component, and provides scrollbars to scroll over that component SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 9 java.awt - The Abstract Windowing Toolkit • Panel – a container that must be contained within another container – does not have its own window • Applet – a subclass of Panel – actually part of the java.applet package, not the AWT SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 10 5 AWT Limitations • The “look and feel” of AWT-based programs differs slightly across platforms, because of differences in the underlying native GUI elements • AWT components are limited to those that have peer components on all platforms ("lowest common denominator") SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 11 javax.swing - The Swing Toolkit • In response to the AWT, Netscape developed the Internet Foundation Classes, which evolved into the Swing toolkit (part of Sun’s Java Foundation Classes (JFC)) • Swing components do not require native peer components • Each Swing UI component is painted onto a blank window • Only peer functionality required is the ability to display windows and paint on them • Here is a (small) subset of the Swing class hierarchy, showing its relationship to the AWT classes: SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 12 6 Object Most (but not all) Swing classes begin with the letter "J" JComponent JPanel Component JScrollPane Container Window JFileChooser ... Box Frame Dialog JFrame FileDialog JWindow JDialog Panel Applet ScrollPane JApplet SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 13 javax.swing - The Swing Toolkit • JWindow, JFrame, JDialog, JPanel, JApplet, JScrollPane, and JFileChooser are the Swing counterparts of the AWT's Window, Frame, Dialog, Panel, Applet, ScrollPane and FileDialog classes • JComponent is the base class of most of the Swing components, including those dealing with menus – Swing has many more components than AWT • Use the Swing classes instead of the corresponding AWT classes • Box is a lightweight container (more later...) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 14 7 Some Swing Components SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 15 Some Swing Components • Not shown in the screen shot are: – components for building drop-down, pop-up, and pull-right menus: JMenuBar, JMenu, JPopupMenu, JMenuItem, JCheckBoxMenuItem, JRadioButtonMenuItem, JSeparator – components for building 2-D tables: JTable, JTableHeader – panes: JSplitPane, JTabbedPane, JLayeredPane, JEditorPane, JTextPane, JDesktopPane SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 16 8 Some Swing Components – JToolBar: a toolbar for displaying commonly used controls – JToolTip: displays a "tip" for a component – JOptionPane: class for creating and displaying standard dialog boxes – Misc. classes: JColorChooser, JInternalFrame, JPasswordField, JScrollbar, JTextArea, JTree, JViewport – Browse the API documentation for the classes in the javax.swing.* packages SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 17 First Swing Example: An Up/Down Counter SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 18 9 First Swing Example: An Up/Down Counter • Clicking the Up button causes the count to be incremented by 1 • Clicking the Down button causes the count to be decremented by 1 – this button is enabled only when the count is > 0 • Clicking the Reset button clears the count to 0 SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 19 MVC Architecture • One widely-accepted way of structuring a GUI-based application is to use the model-view-controller (MVC) architecture SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 20 10 MVC Architecture Controller The controller runs in response to user input (mouse clicks, key presses), and sends requests to the model. Model View The view displays information from the model in the user interface. The model contains the "domain objects" (the core application logic). When the model's state changes, it requests the view to update itself. SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 21 First Version of Class CounterModel public class CounterModel { private int count; public CounterModel() { count = 0; } public void increment() { count++; } public void decrement() { if (count > 0) count--; } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 22 11 First Version of Class CounterModel public void reset() { count = 0; } public int value { return count; } public String toString() { return Integer.toString(count); } public boolean equals(Object o) {...} } • Notice that this class does not inform the view when the model's state changes (will fix this later) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 23 First Version of Class CounterView import javax.swing.*; public class CounterView extends JFrame { private CounterModel model; Note: the package name is javax, not java public CounterView(CounterModel model) { super("Counter"); this.model = model; } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 24 12 First Version of Class CounterView • A JFrame is used as the top-level window for a Swing-based application – CounterView is declared to be a subclass of JFrame • JFrame has two constructors: – JFrame() creates an untitled JFrame object – JFrame(String title) creates a JFrame object with the specified title • Here, we use super(String) to invoke JFrame(String) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 25 First Version of Class Counter • This class creates an instance of the model and the view public class Counter { public static void main(String[] args) { CounterModel model = new CounterModel(); CounterView view = new CounterView(model); view.setResizable(false); view.setSize(400, 300); view.setVisible(true); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 26 13 First Version of Class Counter • By default, a frame is sized at at 0x0 pixels, so setSize() is sent to the frame to change it size to 400 pixels wide x 300 pixels high – setSize() is inherited from Component • If the setSize() message is not sent, only the title bar is displayed • The setVisible() message is sent to the frame to make it visible – setVisible() is inherited from Component SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 27 Running the Counter App SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 28 14 Closing a Frame • Clicking on the Close button or selecting Close from the left-most drop-down menu hides the frame but does not close the application • When a user attempts to close a JFrame, the default behaviour is to hide the frame • We can invoke setDefaultCloseOperation() to change the default behaviour SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 29 Closing a Frame • Symbolic constants for the method's arguments are defined in interface WindowConstants and inherited by JFrame – DISPOSE_ON_CLOSE – DO_NOTHING_ON_CLOSE – EXIT_ON_CLOSE – HIDE_ON_CLOSE • See the API documentation for JFrame for more information on the meaning of these constants SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 30 15 Closing a Frame • When the user closes the frame, we want the application to terminate by invoking System.exit(), so we set the default close operation to EXIT_ON_CLOSE – add this statement to Counter(): view.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE); • It works! Now we can populate the frame with components SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 31 A JFrame Consists of 4 Panes Title JFrame JRootPane JLayeredPane optional menu bar content pane glass pane Adapted from Core Java 1.2, Volume 1 - Fundamentals, Horstmann & Cornell SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 32 16 Containers and Components • Components are placed in the frame by adding them to the frame's content pane • JFrame’s getContentPane() method returns the frame's content pane (a Container) • Container defines several add() methods for adding Component objects to the container • Example: // assume that f refers to a JFrame and // comp refers to a Component Container contentPane = f.getContentPane(); contentPane.add(comp); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 33 Component Layout • Components are (normally) not placed in a content pane by specifying their (x,y) coordinates – what looks good in one environment may not look as good in another environment • Instead, each Container object has a layout manager object that controls how components are positioned in the container • Layout managers are defined by two interfaces in the java.awt package: LayoutManager and LayoutManager2 • Here are the layout managers that are most frequently used by application developers: SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 34 17 Border Layout • The default layout manager for a JFrame’s content pane object is a BorderLayout object • A border layout divides the container into 5 regions: “North”, “South”, “East”, “West”, and “Center” • One component can be placed in each region • See the API for java.awt.BorderLayout • BorderLayoutDemo.java produces the frame shown on the next slide SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 35 Border Layout SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 36 18 Flow Layout • A flow layout arranges components in a left to right flow, like words placed in lines of text in a paragraph • If the container changes shape, the components flow to new positions • See the API for java.awt.FlowLayout • FlowLayoutDemo.java produces the frame shown on the next slide SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 37 Flow Layout SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 38 19 Grid Layout • This layout manager lays out the panel’s components in a rectangular grid • The container is divided into equal-sized rectangles, and one component is placed in each rectangle • See the API for java.awt.GridLayout • GridLayoutDemo.java produces the frame shown on the next slide SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 39 Grid Layout SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 40 20 Box Layout • A box layout arranges components horizontally (leftto-right placement) or vertically (top-to-bottom placement) in the same order that they are added to the container • The major axis (X-axis or Y-axis) is specified when the BoxLayout object is created • See the API for javax.swing.BoxLayout • BoxLayoutDemo.java produces the frame shown on the next slide SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 41 Box Layout: Vertical Orientation SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 42 21 Box Layout: Horizontal Orientation SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 43 Components and Containers • It might seem that are layout choices are limited • Have another look at the AWT/Swing class hierarchy (see next slide) • A Container (and any subclass of Container) is a subclass of Component; i.e., a Container is-a kind of Component • So, we can put containers in containers • Commonly used Swing containers are JPanel and Box – in theory, any Swing component can be a container, because they are all subclasses of JComponent SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 44 22 Object Most (but not all) Swing classes begin with the letter "J" JComponent JPanel Component JScrollPane Container Window JFileChooser ... Box Frame Dialog JFrame FileDialog JWindow JDialog Panel Applet ScrollPane JApplet SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 45 Nesting Containers • This means we can put components in a JPanel (or a Box) and put the JPanel (Box) in the JFrame’s content pane – we can even put JPanel and Box objects inside JPanel and Box objects • Each Container has its own layout manager, which can be changed by sending the container the setLayout() message, passing a new layout manager object as the message argument – the default layout manager for a JPanel is a FlowLayout object SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 46 23 Component Nesting JComponent JPanel JComponent content pane of JFrame (a Container) JComponent JPanel JComponent JComponent JPanel JComponent SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 47 Counter App GUI Components JTextField content pane of JFrame (a Container) JButton JButton JPanel JButton SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 48 24 Second Version of Class CounterView import java.awt.*; import javax.swing.*; public class CounterView extends JFrame { private JTextField counterDisplay; private JButton upButton; private JButton downButton; private JButton resetButton; public CounterView(CounterModel model) { super("Counter"); Container contentPane = this.getContentPane(); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 49 Second Version of Class CounterView counterDisplay = new JTextField(); counterDisplay.setEditable(false); counterDisplay.setFont( new Font(null, Font.BOLD, 18)); counterDisplay. setHorizontalAlignment(JTextField.RIGHT); contentPane.add(counterDisplay, BorderLayout.NORTH); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout( new GridLayout(1, 3)); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 50 25 Second Version of Class CounterView // // // // // // // // // or buttonPanel.setLayout( new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); or, we could use a FlowLayout manager. Since this is the JPanel's default layout manager, there would be no need to create a new FlowLayout object. SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 51 Second Version of Class CounterView upButton = new JButton("Up"); buttonPanel.add(upButton); downButton = new JButton("Down"); buttonPanel.add(downButton); resetButton = new JButton("Reset"); buttonPanel.add(resetButton); contentPane.add(buttonPanel, BorderLayout.CENTER); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 52 26 Running the Counter App • The view looks o.k. (except that the value of the counter isn't displayed) • Clicking the buttons has no effect, because they aren't "hooked up" to the model • To do that, we have to design the controller SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 53 How Does a GUI-based Program Obtain Input? • We’ve seen how to use JOptionPane’s showInputDialog() method to get input from the user – it waits for the user to type a string in the box’s text field and press the OK button • In a GUI-based program, there can be several sources of input; e.g., clicking a button, moving a slider, typing characters in a text field, etc. • Invoking methods to wait for user input at specific component won’t work, because we can’t predict where the next input will come from SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 54 27 Event-Driven Programs • GUI-based Java programs use a technique known as event-driven programming • In an event-driven program, instead of having objects send messages to components to wait for input, the components send messages to event listener objects when input actions occur SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 55 The Java 1.0 Event Model • Adequate for simple applets, but not sufficient to build large-scale event-driven applications • Java developers are encouraged to use the newer Java 1.1 event model – you have stumbled into the Java 1.0 event model if you find yourself using: • class java.awt.Event • any of the following methods from class Component: handleEvent(), action(), gotFocus(), keyDown(), keyUp(), lostFocus(), mouseDown(), mouseDrag(), mouseEnter(), mouseExit(), mouseMove(), mouseUp() SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 56 28 The Java 1.1 Event Model • Objects that generate events in response to user actions are called event sources – click on a button – move mouse in a frame – type a key in a text field – etc. SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 57 The Java 1.1 Event Model • Different types of events are represented by different Java classes • java.util.EventObject – superclass of all Java 1.1 events (AWT, JavaBeans) • java.awt.AWTEvent – superclass of all Java 1.1 AWT events SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 58 29 The Java 1.1 Event Model • Each AWT event is represented by its own subclass; e.g., – java.awt.event.ActionEvent – java.awt.event.MouseEvent • Swing adds additional event classes, but uses the Java 1.1 event model SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 59 The Java 1.1 Event Model • Objects that receive events are called event listeners – package java.awt.event provides a number of listener interfaces (usually one for each type of event) – to process events, we develop classes that implement the appropriate listener interfaces – event listener objects are created from these classes – aside - for many events, there are abstract adapter classes that implement the listener interfaces • listener classes extend these adapter classes SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 60 30 The Java 1.1 Event Model • Each event source maintains a list of event listeners that are to be notified when events occur – source object provides methods to add and remove listener objects from the list • The Java Virtual Machine watches for the user’s actions on GUI components; e.g., – mouse movement/dragging, clicks on components – key presses SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 61 The Java 1.1 Event Model • When the JVM detects that user has interacted with a GUI component (e.g. clicking a button), the event source creates an event object that corresponds to the action, and notifies all of its listener objects that the event has occurred – source object invokes a method provided by the listener objects – the event object is passed to this method • The listeners then handle the event (typically by sending requests to other objects) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 62 31 Example • A JButton is a source of ActionEvent events, which are generated when the button is clicked • The listener object that receives these events is an instance of a class that implements the ActionListener interface • This interface declares a single method: public void actionPerformed(ActionEvent e) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 63 Example Here's a first attempt at implementing a listener for the counter app's Up button: class UpButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println("Up button clicked"); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 64 32 Example • The listener object must be created and registered with the JButton before it can receive events from the button • To do this we invoke the button's addActionListener() method ActionListener upButtonListener = new UpButtonListener(); upButton.addActionListener(upButtonListener); or simply, upButton.addActionListener( new UpButtonListener()); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 65 Example • When the Up button is clicked with the mouse, the UpButtonListener object's actionPerformed() method is invoked, and passed a reference to the ActionEvent object for the event • In this example, when you click the button, "Up button clicked" is displayed • We can write similar event listener classes for the Down and Reset buttons, then verify that the program correctly recognizes input from the user (although the listeners currently don't do any useful work - that's next) SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 66 33 MVC Controller • When structuring a Java program according to the MVC pattern, the controller corresponds to the listener classes, plus the code that registers the listeners with the components • The controller for the Counter app. will consist of four classes: SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 67 Counter App Controller Classes • The listener for the Up button will be an instance of a class called UpButtonListener • The listener for the Down button will be an instance of a class called DownButtonListener • The listener for the Reset button will be an instance of a class called ResetButtonListener • We'll also have a class called CounterController that will be responsible for creating the listener objects and registering them with the appropriate JButton objects SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 68 34 Counter App Controller Classes • Controller classes often need to use components created by the view class(es); e.g., – to register a listener with a component – to get input from a component; e.g., the keystrokes that were typed in a JTextField • We could pass references to the component objects to the controller class constructors , or the view classes could provide getter methods that return references to its components • There's a better way... use inner classes SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 69 Inner Classes • An inner class is a class defined inside another class • An instance of an inner class can access the variables of the instance of the enclosing class that created it • The 3 listener classes will be defined as private inner classes within CounterController • CounterController will be defined as a private inner class within CounterView SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 70 35 CounterController private class CounterController { private CounterModel model; public CounterController(CounterModel model) { this.model = model; upButton.addActionListener( new UpButtonListener()); downButton.addActionListener( new DownButtonListener()); resetButton.addActionListener( new ResetButtonListener()); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 71 CounterController /* The listener that is invoked when the Up button is clicked. */ private class UpButtonListener implements ActionListener { public void actionPerformed( ActionEvent e) { model.increment(); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 72 36 CounterController /* The listener that is invoked when the Down button is clicked. */ private class DownButtonListener implements ActionListener { public void actionPerformed( ActionEvent e) { model.decrement(); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 73 CounterController /* The listener that is invoked when the Reset button is clicked. */ private class ResetButtonListener implements ActionListener { public void actionPerformed( ActionEvent e) { model.reset(); } } } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 74 37 Changes to CounterView • This class is now responsible for creating the controller: public class CounterView extends JFrame { ... public CounterView(CounterModel model) { ... contentPane.add(buttonPanel, BorderLayout.CENTER); /* Create the listeners for the buttons. */ new CounterController(model); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 75 Updating the View • We know have a prototype that has a GUI and which requests the model to change its state when the user clicks the GUI's buttons • Now we need to arrange for the view to be updated when the model's state changes SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 76 38 Updating the View :CounterModel :CounterView increment() getCounterDisplay() getDownButton() Model gets components from view, updates JTextField with current count, enables Down JButton. POOR APPROACH - WHY? SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 77 Updating the View :CounterModel :CounterView increment() giveCurrentValue() Model gives current state to view, view updates its components. O.K. HERE, BUT GENERALLY A POOR APPROACH - WHY? SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 78 39 Updating the View :CounterModel :CounterView increment() update() value() Model asks view to update itself, view ask model for the state information that it wants to display. BEST APPROACH SO FAR, BUT HAS A FEW LIMITATIONS SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 79 Observer Pattern • This is a common problem, and one of the best solutions is described a design called the Observer pattern – you'll study design patterns extensively in upper year courses • Intent – “Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” -- Design Patterns:Elements of Reusable Object-Oriented Software SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 80 40 The Problem • We need to define a one-to-many dependency between the model and one or more views so that when the model changes its state all its dependents are notified and updated automatically • We want to notify the views: – without having to know how many there are – without having to know who they are • Essentially, we want to remove the tight coupling between the model object(s) and the view object(s) that should be notified SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 81 Essence of the Solution • The Observer pattern proposes a general design solution describing how to establish the relationships between these objects • The pattern defines a subject and observers – each subject maintains a list of dependent observers – when a subject changes state, all of its observers are notified – in response to receiving a notification, each observer queries the subject so that it can update its state SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 82 41 Essence of the Solution • This pattern is a publish-subscribe mechanism: – subject publishes notifications – observers subscribe (register with the subject) to receive these notifications SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 83 GOF Observer Pattern Structure Subject 1 attach(anObserver) detach(anObserver) notify ConcreteSubject - subjectState getState setState * Observer update for all o in observers { o.update() } ConcreteObserver - observerState update observerState = subject.getState() SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 84 42 Classes in the Observer Pattern • Participants (adapted from GoF) • Subject – knows its observers. Any number of Observer objects may observe a Subject – provides an interface for attaching and detaching Observer objects • Observer – defines an updating interface for objects that should be notified of changes in a subject SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 85 Classes in the Observer Pattern • ConcreteSubject – stores state of interest to ConcreteObserver objects – sends a notification to its observers when its state changes • ConcreteObserver – maintains a reference to a ConcreteSubject object – stores state that should stay consistent with the subject’s – implements the Observer updating interface to keep its state consistent with the Observable SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 86 43 Java Support for the Observer Pattern • Java directly supports the Observer pattern through class java.util.Observable and interface java.util.Observer • An observer (e.g. a view) implements the Observer interface • A subject (e.g., the model) extends the Observable class • The method names are different than those shown in the class diagram, but they provide equivalent operations SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 87 Modifying CounterModel public class CounterModel extends Observable { private int count; public CounterModel() { count = 0; } public void increment() { count++; setChanged(); notifyObservers(); } Inherited from class Observable SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 88 44 Modifying CounterModel public void decrement() { if (count > 0) count--; setChanged(); notifyObservers(); } public void reset() { count = 0; setChanged(); notifyObservers(); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 89 Modifying CounterModel public int value { return count; } public String toString() { return Integer.toString(count); } public boolean equals(Object o) {...} } • IMPORTANT: Notice that all methods that change the model's state invoke setChanged() and notifyObservers(), but methods that don't change the state never invoke those methods SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 90 45 Modifying CounterView import java.awt.*; import javax.swing.*; public class CounterView extends JFrame implements Observer { • The Observable interface defines a single abstract method: public void update(Observable o, Object arg); • We must implement the update() method to update the view to reflect the changed state of the model • This method will be invoked when the model invokes setChanged()/notifyObservers() SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 91 Modifying CounterView public void update(Observable o, Object arg) { /* Currently, the CounterModel we're observing * doesn't pass an argument when it notifies * its observers, so we don't use arg in this * method. */ CounterModel model = (CounterModel)o; /* Update the text field with the current * value of the counter. */ int count = model.value(); counterDisplay.setText( Integer.toString(count)); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 92 46 Modifying CounterView /* Ensure that the Down button is enabled * only when the count is positive. */ if (count == 0) downButton.setEnabled(false); else downButton.setEnabled(true); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 93 Modifying CounterView • How does the model know which view or views are observing it? • We need to change CounterView() to register the view as an observer of the model ... contentPane.add(buttonPanel, BorderLayout.CENTER); /* Register this view as an observer of the * model. */ model.addObserver(this); /* Create the listeners for the buttons. */ new CounterController(model); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 94 47 Modifying Class Counter • The main() method should ask the view to update itself after the model, view and controller have been created public class Counter { public static void main(String[] args) { CounterModel model = new CounterModel(); CounterView view = new CounterView(model); view.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 95 Modifying Class Counter /* Update the view to reflect the initial * state of the model. */ view.update(model, null); view.setResizable(false); view.pack(); // or view.setSize(400, 300); view.setVisible(true); } } • Also, notice the use of pack() instead of setSize() to size the frame SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 96 48 Tracing Key Method Invocations Counter <<create>> : CounterView addObserver(this) : CounterModel <<create>> : CounterController SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 97 Tracing Key Method Invocations : UpButtonListener : CounterModel : CounterView actionPerformed() increment() notifyObservers() update() value() setText() setEnabled() SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 98 49 Handling Events From Multiple Sources • A single event listener object can be registered as the listener for several components • To handle the event, the listener must first identify which component sent the event • The event listener starts by sending the event object the getSource() message, which returns a reference to the object that generated the event • Let’s look at how to write an event listener that handles the 3 counter buttons SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 99 CounterController with 1 Listener (v1) private class CounterController { private CounterModel model; public CounterController(CounterModel model) { this.model = model; ActionListener listener = new CounterButtonListener(); upButton.addActionListener(listener); downButton.addActionListener(listener); resetButton.addActionListener(listener); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 100 50 CounterController with 1 Listener (v1) /* The listener that is invoked when the Up, * Down and Reset buttons are clicked. */ private class CounterButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { /* Get a reference to the component that * sent the event. */ Object o = e.getSource(); JButton b = (JButton)o; SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 101 CounterController with 1 Listener (v1) if (b == upButton) model.increment(); else if (b == downButton) model.decrement(); else if (b == resetButton) model.reset(); } } Notice that we use ==, not equals(). Why? SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 102 51 CounterController with 1 Listener (v1) • In this example, b is a reference to the JButton object that generated the event • This reference is compared to the references saved in instance variables upButton, downButton, and resetButton SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 103 CounterController with 1 Listener (v2) • Another way we can identify which button was clicked is to check action commands • Each button has an action command, which is a String • By default, this action command is the button’s label, but this can be changed by sending the button the setActionCommand() message • We can obtain the action command by invoking JButton’s getActionCommand() method, which returns the String SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 104 52 CounterController with 1 Listener (v2) private class CounterController { private CounterModel model; public CounterController(CounterModel model) { this.model = model; ActionListener listener = new CounterButtonListener(); upButton.addActionListener(listener); downButton.addActionListener(listener); resetButton.addActionListener(listener); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 105 CounterController with 1 Listener (v2) /* The listener that is invoked when the Up, * Down and Reset buttons are clicked. */ private class CounterButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { /* Get a reference to the component that * sent the event. */ Object o = e.getSource(); JButton b = (JButton)o; SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 106 53 CounterController with 1 Listener (v2) String s = b.getActionCommand(); if (s.equals("Up")) model.increment(); else if (s.equals("Down")) model.decrement(); else if (s.equals("Reset")) model.reset(); } } Notice that we use equals(), not ==. Why? SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 107 CounterController with 1 Listener (v3) • The drawback to this approach is that every time we change the button labels (e.g., to use a different alphabet in a different country), the action commands will change • Use setActionCommand() to change the action commands – changing an action command doesn't change the button's label • Example: upButton.setActionCommand("+"); downButton.setActionCommand"("-"); resetButton.setActionCommand("0"); SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 108 54 CounterController with 1 Listener (v3) private class CounterController { private CounterModel model; public CounterController(CounterModel model) { this.model = model; ActionListener listener = new CounterButtonListener(); upButton.addActionListener(listener); downButton.addActionListener(listener); resetButton.addActionListener(listener); } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 109 CounterController with 1 Listener (v3) /* The listener that is invoked when the Up, * Down and Reset buttons are clicked. */ private class CounterButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { /* Get a reference to the component that * sent the event. */ Object o = e.getSource(); JButton b = (JButton)o; SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 110 55 CounterController with 1 Listener (v3) String s = b.getActionCommand(); if (s.equals("+")) model.increment(); else if (s.equals("-")) model.decrement(); else if (s.equals("0")) model.reset(); } } SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 111 Using Action Commands • Changing the counter controller to use action commands as the way to identify the button is a bit contrived, but for more complicated GUIs, they are a useful way to provide information about the button to the event listener SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing 112 56