Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto...

51
How to design a UI class library Lightweight Java Meetup, 25.11.2015 Johannes Döbler [email protected]

Transcript of Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto...

Page 1: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to design a

UI class library

Lightweight Java Meetup, 25.11.2015

Johannes Döbler

[email protected]

Page 2: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Developer virtues

CraftsmanshipWrite clean and efficient code

AlgorithmicFind and implement solutions for problems

ArchitecturalAssemble components to complex systems

UI design Make it easy for end users to use an application

API designMake it easy for developers to use a library

Language designInvent expressive and concise languages, syntax

Page 3: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Agenda

(1) The story behind the talk

(2) Library and API design

(3) Code examples

Page 4: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Project: Port a huge desktop-based information

system to the web (modern SPA, RIA)

500+ database tables, 1000+ forms and dialogs

The story behind the talk

Which web framework?

Found two candidates:

Liked development model and architecture…

Page 5: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

The story behind the talk

panel.add(new Button("OK")).addClickListener(

event -> log("Clicked"));

{create:"button", id:"f451", text:"OK",...}

<button id="f451">OK</button>

{event:"click", id:"f451"}

panel.add(new Button("OK")).addClickListener(

event -> log("Clicked"));

Programming model:

Page 6: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

The story behind the talk

… then we built proof-of-concept prototypes ̶

and were shaken, not stirred…

Framework Friction Alert!

… and decided to write

an own framework

for the candidate

architecture (yes!)

Page 7: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

The story behind the talk

UI

Servlet Container

Databinding I10N

↓ Protocol ↑

Protocol Interpreter

Event Handler Up/Download Utilities

API

JSON

JS

Java

Servlet Layer

Protocol Interpreter

thisthisthisthis talktalktalktalk

JQuery

Page 8: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Agenda

(1) The story behind the talk

(2) Library and API design

(3) Code examples

Page 9: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

API qualities

Allows good client code:simple, short, elegant, fast, fun

Implied library qualities:expressive, intuitive, coherent, extensible

Interface designers must take responsibility.

Clients — the people using your interfaces — are trying to

do a good job. They want things to behave correctly.

That being the case, if clients make a mistake

when using your interface, it's your fault.

Scott Myershttp://www.aristeia.com/Papers/IEEE_Software_JulAug_2004_revised.htm

Page 10: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Simply start

FADE IN...

public class Button {...

public class TextField {...

public class Table {...

How to be come a better screenwriter?

Get some paper, put it in a typewriter,

type FADE IN and keep typing.

Peter »Columbo« Falk

Page 11: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Have a guiding idea

UI objects render to HTML element(s)

TextField field

<input type=" " pattern=" ">

public class TextField {

public enum Type { TEXT,EMAIL,URL,... };

public void setType(Type type);

public void setPattern(String pattern);

...

}

Page 12: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Build on prior art

copy , improve , discard , innovate

Java: AWT, Swing, SWT, JavaFX

Web: GWT, Vaadin

Cross-PF: QT

Windows: MVC, Windows Forms (.net)

Linux: KDE, Gnome

JS: JQueryUI, ExtJS, KendoUI

Mobile: Android, iOS

https://en.wikipedia.org/wiki/List_of_widget_toolkits

Page 13: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Know the design patterns

Composite

Observer

Builder, Factory

Decorator, Command

Model-View-Controller

Design Patterns:Elements of Reusable Object-Oriented Software1994

Gamma E., Helm R., Johnson R., Vlissides, J.

Page 14: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Build minimal and complete interfaces*

Javadoc - Methods inherited from class java.awt.Componentaction, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, deliverEvent, disable, disableEvents, dispatchEvent, doLayout, enable, enable, enableEvents, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getAlignmentX, getAlignmentY, getBackground, getBaseline, getBaselineResizeBehavior, getBounds, getBounds, getColorModel, getComponentAt, getComponentAt, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeys, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMinimumSize, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPeer, getPreferredSize, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusCycleRoot, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isOpaque, isPreferredSizeSet, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paint, paintAll, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, processMouseWheelEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removeNotify, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, requestFocus, requestFocusInWindow, requestFocusInWindow, reshape, resize, resize, revalidate, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeys, setFocusTraversalKeysEnabled, setFont, setForeground, setIgnoreRepaint, setLocale, setLocation, setLocation, setMaximumSize, setMinimumSize, setName, setPreferredSize, setSize, setSize, setVisible, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle, update, validate

No further questions your honor, harharhar, … *Scott Myers

Page 15: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

A camel is a horse designed by committee

View your design through the eyes of a user.

Eat your own dog food. Write a real-life, non trivial application using the library.

And then adjust the design. Rinse and repeat.

Page 16: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Refactor without mercy

public class Div^H^H^H Panel {

}

Create class. Delete. Restore. Rename. Delete.

Revert. Can‘t sleep. Rename again.

(…to be continued)

���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ���� ����

Page 17: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Agenda

(1) The story behind the talk

(2) Library and API design

(3) Code examples

Page 18: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Composite pattern

UI components build a tree.

Composite pattern: Allows to treat a group (tree) of

objects in the same way as a single instance of an object.

Common operations, tree traversal, content

Variant 1: Variant 2:

Page 19: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Composite pattern

Widget base class: Tree traversal, content

public abstract class Widget {

public Widget getParent()

public int getChildCount()

public Widget getChild(int index)

public void add(Widget child)

public void empty()

public void delete()

...

Page 20: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Composite pattern

Widget base class: Common operations

...

public boolean isVisible()

public void setVisible(boolean)

public boolean isDisabled()

public void setDisabled(boolean)

public void setEnabled(boolean)

// more common operations

}

public class Button extends Widget {...

Page 21: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to set a button label?

Button ok = new Button();

ok.setText("OK");

Button ok = new Button("OK");

Create a simple OK button

Page 22: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to set a button label?

javax.swing.JButton:

JButton(String)

JButton(Icon)

JButton(String, Icon)

setText(String)

setIcon(Icon)

setRolloverIcon(Icon)

setSelectedIcon(Icon)

setRolloverSelectedIcon(Icon)

setIconTextGap(int)

Combinatorial

EXPLOSION

ALERT

!

Create a button with an icon

Button ok = new Button(?);

button.setText(?);

Page 23: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to set a button label?

<button>OK</button>

<button>

<span class="glyphicon glyphicon-download"></span>

Download

</button>

Button ok = new Button();

ok.setText("OK");

Button dl = new Button();

dl.add(Glyphicon.download);

dl.addText("Download");

Create buttons like

declared indeclared indeclared indeclared in

widget base classwidget base classwidget base classwidget base class

HTML mixed contentHTML mixed contentHTML mixed contentHTML mixed content

Page 24: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to set a … label?

Create widgets like etc.

<input type="submit" name="OK" value="OK" src="...">

<select>

<option value="1">Uno</option

<option value="2">Due</option

<option value="3">Tre</option

</select>

HTML is not perfect:

Page 25: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

How to set a button label?

Why AWT/Swing /SWT/Javafx/etc fail...

awt.Button

swt.Button

awt.Component

swt.Widget

javafx.Node

awt.Container

swt.Composite

swing.JComponent

swing.JButton

javafx.Parent

javafx.Button

Page 26: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Styles and layout

positionpositionpositionposition widthwidthwidthwidth

heightheightheightheightcolorcolorcolorcolor

fontfontfontfont

borderborderborderborder

marginmarginmarginmargin

backgroundbackgroundbackgroundbackgroundpaddingpaddingpaddingpaddingspacingspacingspacingspacing

minminminmin----maxmaxmaxmax----prefsizeprefsizeprefsizeprefsize

orientationorientationorientationorientation

animationanimationanimationanimation

hoverhoverhoverhover

cursorcursorcursorcursor alignmentalignmentalignmentalignment

Page 27: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Styles and layout

org.eclipse.swt.widgets.Control

Style

getStyle()

getBorderWidth()

setBackground(Color*)

setBackgroundImage(Image*)

setCursor(Cursor*)

setFont(Font*)

setForeground(Color*)

setOrientation(int)

setTextDirection(int)

* extends

org.eclipse.swt.graphics.Resource

Position and size

setBounds(int,int,int,int)

setBounds(Rectangle)

setLayoutData(Object)

setLocation(int,int)

setLocation(Point)

setSize(int,int)

setSize(Point)

Layout

computeSize(int,int,boolean)

pack()

setRedraw()

update()

LayoutManagerFAT API ALERT!

Page 28: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Styles and layout

CSS to the rescue (HTML, JavaFX)

<button font="..."></button>

<button class="btn btn-default">Default</button><button class="btn btn-primary">Primary</button>

...

Widget widget = ...

widget.css("btn", "btn-primary"); // use constants

widget.css().toggle("required"); // use constants

widget.style("valign", "top"); // use constants

widget.style().width().percent(85);

Page 29: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

125

Fluent API

Keystrokes matter...

Button button = new Button();

button.addClickListener(...);

button.add(Gylphicon.OK);

button.addText("OK");

button.css(Css.BTN);

Requires consistency

Problems with hierarchies:

Method cascading:

(Smalltalk, Dart)

Widget Widget.css(…)

Button Button.addClickListener(…)

void Widget.css(…)

void Button.addClickListener(…)

Button button = new Button()

..addClickListener(...)

..add(Gylphicon.OK)

..addText("OK")..css(Css.BTN);

Method chaining:

97Button button = new Button()

.addClickListener(...)

.add(Gylphicon.OK)

.addText("OK").css(Css.BTN);

Page 30: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Builder pattern

again save same some keystrokes

... and improve readability

Table table = new Table();

table.addColumn();

table.addColumn().width(10); // more columns

TableRow row = table.addRow();

row.addCell("Street").setAlign(align.right);

row.addCell();

row.addCell().add(new TextField());

// 8 more cells to go

TableBuilder tb = new TableBuilder("[right]10[50]3[]");

tb.cell("Street").cell(2).textField();

tb.cell("ZIP / City")

tb.cell().textField();

tb.cell().textField();

tb.cell("Country").cell(2).select();

definedefinedefinedefine

columnscolumnscolumnscolumns

just push cellsjust push cellsjust push cellsjust push cellsinspired by http://miglayout.com/

Page 31: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Edit Widgets: API

javax.swing

JTextField, void setText(String)JTextArea String getText()

JCheckBox, void setSelected(boolean)

JRadioButton boolean isSelected()

JComboBox<E> void setSelectedItem(Object)

Object getSelectedItem()

JList<E> void setSelectedValue(Object)

E getSelectedValue()

Naming Confusion ALERT!

Page 32: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Edit Widgets: API

Control := common base class for edit widgets

public abstract class Control<VALUE> extends Widget {

public void setValue(VALUE);

public VALUE getValue();

public boolean isChanged();

public void setChanged(boolean);

public boolean isRequired();

public void setRequired(boolean);

public boolean isInvalid();

public void setInvalid(boolean, String);

public void addValueListener(ValueListener);

public void removeValueListener(ValueListener);

}

Page 33: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Edit Widgets: Type support

from the having-a-hard-time-department

How to enter number/date/time values?

import com.vaadin.ui.TextField;

TextField field = new TextField();

field.setConverter(Integer.class);

String s = field.getValue();

try {

Integer n = (Integer)field.getConvertedValue();

} catch (ConversionException e) {

Notification.show("Could not convert value");

}

https://vaadin.com/wiki/-/wiki/Main/Creating+a+TextField+for+Integer+only+input+when+not+using+a+data+source

Page 34: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Edit Widgets: Type support

Control implementations for common simple types

class TextField extends Control<String>

class DoubleField extends Control<Double>

class IntField extends Control<Integer>

class DateField extends Control<Date>

class Select<VALUE> extends Control<VALUE>

class List<VALUE> extends Control<VALUE>

class Checkbox<VALUE> extends Control<VALUE>

locale dependentlocale dependentlocale dependentlocale dependent

jqueryjqueryjqueryjquery pluginspluginspluginsplugins::::

autonumericautonumericautonumericautonumeric,,,,

datepickerdatepickerdatepickerdatepicker,,,,

timentrytimentrytimentrytimentry,,,,

chosenchosenchosenchosen, , , , …

Page 35: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Edit Widgets: Extensions

More fun with controls...

InlineEditor<Address>

SearchLookup<Company>

DateTimeField

Page 36: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Class hierarchy

Building classifications is hard…

From an ancient chinese encyclopedia:

Tiere unterteilen sich in a) Tiere, die dem Kaiser

gehören, b) einbalsamierte Tiere, c) gezähmte, d)

Milchschweine, e) Sirenen, f) Fabeltiere, g) herrenlose

Hunde, h) in diese Gruppierung gehörige, i) die sich

wie Tolle gebärden, k) die mit einem ganz feinen Pinsel

aus Kamelhaar gezeichnet sind, l) et cetera,

m) die den Wasserkrug zerbrochen haben, n) die von

weitem wie Fliegen aussehen.

Jorge Luis Borges, Die analytische Sprache des John Wilkins

Page 37: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Class hierarchy

Inherit API or implementation? How deep?

javafx.scene.Node base component classbase component classbase component classbase component class

javafx.scene.Parent base composite classbase composite classbase composite classbase composite class

javafx.scene.layout.Region base class for UI controlsbase class for UI controlsbase class for UI controlsbase class for UI controls

javafx.scene.control.Control base class for UI controlsbase class for UI controlsbase class for UI controlsbase class for UI controls

javafx.scene.control.Labeled has textual contenthas textual contenthas textual contenthas textual content

javafx.scene.control.ButtonBase buttonbuttonbuttonbutton----like controlslike controlslike controlslike controls

javafx.scene.control.Button

javafx.scene.control.Checkbox

javafx.scene.control.Hyperlink

javafx.scene.control.MenuButton

javafx.scene.control.ToggleButton

javafx.scene.control.RadioButton

Page 38: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Class hierarchy

Inherit API or implementation? How deep?

web.ui.Widget base widgetbase widgetbase widgetbase widget////composite classcomposite classcomposite classcomposite class

web.ui.Button

web.ui.Link

web.ui.Radio

web.ui.Control<V> base class for input widgetsbase class for input widgetsbase class for input widgetsbase class for input widgets

web.ui.Checkbox<V>

web.ui.RadioGroup<V>

Page 39: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Class hierarchy

com.vaadin.ui.Component.Focusable

All Known Implementing Classes:

AbstractField, AbstractSelect, AbstractTextField, Accordion, Button, CheckBox, ColorPickerPopup, ComboBox, CustomField, DateField, Form, InlineDateField, LegacyWindow, ListSelect, MenuBar, NativeButton, NativeSelect, OptionGroup, Panel, PasswordField, PopupDateField, ProgressBar, ProgressIndicator, RichTextArea, Select, Slider, Table, TabSheet, TextArea, TextField, Tree,TreeTable, TwinColSelect, UI, Upload, Window

if (component instanceof Focusable)

((Focusable)component).focus();

public class Widget {

public boolean focus()

}

widget.focus();

Nobody is perfect

Osgood Fielding III., Gerald ‚Jerry‘ (Daphne)

Page 40: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Events

Observer or Listener pattern

Decouple event handling from event source

ClickListener

ClickListener

addClickListener

Event processEvent(Event)

ButtononClick(Event)

onClick(Event)

API:

Event class(es), Listener interfaces, register and process methods

Page 41: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

public class Event

public class ActionEvent extends Event {

public int getModifiers()

}

Events

Swing: Explicit event class per event type

...API EXPLOSION ALERT!

ActionEvent, AdjustmentEvent, AncestorEvent, CaretEvent, ChangeEvent, ComponentEvent, ContainerEvent, FocusEvent, HierarchyEvent, HyperlinkEvent, InputEvent, InputMethodEvent, InternalFrameEvent, InvocationEvent, ItemEvent, KeyEvent, ListDataEvent, ListSelectionEvent, MenuDragMouseEvent, MenuEvent, MenuKeyEvent, MouseEvent, MouseWheelEvent, PaintEvent, PopupMenuEvent, RowSorterEvent, TableColumnModelEvent, TableModelEvent, TextEvent, TreeExpansionEvent, TreeModelEvent, TreeSelectionEvent, UndoableEditEvent, WindowEvent,

Page 42: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Events

Simplify: Only use one event class with a type field, and a

generic param map, discard layout related event types

public class Event {

public EventType getType()

public Widget getTarget()

public String getParam(String key)

public int getIntParam(String key)

}

action, click, close, closing, drop, dblclick,

focusgained, focuslost, hide, hiding,

input, keydown, keypressed, keyup,

mousedown, mousemove, mouseout, mouseover, mouseup,

open, opening, scrolled, show, showing,

valuechanged, valueset, <userdefined>

Page 43: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Events

AWT/Swing EventListeners

public interface ActionListener extends EventListener {

actionPerformed(ActionEvent event);

}

public interface FocusListener extends EventListener {

focusGained(FocusEvent event);

focusLost(FocusEvent event);

}

SOME CanNOt use lambdas and method handles:

TextField f = ...

f.addFocusListener(e –> System.out.println(e));

f.addFocusListener(this::onFocus);

Page 44: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Events

Simplify: Only use functional interfaces

public interface FocusListener extends EventListener {

public void onFocus(Event event);

}

public class MyListener implements FocusListener {

public void onFocus(Event event) {

if (event.getType() == FocusListener.GAINED)

...

else

...

}

}

Page 45: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

public class MyListener implements ActionListener {

public void actionPerformed(ActionEvent event) {

try {

showResult(db.query());

} catch (SQLException e) {

log.error(e);

showMessage("sorry, can't fix");

}

}

}

Exceptions

A Listener in AWT/Swing:

public class MyListener implements ActionListener {

public void actionPerformed(ActionEvent event) {

showResult(db.query());

}

}

Must catch any checked exception.

What happens to uncatched runtime exceptions?

Page 46: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Exceptions

Solution: Allow any exception during event processing:

public interface ClickListener {

public void onClick(Event event) throws Exception;

}

Uncatched exceptions bubble up the widget tree.

Allows to handle the exception in the right context.

listener.onClick(Event)

widget.onEventError(Event, Exception)

widget.getParent().onEventError(Event, Exception)

...

window.onEventError(Event, Exception)

Page 47: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Property binding

Bind properties to the result of an expression.

Example:

OldschoolCheckbox cb = ...; TextField tf = ...;

cb.addValueListener(event ->

tf.setEnabled(cb.isChecked());

New hotnesstf.setEnabledWhen(cb);

Page 48: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Property binding

Bindable properties: disabled / visible / required / invalid /

css / value / text content / …

Controls are expressions, expressions are composable

IntField n = ...

TextField t = ...

t.setInvalid(not(equal(length(t),n)));

Digest cycle, listener handling, etc. done by the library

DEMO

Can also define additional dynamic variablesForm form = ...

Button save = ...

save.setEnabledWhen(form.getEditStatus().is(DIRTY));

Page 49: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Summary

Presented simple design examples

UI libraries: very old topic – still room for

improvements. Same ideas (and errors) are

reproduced in most libraries

No library is perfect, we are all learning

Metrics: Lines of code, API size, easy coding

We are not only assemblers of other libraries,

but also designers, authors, artists, creators

Page 50: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Thank you for your attention

Questions…

Johannes Döbler

[email protected]

Page 51: Howto designa UI classlibraryfiles.meetup.com/4939632/20151125_how_to_design_a_ui_library.pdfHowto designa UI classlibrary LightweightJava Meetup, 25.11.2015 Johannes Döbler jd@civilian-framework.org

Images

API qualities

http://www.artima.com/cppsource/top_cpp_aha_moments.html

Simply start

https://en.wikipedia.org/wiki/File:Peter_Falk_-_1973.JPG

Derive API from context/constraints

https://en.wikipedia.org/wiki/File:Crystal_Clear_app_ktip.svg

Know the design patterns

http://info.tatcenter.ru/article/107688/

https://de.wikipedia.org/wiki/Datei:FANTA_4.jpg

https://de.wikipedia.org/wiki/Datei:Stadtmusikanten_Bremen.png

https://en.wikipedia.org/wiki/File:Dean_Franklin_-_06.04.03_Mount_Rushmore_Monument_%28by-sa%29-3_new.jpg

A camel is a horse designed by committee

http://projectcartoon.com/cartoon/3

Refactor without mercy

https://en.wikipedia.org/wiki/File:Clint_Eastwood_-_1960s.JPG

https://en.wikipedia.org/wiki/File:BatmanRoguesGallery.jpg

https://en.wikipedia.org/wiki/File:Gladiator_ver1.jpg

Composite pattern

https://en.wikipedia.org/wiki/File:Composite_UML_class_diagram_%28fixed%29.svg

Edit Widgets: Type support

https://commons.wikimedia.org/wiki/File:Waaah!.jpg

Class Hierarchy

https://de.wikipedia.org/wiki/Datei:DPAG_2010_40_Frankfurter_Buchmesse_Argentinien.jpg

https://de.wikipedia.org/wiki/Datei:Max_und_Moritz_%28Busch%29_040.png

http://girls-can-play.blogspot.de/2011/06/some-like-it-hot.html