100
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

Model-Oriented Architectures and Frameworks for Swing-Based User Interfaces Dan Jacobs [email protected] President and founder, ModelObjects Group

Embed Size (px)

Citation preview

  • Slide 1

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 Slide 2 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 Slide 3 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 Slide 4 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 Slide 5 Overview of AWT and Swing Slide 6 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 Slide 7 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 Slide 8 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 System and Window System Application Code J2SE Many other standard extensions Slide 9 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. Slide 10 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 doesnt see lightweight comps Slide 11 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. Slide 12 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 Slide 13 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 Slide 14 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); Slide 15 Object-Oriented Design Patterns and Frameworks Slide 16 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. Slide 17 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 Dont take it too far some things are not independent of each other Slide 18 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. Slide 19 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(); NewPlugAdapter implements NewPlugProvider NewPlug getNewPlug() { } private OldSocket _oldSocket; references implements class NewSocket plugIn( NewPlug ); references Slide 20 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 Swings implementation: Event sources follow naming conventions Listeners notified by synchronous calls Some event objects are modifiable Slide 21 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-sourceimplements event Slide 22 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 Slide 23 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); Slide 24 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 dont have to be large or complex the fewer roles, the better. Can offer best kind of code reuse. Slide 25 Model View Controller Pattern Click Here A Frequently Misunderstood Pattern Slide 26 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. Slide 27 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 gesture events model state queries view control Slide 28 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. Slide 29 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. Slide 30 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. Slide 31 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()); } Slide 32 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 Slide 33 Model-Oriented Architectures Model-Oriented Application = Model Objects + Coordinated Uses of Model Objects Slide 34 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 Slide 35 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. Slide 36 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. Slide 37 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 Application Model Object Instance Application Model Object Class (or other metadata) n n 1 1 11 11 11 n 1 class level information instance level Slide 38 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 38 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); }... } Slide 39 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 39 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) { } Slide 40 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) Slide 41 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 whats wrong tool-tips normal tool-tips explain purpose of field Alert dialog, status line, message log Slide 42 Adapters for Edit Components Slide 43 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 Slide 44 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. Slide 45 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 45 ViewAspectAdapter void setModelAspectValue(Object) Object getModelAspectValue() void setEditable(boolean) addChangeListener(ChangeListener) EditRuleModelAspectIdViewValueConverter AWT/Swing Component Slide 46 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 46 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(); } Slide 47 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 Slide 48 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(...); Slide 49 Connecting Models to Views Slide 50 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. Slide 51 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 51 ModelEditMediator ModelObjectAdapter View Aspect Adapters Model Aspect Adapters Model Descriptor Model-Object Propagator Model-Object Validators Edit Rule View Value Converter User Interface Component ModelEditMediator apply, reset, undo, redo editModelObject(ModelObjectAdapter) editModelAsNewObject(ModelObjectAdapter) addModelEditListener(ModelEditListener) addModelEditFailureListener() Slide 52 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. Slide 53 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 53 Edit, Apply, and Validate Logic Swing Components and Swing Models ViewAspectAdapters and ViewValueConverters ModelEditMediator and collected model-aspect values PropertyChangeEvents and UndoableModelEditEvents ModelObjectAdapter ModelDescriptor and ModelAspectAdapters ModelObjectValidators and ModelObjectPropagator Application Model Object ModelEditListeners and ModelEditFailureListeners ModelAspectValidators Slide 54 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 Slide 55 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. Slide 56 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 Slide 57 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 and method calls initiator events model state queries view control Slide 58 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. Slide 59 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 59 Type-Specific Model-Edit-Forms ModelEditForm getEditTypeKey() Form Container & Edit Components ModelEditMediator ModelDescriptor getEditTypeKey() ModelAspectAdaptersViewAspectAdapters ViewController Model Slide 60 Organizing Models in Views Slide 61 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 Slide 62 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 Faade and Factory for TableColumn getColumnValue(Object model, int row) Helps manage headers, sorting, widths, custom cell-renderers, etc. Slide 63 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()); Slide 64 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. Slide 65 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() Slide 66 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 66 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(); } Slide 67 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() ModelEditFormsModelObjectFactory Slide 68 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); } Slide 69 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 Slide 70 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 Slide 71 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 71 Model-Oriented Data Flow External Data (XML / DBMS) External to Java Model Translation TableFormMediator EditFormManager EditForm ModelEditMediator Slide 72 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 and method calls initiator events model state queries view control Slide 73 Event-Handling Tips & Patterns Slide 74 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 Swings Single-Thread Restriction Long-Running Operations Slide 75 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, Slide 76 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 Slide 77 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 77 RelayActions & Action Wrappers In a Faade, want to relay events from within, with faade as source. May want more control over when faades Actions are enabled. Chain-of-Responsibility Pattern for configurable properties. Chain-reaction of ActionListeners and ActionEvents. Slide 78 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 78 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()); }... Slide 79 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. Slide 80 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")); Slide 81 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 Slide 82 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 82 Swings 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. Slide 83 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. Slide 84 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 84 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); } Slide 85 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 85 Inside CancelableThread 2 public 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; } Slide 86 Swing Layout Manager Tips Slide 87 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 Slide 88 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. Slide 89 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. Slide 90 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. Slide 91 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 91 Setting the Table Slide 92 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 92 LayoutManager Responsibilities Help compute Containers 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 Dont change containers size or position Components provide own preferred sizes Frequently using their own layout managers Slide 93 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 93 Phases of Container Layout Compute Windows preferred size Compute child preferred sizes (recursive) Combine using windows layout manager Assign the Windows 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 Slide 94 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 Slide 95 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() Slide 96 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 96 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); Slide 97 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. Slide 98 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 98 Custom Layout Managers Container-owned or sharable. Compute preferred-size abstractly. Containers current size doesnt matter. Use preferred sizes of current children. Dont forget the containers insets. Layout container concretely. Dont change the containers size, position, etc. Assign sizes and positions to all children. Dont invalidate layout of anything else. Dont forget the containers insets. How to handle excess/insufficient space. Stretch, align, squash, abbreviate, etc. Slide 99 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. Slide 100 GBCACM PDS April 30, 2005 Dan Jacobs http://www.modelobjects.com 100 Questions and Discussion