You are on page 1of 5

GUI Design/Implementation Introduction to Java GUIs

Patterns: The Listener (Observer-Observable) pattern Return of the MVC pattern Toolkits: MigLayout (improved API for GUI layout) UISpec4J (unit testing of GUI) Packaging: Manifest file and specifying the main class Including components in the jar file
(2)

Philip Johnson Collaborative Software Development Laboratory Information and Computer Sciences University of Hawaii Honolulu HI 96822
(1)

Question: How can object Foo communicate that its state has changed to objects Bar and Baz? One approach: direct method invocation. Class Foo { public void stateChange() { bar.notifyChange(Foo changed); baz.notifyChange(Foo changed); } } Issues with this approach: Object Foo hardwires references to instances it communicates with. In this code, every instance of Foo communicates their changes to a single instance of Bar and Baz! If a new object (Qux) wants to know about changes to Foo, the code in Foo must change.
(3) (4)

Listener Pattern (Motivation)

Listeners
Listeners provide a more flexible way for instances to communicate with each other. Approach: Foo maintains a list of instances who want to be notified when something happens to Foo. Foo provides some kind of addListener method. Bar and Baz instances add themselves to the list by invoking that method. Bar and Baz provide some kind of notify method that Foo will invoke on all of the instances in its list when something happens.

Foo
class Foo { private List listeners = new ArrayList(); public addListener(FooListener object) { listeners.add(object); } public notifyListeners () { for (FooListener listener: listeners) { listener.notify(Foo changed); } }
(5) (6)

Bar
class Bar implements FooListener { public Bar () { Foo foo = new Foo(); foo.addListener(this); } public void notify (String message) { System.out.println (Foo says: + message); }

Interface FooListener
public interface FooListener { public void notify(String message) { } }

Why Listeners are cool


Advantages of listener design pattern Simple to implement. Instances of Foo dont know (or care) who or how many instances are listening for its changes. Each instance of Foo can have different instances of Bar and Baz attached to it. Most important advantage: If a new class Qux wants to listen to Foo, no changes need be made to Foos code.

(7)

(8)

(1) All GUI components (Buttons, TextFields, etc.) support a variety of listeners. If an instance of Class Foo needs to know when a button is pressed, it adds itself as a listener to that button instance. (2) java.util provides the Observer (interface) and Observable (class) that implement this pattern. Provides basic machinery to non-GUI code

Java Support for the Listener Design Pattern

GUI example
class Foo implements ActionListener { private JButton button = new JButton(Hi!); public Foo () { button.addActionListener(this); } public void actionPerformed (ActionEvent e) { System.out.println(Button Hi! was pressed!): }
(10)

(9)

Observer-Observable Example (1)


class Foo extends Observable { private update() { this.doSomethingThatChangesState(); setChanged(); notifyObservers(Something Changed); }

Observer-Observable Example (2)


class Bar implements Observer { private Foo foo = new Foo(); public Bar () { this.foo.addObserver(this); } public void update(Observable obs, Object arg) { System.out.println(Foo changed!); }

(11)

(12)

The MVC Pattern

Implementing MVC: The Model


Model: Contains the application state (as usual) Implements Observable interface -Allows clients to add Observers (listeners) -When application state changes, Model invokes notifyObservers(). -This triggers invocation of all Observer's update() method

(Observer/Observable)

(GUI) (implemented using listeners)


(13) (14)

Model <-> View


Model - implements Observable - notifyObservers()

Implementing MVC: The View


View: Renders the GUI interface on screen. Two kinds of communication -Receives updates from model and displays these changes on screen. -Sends user gestures to controller using ActionPerformed methods available in each GUI component.

View "listens" for changes to model.

View - extends Observer - update() (15) (16)

View
Model - implements Observable - notifyObservers()

Implementing MVC: Controller


Controller: Listens for user gestures (changes to view) -Updates model in response

View "listens" for changes to model.

View - extends Observer - update() - GUI listeners


(17)

Controller "listens" for changes to view (user gestures).

Controller - actionPerformed() (18)

Controller
Model - implements Observable - notifyObservers() Controller changes model state (using method calls)

Most "sample" Java GUIs do not implement the full MVC pattern. Model and Controller are combined together, no Observer/Observable component. This is bad! As your GUI becomes more sophisticated, the lack of a real MVC design generally makes your code hard to understand, buggy, and hard to change. Using "real" MVC simplifies scale-up: multiple updates to View from one Model change multiple updates to Model from one user gesture easily support multiple Controllers, multiple Views, multiple Models

Advantages of MVC

View "listens" for changes to model.

View - extends Observer - update() - GUI listeners


(19)

Controller "listens" for changes to view (user gestures).

Controller - actionPerformed() - invokes Model API


(20)

StackMVCgui
Model: The StackModel class Implements Observable View: The View class Extends Observer Contains GUI components Controller: The Controller class Listens to GUI components Invokes StackModel API to change state.
(21) (22)

Layout Managers
To specify how your GUI components appear in the window, you use a Layout Manager. Java provides a set of built-in Layout Managers to support different needs. The built-in Layout Managers have been criticized as hard to use. Over the years, next generation layout managers have appeared. Two good open source alternatives: JGoodies MigLayout (used in StackMVCgui)

Unit Testing
We want to write unit tests that exercise the GUI interface that can be invoked from JUnit. We want support for this (similar to DbUnit support for databases and HttpUnit support for webapp testing). Lots of packages available! JFCUnit Abbott UiSpec4J (used in StackMVCgui) Two basic approaches: Use API calls on GUI components. Invoke the GUI manually, generate a script that can be re-run later.

Packaging
GUI applications generally want to be double clickable. Easiest way is to: package code and all required libraries in a single jar file. Indicate the main class in the manifest file. Besides double clicking, can invoke with: java -jar stackmvcgui.jar

(23)

(24)

Concurrency
All Java GUI programs are multi-threaded. Initial thread -the main program Event Dispatch thread -where event-handling code executes Worker threads -where time-consuming operations execute You must take care to make sure that code executes in the correct thread so that The user interface is responsive The user interface does not freeze!
(25) (26)

The initial thread


This thread runs the main() method. In typical Java GUI applications, this thread doesnt do much more than kick off the GUI in the Event Dispatch thread using code like the following: SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }

The Event Dispatch Thread


In general, code invoking Swing methods should execute on the Event Dispatch Thread. This code should be short tasks, such as tasks that respond to button presses and so forth. Tasks on the Event Dispatch thread must finish quickly, otherwise unhandled events back up and the user interface becomes unresponsive.
(27) (28)

Worker Threads
Used to execute long-running tasks. Each task running on a worker thread uses an instance of SwingWorker (Java SE 6): Supports a done method that runs on the Event Dispatch thread when the task completes. Intermediate results can be published to the Event Dispatch thread. Other goodies. See the Java Tutorial on Swing Concurrency for more details.

You might also like