18.JavaGUI - ics-software

Download Report

Transcript 18.JavaGUI - ics-software

Introduction to Java GUIs
Philip Johnson
Collaborative Software Development Laboratory
Information and Computer Sciences
University of Hawaii
Honolulu HI 96822
(1)
GUI Design/Implementation
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)
Listener Pattern (Motivation)
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)
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.
(4)
Foo
class Foo {
private List listeners = new ArrayList();
public void addListener(FooListener object) {
listeners.add(object);
}
private notifyListeners () {
for (FooListener listener: listeners) {
listener.notify(“Foo changed”);
}
}
(5)
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);
}
(6)
Interface FooListener
public interface FooListener {
public void notify(String message) { }
}
(7)
Why Listeners are cool
Advantages of listener design pattern
•Simple to implement.
•Instances of Foo don’t 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 Foo’s code.
(8)
Java Support for the Listener
Design Pattern
(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
(9)
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)
Observer-Observable Example (1)
class Foo extends Observable {
private update() {
this.doSomethingThatChangesState();
setChanged();
notifyObservers(“Something Changed”);
}
(11)
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!”);
}
(12)
The MVC Pattern
(Observer/Observable)
(GUI)
(implemented using listeners)
(13)
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
(14)
Model <-> View
Model
- implements Observable
- notifyObservers()
View "listens"
for changes to
model.
View
- extends Observer
- update()
(15)
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.
(16)
View
Model
- implements Observable
- notifyObservers()
View "listens"
for changes to
model.
View
- extends Observer
- update()
- GUI listeners
(17)
Controller "listens"
for changes to
view (user gestures).
Controller
- actionPerformed()
-
Implementing MVC: Controller
Controller:
•Listens for user gestures (changes to view)
-Updates model in response
(18)
Controller
Model
- implements Observable
- notifyObservers()
Controller changes
model state (using
method calls)
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
Advantages of MVC
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.
(20)
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
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)
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)
(22)
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.
(23)
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
(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)
The initial thread
This thread runs the main() method.
In typical Java GUI applications, this thread
doesn’t 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();
}
}
(26)
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)
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.
(28)