1k likes | 1.16k Views
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
E N D
Model-Oriented Architectures and Frameworks for Swing-Based User Interfaces Dan Jacobsdjacobs@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 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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
Swing (javax.swing and sub-packages) AWT Lightweight Support / Graphics 2D AWT Component & Container Framework J2SE Core Java Packages JVM and native method libraries Platform Operating Systemand Window System AWT/Swing Software Layers Many other standard extensions Application Code J2SE Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
Black-Box Component Use JButton button1 = new JButton("Press Me"); button1.setEnabled(false); buttonPanel.add(button1); ActionListener bh = new ButtonHandler(this); button1.addActionListener(bh); Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
Object Adapter Design Pattern class NewSocket plugIn(NewPlug); … interface NewPlugProvider NewPlug getNewPlug(); … references implements class OldHairDryer OldPlug getPlug();boolean getBlowerOn(); setBlowerOn(boolean);… NewPlugAdapterimplements NewPlugProvider NewPlug getNewPlug() { … } private OldSocket _oldSocket; … references Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
Event Listener Design Pattern FooEventSource addFooListener(FooListener) removeFooListener(FooListener) fireFooEvent1() fireFooEvent2() FooListener handleFooEvent1(FooEvent) handleFooEvent2(FooEvent) listeners event-source implements FooEvent getSource() getEventType() getEventDetails() ConcreteFooListener handleFooEvent1(FooEvent) handleFooEvent2(FooEvent) event Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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); Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
Model View Controller Pattern • Model • view-independent • object encapsulation • change-event source • first-class object model state queries model change events model state changes • 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 gesture events view control Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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); } } Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
Model Metadata Framework ModelObjectAdapter Object getAspectValue(ModelAspectId) void setAspectValue(ModelAspectId, Object) Object getModelObject() void validateModel() throws ModelValidationException Application Model Object Instance instance level 1 1 n n modelDescriptor 1 1 ModelDescriptor ModelObjectAdapter makeModelObjectAdapter(Object) ModelAspectAdapter getModelAspectAdapter(ModelAspectId) void addModelObjectValidator(ModelObjectValidator) void validateModel(ModelObjectAdapter) Application Model Object Class (or other metadata) 1 1 1 class level information modelAspectAdapters n ModelAspectAdapter* Object getAspectValue(ModelObjectAdapter)* void setAspectValue(ModelObjectAdapter, Object)* Class getModelAspectType() boolean isReadOnlyAspect() ModelAspectId String getName() 1 1 Dan Jacobs http://www.modelobjects.com
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); } ... } Dan Jacobs http://www.modelobjects.com
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) { … } } Dan Jacobs http://www.modelobjects.com
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) Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com
ViewAspectAdapter EditRule ViewValueConverter ModelAspectId ViewAspectAdapter void setModelAspectValue(Object) Object getModelAspectValue() void setEditable(boolean) addChangeListener(ChangeListener) AWT/Swing Component Dan Jacobs http://www.modelobjects.com
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(); } Dan Jacobs http://www.modelobjects.com
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 Dan Jacobs http://www.modelobjects.com
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(...); Dan Jacobs http://www.modelobjects.com
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. Dan Jacobs http://www.modelobjects.com