Model-Oriented Architectures and Frameworks for Swing-Based User Interfaces

Preview:

DESCRIPTION

Model-Oriented Architectures and Frameworks for Swing-Based User Interfaces. Dan Jacobs djacobs@modelobjects.com President and founder, ModelObjects Group http://www.modelobjects.com President and founder, JPlates Inc. http://www.jplates.com Chairman, Boston ACM WebTech Group - PowerPoint PPT Presentation

Citation preview

Model-Oriented Architectures and Frameworks for

Swing-Based User Interfaces

Dan Jacobsdjacobs@modelobjects.com

President and founder, ModelObjects Grouphttp://www.modelobjects.com

President and founder, JPlates Inc.http://www.jplates.com

Chairman, Boston ACM WebTech Grouphttp://www.acm.org/chapters/webtech

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

2

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

3

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

4

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

Overview of AWT and Swing

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

6

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

7

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

8

AWT/Swing Software Layers

Swing (javax.swing and sub-packages)

J2SE Core Java Packages

JVM and native method libraries

AWT Lightweight Support / Graphics 2D

AWT Component & Container Framework

Platform Operating Systemand Window System

ApplicationCodeJ2SE

Many other standard extensions

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

9

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

10

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

11

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

12

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

13

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

14

Black-Box Component Use

JButton button1 = new JButton("Press Me");

button1.setEnabled(false);

buttonPanel.add(button1);

ActionListener bh = new ButtonHandler(this);

button1.addActionListener(bh);

Object-Oriented Design Patterns and Frameworks

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

16

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

17

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

18

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

19

Object Adapter Design Pattern

class OldHairDryer

OldPlug getPlug();boolean getBlowerOn();setBlowerOn(boolean);

interface NewPlugProvider

NewPlug getNewPlug();…

NewPlugAdapterimplements NewPlugProvider

NewPlug getNewPlug() { … }private OldSocket _oldSocket;

references

implements

class NewSocket

plugIn(NewPlug);…

references

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

20

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

21

Event Listener Design Pattern

FooEventSource

addFooListener(FooListener)removeFooListener(FooListener)

fireFooEvent1()fireFooEvent2()

FooListener

handleFooEvent1(FooEvent)handleFooEvent2(FooEvent)

listeners

FooEvent

getSource()getEventType()

getEventDetails()

ConcreteFooListener

handleFooEvent1(FooEvent)handleFooEvent2(FooEvent)

event-source implements

event

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

22

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

23

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

24

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.

Model View Controller Pattern

<a href="dosomething?foo=3&bar=no">Click Here</a>

A Frequently Misunderstood Pattern

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

26

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

27

Model View Controller Pattern

Model• view-independent• object encapsulation• change-event source• first-class object

View• renders model info• change-event listener• gesture-event source• first-class object

Controller• gesture-event listener• updates models• selects alternative views• first-class object

model change events

model state changes

gestureevents

model state

queries

view control

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

28

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

29

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

30

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

31

Direct Editing Example

class HtmlEmailCheckboxWatcher implements ItemListener { public void itemStateChanged(ItemEvent event) { boolean selected = (event.getStateChange() == ItemEvent.SELECTED); _recipient.setPrefersHtmlEmail(selected); } }

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()); … }

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

32

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

Model-Oriented Architectures

Model-Oriented Application = Model Objects + Coordinated Uses of Model Objects

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

34

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

35

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

36

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

37

Model Metadata Framework

ModelObjectAdapter

Object getAspectValue(ModelAspectId)void setAspectValue(ModelAspectId, Object)Object getModelObject()void validateModel() throws ModelValidationException

ModelDescriptor

ModelObjectAdapter makeModelObjectAdapter(Object)ModelAspectAdapter getModelAspectAdapter(ModelAspectId)void addModelObjectValidator(ModelObjectValidator)void validateModel(ModelObjectAdapter)

ModelAspectAdapter*

Object getAspectValue(ModelObjectAdapter)*void setAspectValue(ModelObjectAdapter, Object)*Class getModelAspectType()boolean isReadOnlyAspect()

ModelAspectId

String getName()

modelDescriptor

modelAspectAdapters

ApplicationModel ObjectInstance

ApplicationModel Object

Class(or other metadata)

n

n

1

1

1 1

1 1

11

n

1

class

level in

form

ati

on

inst

an

ce level

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

38

Inside ModelObjectAdapterpublic 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

39

HashTable ModelAspectAdapterpublic 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

40

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

41

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

Adapters for Edit Components

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

43

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

44

ViewAspectAdapter Features

Conversion between model-aspect-values 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

45

ViewAspectAdapter

ViewAspectAdapter

void setModelAspectValue(Object)Object getModelAspectValue()void setEditable(boolean)addChangeListener(ChangeListener)

EditRule ModelAspectIdViewValueConverter

AWT/Swing Component

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

46

Inside JTextFieldAdapterpublic 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

47

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

48

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(...);

Connecting Models to Views

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

50

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

51

ModelEditMediator

ModelObjectAdapter

View AspectAdapters

Model AspectAdapters

ModelDescriptor

Model-ObjectPropagator

Model-ObjectValidators

Edit RuleView ValueConverter

User InterfaceComponent

ModelEditMediatorapply, reset, undo, redoeditModelObject(ModelObjectAdapter)editModelAsNewObject(ModelObjectAdapter)addModelEditListener(ModelEditListener)addModelEditFailureListener(…)

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

52

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

53

Edit, Apply, and Validate Logic

Swing Components andSwing Models

ViewAspectAdaptersand ViewValueConverters

ModelEditMediator andcollected model-aspect values

PropertyChangeEvents andUndoableModelEditEvents

ModelObjectAdapterModelDescriptor andModelAspectAdapters

ModelObjectValidators andModelObjectPropagator

Application Model Object

ModelEditListeners andModelEditFailureListeners

ModelAspectValidators

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

54

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

55

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

56

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

57

Application-Level MVC

Application Model• view-independent• model-change source• defines app behavior• high-level abstraction

Application View• render model aspects• model-change listener• fires initiator-events• organizes models

App Controller• initiator-event listener• update app models• use app-model API• select alternative views

model change events

model state changes andmethod calls

initiatorevents

model state

queries

view control

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

58

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

59

Type-Specific Model-Edit-Forms

ModelEditForm

getEditTypeKey()

Form Container &Edit Components

ModelEditMediatorModelDescriptor

getEditTypeKey()

ModelAspectAdaptersViewAspectAdapters

View Controller Model

Organizing Models in Views

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

61

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

62

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

63

Using Model-Oriented Tables

ModelTableColumnAdapter firstNameColumnAdapter = new ExprTableColumnAdapter("firstName", // property name "First Name", // column header label false, // editable String.class, // type for sorting, etc. 40, 120, 400); // min, normal, max widths...ModelTableColumnAdapter[] modelColumnAdapters = { firstNameColumnAdapter, lastNameColumnAdapter, ...};

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

64

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

65

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

66

Using Model-Oriented Treesclass 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

67

Coordinating Tables and Forms

TableFormMediator

selectionChanged(SelectionEvent)getDeleteRowAction()

getNewInstanceAction()

ModelTable

ModelEditFormManager

getEditTypeKey(Object model)editModelObject(Object model)

createAndEditNewInstance()

ModelEditForms ModelObjectFactory

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

68

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

69

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

70

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

71

Model-Oriented Data Flow

External Data(XML / DBMS)

Externalto JavaModel

Translation

TableFormMediator

EditFormManager

EditForm

ModelEditMediator

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

72

Application-Level MVC

Application Model• view-independent• model-change source• defines app behavior• high-level abstraction

Application View• edit model aspects• render model objects• organize model objects• fire initiator-events

App Controller• initiator-event listener• update app models• use app-model API• select alternative views

model change events

model state changes andmethod calls

initiatorevents

model state

queries

view control

Event-Handling Tips & Patterns

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

74

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

75

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

76

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

77

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

78

RelayActions & Action Wrapperspublic 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

79

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

80

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

81

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

82

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

83

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

84

Inside CancelableThread – 1public 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

85

Inside CancelableThread – 2public void cancel() { _cancelled = true; // mark thread as cancelled this.interrupt(); // 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;}

Swing Layout Manager Tips

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

87

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

88

Layout Manager Rationale Best (maybe only) way to build cross-

platform 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

89

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 relative positioning Absolute relative (preferred) sizes Absolute relative spacing Absolute relative orientation

Good layout managers add clarity.

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

90

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

91

Setting the Table

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

92

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

93

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

94

Layout Roles and Methods

Component

Dimension getPreferredSize()Insets getInsets()

Container / JComponent

void doLayout()Component getComponent(int index)

void revalidate()

LayoutManager

Dimension preferredLayoutSize(Container)void layoutContainer(Container)

Concrete LayoutManager

extends implements

layout

GBCACM PDS April 30, 2005

Dan Jacobs http://www.modelobjects.com

95

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

96

Containers and Layout Managerspublic 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

97

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

98

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

99

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

100

Questions and Discussion

Recommended