Model-Oriented Architectures and Frameworks for Swing
Download
Report
Transcript Model-Oriented Architectures and Frameworks for Swing
Model-Oriented Architectures
and Frameworks for
Swing-Based User Interfaces
Dan Jacobs
[email protected]
President and founder, ModelObjects Group
http://www.modelobjects.com
President and founder, JPlates Inc.
http://www.jplates.com
Chairman, Boston ACM WebTech Group
http://www.acm.org/chapters/webtech
ModelObjects Group
Founded in December 1995
Object-Oriented Software Development
Architecture, Design, Implementation
Swing User-Interface Development
Compilers and Language Tools
Multithreaded Server Architectures
Web & J2EE Applications
IDE Integration and Plug-ins
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
2
Seminar Overview
Why build more traditional GUIs?
Overview of AWT and Swing
Important Design Patterns
Levels of Model-View-Controller
Model-Oriented UI Architectures
Application-Level Controller Logic
Effective Event-Handling Strategies
Effective Swing Layout Management
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
3
Why Build Traditional GUIs?
Most interactive, most expressive
Easier to develop (in some ways)
Easier to debug, performance-tune, …
Better at maintaining user confidence
More flexible for managing complexity
Integration with other applications
Integration with other technologies
Disadvantages too
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
4
Overview of AWT and Swing
Overview of AWT and Swing
Swing is built on core of AWT
Common event-handling model
Lightweight components
Powerful graphics operations
Fonts, colors, images, printing, etc.
Layout managers, container composition
Rich component class library
Pluggable Look and Feel
Powerful and Extensible
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
6
Swing Development Challenges
Mostly single-threaded model
Everything happens on event thread
Many large, complex frameworks
Hard to know how & where to fit it
Unfamiliar layout and composition
The right thing for cross-platform GUIs
API shows signs of age (from JDK1.1)
Enormous API, not entirely consistent
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
7
AWT/Swing Software Layers
Many other standard extensions
Swing (javax.swing and sub-packages)
J2SE
AWT Lightweight Support / Graphics 2D
Application
Code
AWT Component & Container Framework
J2SE Core Java Packages
JVM and native method libraries
Platform Operating System
and Window System
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
8
Swing Components
Simple Components
Button, text-field, check-box, scrollbar,
label, slider, combo-box, spinner, etc.
Containers
Panel, scroll-pane, tab-pane, split-pane,
dialog, window, popup, etc.
Complex Components
Table, tree, menu, file-chooser, etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
9
Lightweight Component Model
Platform window system provides:
Top-level windows and dialogs
Underlying input events
Underlying graphics operations
AWT/Swing does the rest:
Mapping “flat” events to components
Painting, clipping, etc. on window
Platform doesn’t see lightweight comps
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
10
Inside Swing Components
Internal state management
Event handling
Painting / Rendering
Support for event-listeners
Component properties customization
Internal composition and layout
Built-in recursive support for child
components – events, painting, etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
11
Black-Box Component Behavior
Allocate and initialize
Configure additional properties
Add to parent container
Add event listeners
Add selection listeners
Add property-change listeners
Modify properties from listeners
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
12
White-Box Customization
Complex object-oriented frameworks
Define subclass of component class
Override methods as appropriate
Call superclass methods as needed
Stick to the rules (if you can find them)
Requires much deeper knowledge of
AWT and Swing design and internals
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
13
Black-Box Component Use
JButton button1 = new JButton("Press Me");
button1.setEnabled(false);
buttonPanel.add(button1);
ActionListener bh = new ButtonHandler(this);
button1.addActionListener(bh);
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
14
Object-Oriented Design
Patterns and Frameworks
Object-Oriented Design Patterns
Recognizable patterns that appear over
and over again in good designs.
General, reusable solutions to common
design problems.
Encapsulate aspects of designs that are
likely to change.
Allow independent parts of a design to
work together – maintain loose coupling.
Reuse of intellectual effort & experience.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
16
Design Principle: Separation of
Independent Concerns
Promote loose coupling and strong
object encapsulation
Allow independent parts of application
to evolve independently
Hide internal details from parts that
should not depend on them
Don’t take it too far – some things
are not independent of each other
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
17
Object-Adapter Design Pattern
Problem: Use an existing class as if it
implemented a new interface, but without
modifying the class or the interface.
Analogy: Plug an electric appliance into a
different kind of outlet, without changing
the appliance, the plug, or the outlet.
Object-Adapter prescribes the relationships
between the existing class, the required
interface, and a new adapter class.
Reusable concept and approach, but each
new kind of adapter uses a new class.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
18
Object Adapter Design Pattern
class NewSocket
interface NewPlugProvider
references
plugIn(NewPlug);
…
NewPlug getNewPlug();
…
implements
NewPlugAdapter
class OldHairDryer
references
OldPlug getPlug();
boolean getBlowerOn();
setBlowerOn(boolean);
…
GBCACM PDS
April 30, 2005
implements NewPlugProvider
NewPlug getNewPlug() { … }
private OldSocket _oldSocket;
…
Dan Jacobs
http://www.modelobjects.com
19
Event Listener Design Pattern
More flexible extension of Observer
Support for multiple event listeners
Event object exposes source, details
Listeners implement common interface
In Swing’s implementation:
Event sources follow naming conventions
Listeners notified by synchronous calls
Some event objects are modifiable
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
20
Event Listener Design Pattern
FooEventSource
addFooListener(FooListener)
removeFooListener(FooListener)
fireFooEvent1()
fireFooEvent2()
FooListener
listeners
handleFooEvent1(FooEvent)
handleFooEvent2(FooEvent)
event-source
FooEvent
getSource()
getEventType()
getEventDetails()
GBCACM PDS
April 30, 2005
implements
event
ConcreteFooListener
handleFooEvent1(FooEvent)
handleFooEvent2(FooEvent)
Dan Jacobs
http://www.modelobjects.com
21
PropertyChangeListener Pattern
Special case of Event Listener pattern
Central to Java Beans component model
Events identify source, property, values
Property normally identified by naming
conventions (e.g. getFoo(), setFoo(…))
Class must provide support for
managing PropertyChangeListeners
Setter methods, after changing state,
fire PropertyChangeEvents
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
22
PropertyChangeListener Pattern
class ChangeHandler implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent event) {
Object changeSource = event.getSource();
String propertyName = event.getPropertyName();
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
...
}
}
…
ChangeHandler handler = new ChangeHandler();
objectToWatch.addPropertyChangeListener(handler);
…
doSomethingTo(objectToWatch);
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
23
Object-Oriented Frameworks
Typically use many design patterns.
Well defined roles to play, frequently
specified by interfaces.
Core group of classes orchestrates
common behavior for other roles.
Frameworks don’t have to be large or
complex – the fewer roles, the better.
Can offer best kind of code reuse.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
24
Model View Controller Pattern
A Frequently Misunderstood Pattern
<a href="dosomething?foo=3&bar=no">Click Here</a>
Model View Controller Pattern
One of best know (as MVC), least
fully-understood design patterns.
Originated in Smalltalk-80 window
system library – fully object-oriented.
Innumerable mutants, contortions,
and distant cousin spin-off patterns.
Encapsulated object state is not the
same thing as the model role.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
26
Model View Controller Pattern
model
state
queries
•
•
•
•
View
Model
•
•
•
model •
change
events
view-independent
object encapsulation
change-event source
first-class object
renders model info
change-event listener
gesture-event source
first-class object
GBCACM PDS
April 30, 2005
gesture
events
•
•
view •
control •
model
state
changes
Controller
gesture-event listener
updates models
selects alternative views
first-class object
Dan Jacobs
http://www.modelobjects.com
27
MVC Variant Used in Swing
View and Controller combined into a
single look-and-feel (L&F) object.
View-specific state in Component and
L&F, view-independent state in Model.
Models are specified by interfaces, and
default implementations provided.
Some components rarely expose the
model, and support listeners directly.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
28
Swing MVC Example 1 - JButton
View supports label, different colors
for disabled, armed, etc., icons for
normal and disabled, etc.
Controller responds to mouse press
and release, enter and exit, etc.
JButton state includes label, icons,
colors, and button-model.
Model includes action-command,
enabled, armed, pressed, rollover,
selected (e.g. for checkbox), etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
29
Swing MVC Example 2 - JList
List-model abstracts list of Objects and
change-events for contents of the list.
Selection-model independent of model.
View defined in terms of cell-renderers
that render individual model elements.
Changes to model made by application
code, not by component interactions.
Model changes handled by view, model
elements painted by cell-renderers.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
30
Direct Editing Example
EmailRecipient _recipient;
JCheckBox prefersHtmlCheckbox = new JCheckBox("prefers HTML email");
prefersHtmlCheckBox.addItemListener(new HtmlEmailCheckboxWatcher());
public void editEmailRecipientPreferences(EmailRecipient recipient) {
this._recipient = recipient;
prefersHtmlCheckbox.setSelected(recipient.getPrefersHtmlEmail());
…
}
class HtmlEmailCheckboxWatcher implements ItemListener {
public void itemStateChanged(ItemEvent event) {
boolean selected =
(event.getStateChange() == ItemEvent.SELECTED);
_recipient.setPrefersHtmlEmail(selected);
}
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
31
A Closer Look at Direct Editing
Initialize from Model property value.
Use listener to change property value.
Simple, but deceptively simplistic.
Missing numerous important features:
enable/disable logic
validation, propagation, transactions
apply, reset, undo, redo
notification of model changes to listeners
Direct use of model API by UI code
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
32
Model-Oriented Architectures
Model-Oriented Application =
Model Objects + Coordinated Uses of Model Objects
Model-Oriented Frameworks
Abstract Class-Level Metadata
Model-Oriented Form-Based Editing
Application-Level MVC
Frameworks for Tables and Trees
Master-Detail Relationships
Support for Model Class-Hierarchies
More Object-Oriented Design Patterns
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
34
Abstract Class-Level Metadata
Not all so-called models are Beans.
“tagged” hash-tables
XML DOM sub-trees
LDAP or JNDI entries
URLs with query parameters
database result-set wrappers
Frequently no built-in validation logic.
Rarely any propagation logic.
Rarely any change-listener support.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
35
Class-Level Metadata for the UI
May want additional (often extrinsic)
properties just for the user interface.
Want controlled, secure exposure of
business object internals.
May want higher levels of abstraction
than back-end representations.
Want to localize dependencies on
back-end representation details.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
36
ModelObjectAdapter
Object getAspectValue(ModelAspectId)
void setAspectValue(ModelAspectId, Object)
Object getModelObject()
void validateModel() throws ModelValidationException
n modelDescriptor
1
1
Application
Model Object
Instance
n
1
ModelDescriptor
ModelObjectAdapter makeModelObjectAdapter(Object)
ModelAspectAdapter getModelAspectAdapter(ModelAspectId)
void addModelObjectValidator(ModelObjectValidator)
void validateModel(ModelObjectAdapter)
1
1
Application
Model Object
Class
class level information
1
1
instance level
Model Metadata Framework
(or other metadata)
modelAspectAdapters
n
ModelAspectAdapter*
Object getAspectValue(ModelObjectAdapter)*
void setAspectValue(ModelObjectAdapter, Object)*
Class getModelAspectType()
boolean isReadOnlyAspect()
GBCACM PDS
April 30, 2005
1
Dan Jacobs
http://www.modelobjects.com
1
ModelAspectId
String getName()
37
Inside ModelObjectAdapter
public class ModelObjectAdapter {
protected final Object _modelObject;
protected final ModelDescriptor _modelDescriptor;
...
public Object getAspectValue(ModelAspectId aspectId)
throws NoSuchAspectException
{
ModelAspectAdapter modelAspectAdapter =
_modelDescriptor.getModelAspectAdapter(aspectId);
return modelAspectAdapter.getAspectValue(this, _modelObject);
}
public void setAspectValue(ModelAspectId aspectId, Object newValue)
throws PropertyVetoException, NoSuchAspectException
{
ModelAspectAdapter modelAspectAdapter =
_modelDescriptor.getModelAspectAdapter(aspectId);
modelAspectAdapter.setAspectValue(this, _modelObject, newValue);
}
...
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
38
HashTable ModelAspectAdapter
public class HashTableAspectAdapter extends ModelAspectAdapter
{
private String _key;
public HashTableAspectAdapter(String key) {
super(ModelAspectId.forName(key), Object.class);
this._key = key;
}
protected Object getAspectValue
(Object modelObject, ModelObjectAdapter objectAdapter) {
HashTable hashTable = (HashTable) modelObject;
return hashTable.get(_key);
}
protected void setAspectValue
(Object model, Object value, ModelObjectAdapter moa) {
…
}
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
39
Levels of Validation
Text input validation
keystroke at a time, or when losing focus
based on logical type of data, not use
Field level validation
checked on aspect-value assignment
Object level validation
checked on apply, create, delete
Contextual validation
consistency or uniqueness constraints
may be performed externally (e.g. DBMS)
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
40
Validation Failure Feedback
Constrain input to avoid errors
disable things that are not applicable
offer constrained range or set of choices
custom typed chooser components
Change color to indicate problems
color of border, background, label, etc.
Use “what’s wrong” tool-tips
normal tool-tips explain purpose of field
Alert dialog, status line, message log
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
41
Adapters for Edit Components
Abstract Aspect-Editors/Viewers
Generalized “data-bound” controls.
Allow any kind of UI component.
Allow any kind of application model.
Want a uniform abstract interface to:
associate with specific ModelAspectId
initialize from model-aspect-value
notify when edits have been made
provide edited model-aspect-value
provide unapplied view-aspect-value
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
43
ViewAspectAdapter Features
Conversion between model-aspectvalues and view-aspect-values.
Conversion from component-specific
events to uniform change-events.
Customizable enabled-for-edit rules.
One adapter type for each component
type (sometimes more).
Aspect identified by ModelAspectId.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
44
ViewAspectAdapter
EditRule
ViewValueConverter
ModelAspectId
ViewAspectAdapter
void setModelAspectValue(Object)
Object getModelAspectValue()
void setEditable(boolean)
addChangeListener(ChangeListener)
AWT/Swing Component
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
45
Inside JTextFieldAdapter
public class JTextFieldAdapter extends ViewAspectAdapter
implements DocumentListener
{
public JTextFieldAdapter(ModelAspectId modelAspectId,
JTextField textField, EditRule editRule,
ViewValueConverter valueConverter,
ModelEditMediator editMediator) {
super(modelAspectId, editRule, valueConverter, editMediator);
this._textField = textField;
textField.getDocument().addDocumentListener(this);
}
public void setEditable(boolean editable) {
_textField.setEditable(editable);
}
public void setViewAspectValue(Object viewVal) {
_textField.setText((viewVal == null) ? "" : viewVal.toString());
}
public void insertUpdate(DocumentEvent event) {
fireChangeEvent();
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
46
Prefer Renderers to Converters
Many Swing models support Objects
Lists, Trees, Tables, Combo-Boxes, etc.
Can convert between application
models and strings (for example)
May require cumbersome lookup logic
Can render model aspects instead
Swing model can hold the app model
Custom renderer extracts selected info
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
47
Example Custom Cell Renderer
class EmailRecipientCellRenderer extends DefaultListCellRenderer
{
public Component getListCellRendererComponent
(JList list, Object val, int index, boolean select, boolean focus)
{
EmailRecipient recipient = (EmailRecipient) val;
JLabel result = (JLabel) super. getListCellRendererComponent
(list, recipient.getDisplayName(), index, select, focus);
result.setIcon(getDisplayIcon(recipient));
return result;
}
}
JList recipientsList = new JList(allEmailRecipients);
recipientsList.setCellRenderer(new EmailRecipientCellRenderer());
recipientsList.addListSelectionListener(...);
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
48
Connecting Models to Views
Connecting Models to Views
Connect aspect-adapters on each side.
Handle change notifications from view.
Collect edited model-aspect values.
Support apply and reset actions.
Special treatment for new objects.
Perform validation and report errors.
Update the edited model-object.
Notify listeners of changes, errors, etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
50
ModelEditMediator
User Interface
Component
ModelObjectAdapter
Model Aspect
Adapters
ModelEditMediator
View Aspect
Adapters
Edit Rule
GBCACM PDS
April 30, 2005
apply, reset, undo, redo
editModelObject(ModelObjectAdapter)
editModelAsNewObject(ModelObjectAdapter)
addModelEditListener(ModelEditListener)
addModelEditFailureListener(…)
View Value
Converter
Model-Object
Validators
Dan Jacobs
http://www.modelobjects.com
Model
Descriptor
Model-Object
Propagator
51
ModelEditMediator Apply Logic
Apply-action enabled on “new” or change.
Changed aspect-ids collected during edit.
Collect model-aspect-values to assign.
all editable view-aspect-adapters for new model
Assign values through ModelObjectAdapter.
Run model-object validators & propagator.
Undo changes (non-new only) on failure.
Notify edit-listeners, failure-listeners, etc.
On success, reset view and actions.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
52
Edit, Apply, and Validate Logic
ModelObjectAdapter
ModelDescriptor and
ModelAspectAdapters
PropertyChangeEvents and
UndoableModelEditEvents
ModelAspectValidators
ModelEditMediator and
collected model-aspect values
Application Model Object
ViewAspectAdapters
and ViewValueConverters
ModelObjectValidators and
ModelObjectPropagator
Swing Components and
Swing Models
ModelEditListeners and
ModelEditFailureListeners
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
53
Reset, Undo, and Redo Logic
Reset is same as starting over
re-initialize all view-aspect-adapters
clear all pending changes and actions
When new model-aspect values are
assigned, undo information collected
Aspect-id, old-value, new-value
Swing undo framework helps a lot
Undo/Redo information recorded and
managed on a per-object basis
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
54
Multi-Part Forms
Some models have a lot of aspects.
Organize into logical groups of aspects.
Tabbed-folder organization, wizards, …
Complex view, still just one model.
Creation “wizards” delay apply logic.
Dependencies between values of fields.
Want to use same logic for complex
and simple forms.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
55
Summary of Concepts So Far
MVC: Model View Controller
event-listeners, view-independent model
lower-level events to higher-level actions
Class-level metadata and model adapters
uniform, flexible, extensible, powerful
delegation to model-aspect-adapters
Adapters for UI components too
manipulated with model-aspect-values
Edit-Mediator provides common behavior
independent of both model and view
“form-level” controller component
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
56
Application-Level MVC
Application Model
model
state
queries
•
•
•
model •
change
events
Application View
•
•
•
•
view-independent
model-change source
defines app behavior
high-level abstraction
render model aspects
model-change listener
fires initiator-events
organizes models
GBCACM PDS
April 30, 2005
initiator
events
model state
changes and
method calls
App Controller
•
•
view •
control •
initiator-event listener
update app models
use app-model API
select alternative views
Dan Jacobs
http://www.modelobjects.com
57
Application-Level MVC
Initiator-events from apply, reset,
undo, redo, create, delete actions.
Application Models presented to UI
with abstract metadata and adapters.
Almost everything done in Swing is
part of the Application View.
ModelEditMediator provides sound
foundation for Application Controllers.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
58
Type-Specific Model-Edit-Forms
ModelEditForm
getEditTypeKey()
View
Controller
Form Container &
Edit Components
ModelEditMediator
ViewAspectAdapters
GBCACM PDS
April 30, 2005
Model
ModelDescriptor
getEditTypeKey()
ModelAspectAdapters
Dan Jacobs
http://www.modelobjects.com
59
Organizing Models in Views
Model-Oriented Tables & Trees
Organize for Select, Add, Delete
Display view-oriented model aspects
Adapt models to rows, sub-trees, etc.
Import and export of model objects
Use internal representation in application
Queries, filtering, sorting, etc.
Refresh, caching, & performance issues
Concurrent access to external data
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
61
Model-Oriented Tables
ModelListTableModel
Subclass of AbstractTableModel
Manages an ArrayList of model-objects
Model-object per row, aspect per column
Keeps track of sorting state
ModelTableColumnAdapter
Façade and Factory for TableColumn
getColumnValue(Object model, int row)
Helps manage headers, sorting, widths,
custom cell-renderers, etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
62
Using Model-Oriented Tables
ModelTableColumnAdapter firstNameColumnAdapter =
new ExprTableColumnAdapter("firstName",
//
"First Name",
//
false,
//
String.class,
//
40, 120, 400); //
...
ModelTableColumnAdapter[] modelColumnAdapters = {
firstNameColumnAdapter,
lastNameColumnAdapter,
...
};
property name
column header label
editable
type for sorting, etc.
min, normal, max widths
ModelTable attendeesTable =
new ModelTable(SeminarAttendee.class, modelColumnAdapters);
attendeesTable.getSelectionModel().addListSelectionListener(...);
attendeesTable.getModelListTableModel().setContents(getAllAttendees());
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
63
Using Model-Oriented Tables
Create with custom column adapters.
Customize rendering by column.
Register selection listener.
Configure to support column sorting.
Load with collection of model objects.
Add new items to table-model.
Delete items from table model.
Load table from external data source.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
64
Model-Oriented Trees
Each node responsible for computing
its own children, when asked.
ModelTreeNode supports structural
hierarchy of application model objects.
One-level-deep option for getting
expansion indicators right.
Simple, powerful refresh logic based
on child-nodes computation.
Basic tree-cell-renderer configuration:
getNodeIcon(…), getNodeString(…)
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
65
Using Model-Oriented Trees
class JavaClassTreeNode extends ModelTreeNode {
public JavaClassTreeNode(Class javaClass) {
this._javaClass = javaClass;
}
public List computeChildren() {
ArrayList children = new ArrayList();
Method[] methods = _javaClass.getMethods();
for (int i = 0, n = methods.length; i < n; i++)
children.add(new JavaMethodTreeNode(methods[i]);
...
return(children);
}
public Icon getNodeIcon(boolean expanded, boolean selected, …) {
if (_javaClass.isInterface())
return INTERFACE_ICON;
...
}
public String getNodeString(boolean expanded, boolean selected, …) {
return _javaClass.getName();
}
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
66
Coordinating Tables and Forms
TableFormMediator
ModelEditFormManager
selectionChanged(SelectionEvent)
getDeleteRowAction()
getNewInstanceAction()
getEditTypeKey(Object model)
editModelObject(Object model)
createAndEditNewInstance()
ModelTable
GBCACM PDS
April 30, 2005
ModelEditForms
Dan Jacobs
http://www.modelobjects.com
ModelObjectFactory
67
Inside TableFormMediator
public void valueChanged(ListSelectionEvent listSelectionEvent) {
// overrule selection change if changes would be lost
if (_formManager.hasUnappliedChanges() && !handleUnappliedChanges()) {
revertSelection(_editedRowModel);
return;
}
// clear model from current edit-form
EditForm activeForm = _formManager.getActiveEditForm();
if (activeForm != null)
_formManager.editModelObject(null, activeForm.getEditTypeKey());
// get selected model-object from selected row index
int row = _table.getSelectedRow();
if ((row >= 0) && (row < _tableModel.getRowCount())) {
// edit the model-object in the appropriate edit-form
_editedRowModel = _tableModel.getRowModel(row);
Object editTypeKey = _formManager.getEditTypeKey(_editedRowModel);
_formManager.editModelObject(_editedRowModel, editTypeKey);
}
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
68
Application-MVC Controllers
Specify initiator events and sources
Action events, model-edit events, etc.
Specify responses to initiator events
Update application model state
Call application model methods
Import, export, and sync models
Specify what the UI should do next
Translate handled initiator events into
application behavior
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
69
An Example Editor Application
External XML
Internal Java
XJX framework
Several tables
Different Tabs
Many subclasses
Counts in Tabs
Consistent UI
Same behavior
Early feedback
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
70
Model-Oriented Data Flow
TableFormMediator
External
to Java
Model
Translation
EditFormManager
EditForm
External Data
(XML / DBMS)
GBCACM PDS
April 30, 2005
ModelEditMediator
Dan Jacobs
http://www.modelobjects.com
71
Application-Level MVC
Application Model
model
state
queries
•
•
•
model •
change
events
Application View
•
•
•
•
view-independent
model-change source
defines app behavior
high-level abstraction
edit model aspects
render model objects
organize model objects
fire initiator-events
GBCACM PDS
April 30, 2005
initiator
events
model state
changes and
method calls
App Controller
•
•
view •
control •
initiator-event listener
update app models
use app-model API
select alternative views
Dan Jacobs
http://www.modelobjects.com
72
Event-Handling Tips & Patterns
Event Handling Strategies
Configure UI Components with Actions
Self-enabling Actions
Relay-Actions & Action Wrappers
ActionListeners without Inner Classes
Failure Listeners / Exception Handlers
Swing’s Single-Thread Restriction
Long-Running Operations
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
74
Actions as Abstract Initiators
Associate Actions with
Buttons, toolbar-buttons, menu-items, …
When Action enabled, components too
Listeners register with Actions
Same Action fired from different places
Actions can configure UI components
Label, icon, mnemonic, accelerator, …
Extend AbstractAction for even more
Component initialization, enable logic, …
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
75
Self-Enabling Actions
Important to enable/disable Actions
appropriately.
Can use a different tool-tip when
Action not enabled, to say why not.
Views can use central action-manager
with self-enabling Actions.
Encapsulate common enable logic:
Number and types of selections
Selected object state – property values
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
76
RelayActions & Action Wrappers
In a Façade, want to relay events
from within, with façade as source.
May want more control over when
façade’s Actions are enabled.
Chain-of-Responsibility Pattern for
configurable properties.
Chain-reaction of ActionListeners and
ActionEvents.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
77
RelayActions & Action Wrappers
public class RelayAction extends AbstractAction
implements ActionListener, PropertyChangeListener
{
public RelayAction(Action targetAction) {
this._allowEnable = true;
setTargetAction(targetAction); // register self as listener
}
public void propertyChange(PropertyChangeEvent event) {
if ("enabled".equals(event.getPropertyName())
setEnabledInternal();
}
public void setEnabled(boolean allowEnable) {
this._allowEnable = allowEnable;
setEnabledInternal();
}
private void setEnabledInternal() {
super.setEnabled(_allowEnable && _targetAction.isEnabled());
}
...
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
78
Action Listeners
without Inner Classes
Use reflection to make a call to a
method that takes an ActionEvent.
Encapsulate the Method call & other
state in an ActionListener subclass.
Create instances of ActionListener
subclass instead of many subclasses.
Listeners implemented in terms of
methods in classes that uses them.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
79
MethodProxyActionListener
/**
* MethodProxyActionListener adapts any public instance method that
* takes an ActionEvent parameter to the ActionListener interface.
*/
public class MethodProxyActionListener implements ActionListener
{
public MethodProxyActionListener(Object instance, String methodName)
throws NoSuchMethodException
{
_instance = instance;
_method = this.findMethod(instance.getClass(), methodName);
}
public void actionPerformed(ActionEvent event) {
try {
_method.invoke(_instance, new Object[] { event });
} catch (Exception e) {
// InvocationTargetException or IllegalAccessException
rethrowAsRuntimeExceptionOrError(e);
}
}
...
someAction.addActionListener
(new MethodProxyActionListener(handlerObj, "handleSomeAction"));
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
80
Failure-Event Listeners
Usually to report errors, not fix them.
Multiple event-listeners possible.
Failure-event has all the details.
Event may be delivered long after
exception has been handled internally.
Variation: attempt to fix problem
e.g. repair broken connection, try again
listeners should mark the event for retry
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
81
Swing’s Single-Thread Design
Most Swing components and models
are not thread-safe (by design).
Intended to be used and modified
only on event-dispatch-thread.
To update components & models from
another thread, use invokeLater(…).
invokeLater(Runnable) puts a special
kind of event on the event-queue.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
82
Long Running Activities
Use separate, cancelable threads.
Respond promptly to cancel requests.
Disable appropriate parts of UI.
Use events and listeners to notify:
Start and end of thread execution
Use cancelable-thread-manager
Manage threads, coordinate cancel, etc.
Relay events to general listeners
Use invokeLater to handle completion.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
83
Inside CancelableThread – 1
public CancelableThread(Runnable innerRunnable) {
this._innerRunnable = innerRunnable;
}
public void run() {
this.started = true;
Throwable throwable = null;
try {
fireThreadStarted(_innerRunnable, this);
_innerRunnable.run();
}
catch (RuntimeException e) { throwable = e; }
catch (ThreadDeath t)
{ throwable = t; }
finally {
this.completed = true;
// notify about thread completion two different ways
synchronized (this) { this.notify(); }
fireThreadCompleted(_innerRunnable, this, throwable);
}
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
84
Inside CancelableThread – 2
public void cancel() {
_cancelled = true;
this.interrupt();
}
// mark thread as cancelled
// interrupt active wait calls
public boolean terminate(int maxWaitMillis, boolean forceTermination) {
if (!this.isAlive())
return true;
this.cancel();
// request termination politely
try {
this.join(maxWaitMillis);
// wait for termination or timeout
}
catch (InterruptedException e) {
// safe to ignore here
}
if (!this.isAlive())
return true;
if (forceTermination)
this.stop();
// force hostile termination
return false;
}
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
85
Swing Layout Manager Tips
Swing Layout Manager Basics
Purpose and rationale
Layout Manager Conceptual Model
Relative 2D constraints
Constraints propagate bottom-up
Layout Roles & Responsibilities
Important API
Creating new Layout Managers
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
87
Layout Manager Rationale
Best (maybe only) way to build crossplatform user interfaces.
Size and shape of components based
on configured properties.
Labels, icons, borders, fonts, children, …
Containers should try to respect
preferred sizes of child components.
Expressing multiple levels of
constraints sounds harder than it is.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
88
Expressing Systems of Constraints
in a 2-Dimensional Space
Layout Managers solve constraints.
Flexible constraints usually relative.
Easy to learn how to set the table:
Absolute
Absolute
Absolute
Absolute
relative
relative
relative
relative
positioning
(preferred) sizes
spacing
orientation
Good layout managers add clarity.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
89
Users of Layout Managers
Programmers
Code clarity and succinctness
Choice of special-purpose alternatives
Able to collaborate with other objects
Visual Layout Tools
General-purpose visual metaphor
Visual representation of constraints
Often too complex to use by hand
Special-purpose layouts can wrap and
delegate to general-purpose layouts.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
90
Setting the Table
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
91
LayoutManager Responsibilities
Help compute Container’s preferred size
In terms of components’ preferred sizes
In terms of insets, spacing, is-visible
In terms of specified constraints (e.g. top)
Assign sizes and positions to components
Using same constraints as above
Don’t change container’s size or position
Components provide own preferred sizes
Frequently using their own layout managers
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
92
Phases of Container Layout
Compute Window’s preferred size
Compute child preferred sizes (recursive)
Combine using window’s layout manager
Assign the Window’s size and position
Layout each child component
Assign size and position to each child
Ask the child to perform layout on itself
Layout each child component
Assign size and position to each child
Ask the child to perform layout on itself
…
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
93
Layout Roles and Methods
Component
LayoutManager
Dimension getPreferredSize()
Insets getInsets()
Dimension preferredLayoutSize(Container)
void layoutContainer(Container)
implements
extends
Container / JComponent
void doLayout()
Component getComponent(int index)
void revalidate()
GBCACM PDS
April 30, 2005
layout
Concrete LayoutManager
Dan Jacobs
http://www.modelobjects.com
94
Import Swing Layout API
Important LayoutManager methods:
Dimension preferredLayoutSize(Container)
void layoutContainer(Container)
void addLayoutComponent(String*, Component)
void removeLayoutComponent(Component)
Container methods (and others):
void setLayout(LayoutManager)
void setBounds(int x, int y, int w, int h)
void doLayout()
Dimension getPreferredSize()
int getVisibleRowCount() (in JList)
invalidate(), validate(), revalidate()
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
95
Containers and Layout Managers
public class Container extends Component {
public void setLayout(LayoutManager layout) {
this._layout = layout;
}
public Dimension getPreferredSize() {
return _layout.preferredLayoutSize(this);
}
public void doLayout() {
_layout.layoutContainer(this);
}
…
public class AnyLayout implements LayoutManager {
public Dimension preferredLayoutSize(Container container) {
… container.getComponent(i).getPreferredSize() …
}
public void layoutContainer(Container container) {
Dimension containerSize = container.getSize();
Insets containerInsets = container.getInsets();
…
child.setBounds(childX, childY, childWidth, childHeight);
…
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
96
Swing Layout Rules of Thumb
Only LayoutManagers call setBounds()
(except for top-level windows).
Almost never call setPreferredSize().
Implement Scrollable as appropriate.
Break things down into simpler parts.
Use sub-containers with their own layouts
Encapsulate common uses of complex
layout managers.
revalidate() when composition changes.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
97
Custom Layout Managers
Container-owned or sharable.
Compute preferred-size abstractly.
Container’s current size doesn’t matter.
Use preferred sizes of current children.
Don’t forget the container’s insets.
Layout container concretely.
Don’t change the container’s size, position, etc.
Assign sizes and positions to all children.
Don’t invalidate layout of anything else.
Don’t forget the container’s insets.
How to handle excess/insufficient space.
Stretch, align, squash, abbreviate, etc.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
98
Summary and Review
User interfaces are for expressing
intentions and maintaining confidence.
Check for and report success & problems.
Mature user interfaces exhibit two
levels of Model-View-Controller.
Application models and controllers should
be almost independent of user interface.
Good frameworks maximize reuse and
minimize effort.
Complex operations same for many apps.
Roles the same for many apps.
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
99
Questions and Discussion
GBCACM PDS
April 30, 2005
Dan Jacobs
http://www.modelobjects.com
100