Writing a Large Application in the Real World Based on the Java™ Foundation Class/Swing (JFC/Swing) API Trey Roby Senior Computer Scientist California Institute of Technology Session 1703

Why You Are Here?

Almost anyone can write a small GUI application We will learn how to write a large GUI application that is both well built and easy to use

2

Session 1703

Learning Objectives • Improve your skills with large GUI applications by: – Understanding the key design elements – Knowing where to start your program – Knowing how to finish your program

3

Session 1703

Speaker’s Qualifications • Large GUI-based applications for 12 years • Java™ AWT and JFC/Swing technology for 4 years • OO Development for 10 years

4

Session 1703

Large GUI Applications

Like a towering sky-scraper, large applications have a deep foundation...

5

Session 1703

What We’ll Cover 1. Developing a GUI Infrastructure 2. Building applications around Actions 3. Polishing the application 4. Installing on multiple platforms

6

Session 1703

Design Goals for a Deep Foundation • Homogenous • Extensible • Complete

7

Session 1703

Homogenous • Consistent behavior • Consistent layout

8

Session 1703

Extensible • Easy to add more features • Re-usable core components

9

Session 1703

Complete • Application appears finished • All the implied features are there – – – –

Drag & drop Tool tips Toolbars Help

• Installs easily

10

Session 1703

Homogeneous Developing a GUI Infrastructure

Session 1703

The Challenge • The JFC/Swing API alone is too low-level • Hard to use the JFC/Swing API in a consistent way – Different programmers will create different looks

• Applications can look very different

12

Session 1703

What a GUI Infrastructure Package IS • Classes that complement JFC/Swing objects • Classes that combine JFC/Swing objects • Classes that build JFC/Swing objects – Look & Feel adjustments made in one place

13

Session 1703

What a GUI Infrastructure Package IS NOT • A replacement for JFC/Swing technology • A layer on top of JFC/Swing technology

14

Session 1703

Using a GUI Infrastructure Package—The Big Picture Application Code

GUI Infrastructure

JFC/Swing 15

Session 1703

Warning Signs of a Poor GUI Infrastructure • Over-used ActionListeners • You lay out every individual swing object • Frequent GridBagLayout code • 70%–80% of dialog code interacts with the JFC/Swing API

16

Session 1703

You Have a Solid GUI Infrastructure If You… • Have predefined, re-usable components • Use very few ActionListener • Never create an OK button for a dialog • Never write code for simple number validation

17

Session 1703

You Have a Solid GUI Infrastructure If You… • Rarely write code to new basic components – – – – –

JButton JMenuItem JCheckBox JTextField JRadioButton

• Don’t use default renderers for JTables

18

Session 1703

GUI Infrastructure Package Application Code

GUI Infrastructure

JFC/Swing 19

Session 1703

GUI Infrastructure Package Application Code

Dialogs Utilities

GUI Infrastructure Numeric Table Actions Entry Utilities

JFC/Swing 20

Session 1703

GUI Infrastructure Package Application Code

Dialogs Utilities

Actions

GUI Infrastructure Numeric Table Actions Entry Utilities

JFC/Swing 21

Session 1703

Extensible Part 1— Building Around Actions

Session 1703

Action’s Role in an Application

Action Action

Functions

Application Code

Action Action Action Action Action Action Action

Action Action Action

Data Structures

Start With Actions

GUI Infrastructure

JFC/Swing 23

Session 1703

What Is an Action? Defines actionPerformed() Adds property Handling •addPropertyChangeListener() •removePropertyChangeListener() •putValue() •getValue()

Implements everything but actionPerformed()

24

Session 1703



ActionListener

Action

AbstractAction

Actions— Two-Way Communication • One Action could have many Buttons • Action is an ActionListener on the Button • Buttons adds a PropertyChangeListener to the Action • The button will reflect Action property changes – Text – Tooltip

25

Session 1703

Actions— Two-Way Communication Example

Button1Action

26

Session 1703

Actions— Two-Way Communication Example

PropertyChangeListener notifies Button when something has changed ActionListener Notifies Action when button is pushed

27

Session 1703

Button1Action Button1Action

Examples of Actions • Raise a Dialog • Undo/Redo • Cut, Copy, Paste • Save • Show parts of the User Interface • Etc.

28

Session 1703

Writing an Action Defines actionPerformed() Adds 6 more methods



ActionListener

Action

Implements everything but actionPerformed()

AbstractAction

Implements actionPerformed() to raise a dialog

MyDialogAction

29

Session 1703

Example

NAME

ACCELERATOR_KEY

SHORT_DESCRIPTION

30

Session 1703

Example

ActionListener()

PropertyChangeListener()

MyDialogAction 31

Session 1703

Action to Raise a Dialog (1) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”); putValue(SHORT_DESCRIPTION, “Show my special dialog”); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke( “d”, Event.ALT_MASK )); _dialog= new MyDialog(f); } public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 32

Session 1703

Action to Raise a Dialog (2) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) {

} public void actionPerformed(ActionEvent ev) { } } 33

Session 1703

Action to Raise a Dialog (3) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) {

} public void actionPerformed(ActionEvent ev) { } } 34

Session 1703

Action to Raise a Dialog (4) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) {

} public void actionPerformed(ActionEvent ev) { } } 35

Session 1703

Action to Raise a Dialog (5) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) {

} public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 36

Session 1703

Action to Raise a Dialog (6) public class MyDialogAction extends AbstractAction { private MyDialog _dialog;

Adding Properties

public MyDialogAction(JFrame f) {

} public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 37

Session 1703

Action to Raise a Dialog (7) public class MyDialogAction extends AbstractAction { private MyDialog _dialog;

Adding Properties

public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”);

} public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 38

Session 1703

Action to Raise a Dialog (8) public class MyDialogAction extends AbstractAction { private MyDialog _dialog;

Adding Properties

public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”); putValue(SHORT_DESCRIPTION, “Show my special dialog”);

} public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 39

Session 1703

Action to Raise a Dialog (9) public class MyDialogAction extends AbstractAction { private MyDialog _dialog;

Adding Properties

public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”); putValue(SHORT_DESCRIPTION, “Show my special dialog”); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke( “d”, Event.ALT_MASK )); } public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 40

Session 1703

Action to Raise a Dialog (10) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”); putValue(SHORT_DESCRIPTION, “Show my special dialog”); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke( “d”, Event.ALT_MASK )); _dialog= new MyDialog(f); Create the Dialog } public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } } 41

Session 1703

Action to Raise a Dialog (11) public class MyDialogAction extends AbstractAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { putValue(NAME, “Show My Dialog”); putValue(SHORT_DESCRIPTION, “Show my special dialog”); putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke( “d”, Event.ALT_MASK )); _dialog= new MyDialog(f); } public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); Every button push } } 42

Session 1703

Extensible Part 2 Extending Action and Using Property Files

Session 1703

Let’s Make Actions Even Cooler • Actions do manage properties, but… – Using putValue() is tedious – Every Action has the same type of code

• Add property files!

44

Session 1703

Expanding Property Use • Properties are named pieces of information • java.util.Properties manages properties – Maintains a database of properties – Reads properties from a file

45

Session 1703

Property File Example myDialog.Name= Show My Dialog myDialog.ShortDescription= Show my \ special dialog myDialog.Accelerator=ctrl-d

These lines are in a property file e.g., – actions.prop

46

Session 1703

Adding Loaded Properties to AbstractAction •

AbstractAction—no way to load properties



We need a Subclass to 1. Add properties loading 2. Look for certain property types 3. Convert any necessary properties

47

Session 1703

PropDB—Singleton Class PropDB

java.util.Properties

getInstance() getProperty() load()

getProperty() load()

Singleton Class Queries a property with a key Add more properties from a file

48

Session 1703

Action’s Role in Application

Application Code 1. Load Properties

Action Action

49

Session 1703

Property File Property File

2. Build Actions Action Action Action Action Action Action Action

Property File

Action Action Action

New Class—GeneralAction • Subclass of AbstractAction • Add Property Loading

50

Session 1703

GeneralAction Defines actionPerformed() Adds 6 more methods



ActionListener

Action

Implements everything but actionPerformed()

AbstractAction

Adds property loading but does not implement actionPerformed()

GeneralAction

51

Session 1703

General Action Code (1) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command) PropDB prop= PropDB.getInstance();

{

String s= prop.getProperty(command + "." + SHORT_DESCRIPTION); if (s != null) putValue(Action.SHORT_DESCRIPTION, s); s= prop.getProperty(command + "." + Action.NAME); if (s != null) putValue(Action.NAME, s); // // -- now do mnemonic, accelerator, etc // } } 52

Session 1703

General Action Code (2) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command)

{

Command parameter is the base name for properties

} } 53

Session 1703

General Action Code (3) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command)

{

PropDB prop= PropDB.getInstance();

Get the Singleton property class

} } 54

Session 1703

General Action Code (4) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command) PropDB prop= PropDB.getInstance();

{

String s= prop.getProperty(command + "." + SHORT_DESCRIPTION);

Get the SHORT_DESCRIPTION property

} } 55

Session 1703

General Action Code (5) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command) PropDB prop= PropDB.getInstance();

{

String s= prop.getProperty(command + "." + SHORT_DESCRIPTION); if (s != null) putValue(SHORT_DESCRIPTION, s);

If the property exists, then add it to the Action’s properties } } 56

Session 1703

General Action Code (6) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command) PropDB prop= PropDB.getInstance();

{

String s= prop.getProperty(command + "." + SHORT_DESCRIPTION); if (s != null) putValue(SHORT_DESCRIPTION, s); s= prop.getProperty(command + "." + NAME); if (s != null) putValue( NAME, s);

Do the same thing with NAME } } 57

Session 1703

General Action Code (7) public abstract class GeneralAction extends AbstractAction { public GeneralAction(String command) PropDB prop= PropDB.getInstance();

{

String s= prop.getProperty(command + "." + SHORT_DESCRIPTION); if (s != null) putValue(SHORT_DESCRIPTION, s); s= prop.getProperty(command + "." + NAME); if (s != null) putValue( NAME, s); // // -- now do mnemonic, accelerator, etc

Do the same thing with LONG_DESCRIPTION, SMALL_ICON, ACCELERATOR_KEY, MNEMONIC_KEY

} } 58

Session 1703

GeneralAction Becomes New Base Class ActionListener Action AbstractAction

MyDialogAction

59

Session 1703

GeneralAction Becomes New Base Class ActionListener Action AbstractAction

GeneralAction MyDialogAction

60

Session 1703

MyDialogAction Now Extends GeneralAction (1) public class MyDialogAction extends GeneralAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { super(“myDialog”); _dialog= new MyDialog(f); }

public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } }

61

Session 1703

MyDialogAction Now Extends GeneralAction (2) public class MyDialogAction extends GeneralAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { super(“myDialog”); _dialog= new MyDialog(f); } “myDialog” to GeneralAction

public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } }

62

Session 1703

MyDialogAction Now Extends GeneralAction (3) public class MyDialogAction extends GeneralAction { private MyDialog _dialog; public MyDialogAction(JFrame f) { super(“myDialog”); _dialog= new MyDialog(f); }

Short!!! Same!!!

public void actionPerformed(ActionEvent ev) { _dialog.setVisible(true); } }

63

Session 1703

Property File Example—Again myDialog.Name= Show My Dialog myDialog.ShortDescription= Show my \ special dialog myDialog.Accelerator=ctrl-d

This is the command name

64

Session 1703

Example—Using Property Files

MyDialogAction

Property File 65

Session 1703

Many Actions From Generalaction

Action AbstractAction GeneralAction

CopyAction

66

Session 1703

DeleteAction

EnableAllAction

Many Actions Action Action Action Action Action Action Action Action Action Action

Application Code Action Action Action

Lots of Actions!!!

GUI Infrastructure

JFC/Swing 67

Session 1703

Can We Improve Startup Time? • Dialogs actions are slow to create • Slow actions affect start-up time • We need lazy initialization

68

Session 1703

LazyBuildAction

Action AbstractAction GeneralAction LazyBuildAction build() activate() 69

Session 1703

Abstract: •Does not define actionPerformed()

Abstract: •Defines actionPerformed() •Adds abstract methodsbuild() & activate()

LazyBuildAction • New abstract methods – build() – activate()

public void actionPerformed(ActionEvent ev) { if (!_built) { Build the first time build(); _built= true; } activate(); } 70

Session 1703

LazyBuildAction • New abstract methods – build() – activate()

public void actionPerformed(ActionEvent ev) { if (!_built) { build(); _built= true; } Activate every time activate(); } 71

Session 1703

Who Uses LazyBuildAction?

Action AbstractAction GeneralAction MyDialogAction

These guys are Fine—they don’t create a dialog

EnableAllAction DeleteAction CopyAction

72

Session 1703

Who Uses LazyBuildAction?

Action AbstractAction GeneralAction LazyBuildAction

EnableAllAction DeleteAction

MyDialogAction 73

Session 1703

CopyAction

MyDialogAction Extends LazyBuildAction (1) public class MyDialogAction extends LazyBuildAction { private MyDialog _dialog; private JFrame _f; public MyDialogAction(JFrame f){ super(“myDialog”); _f= f; } protected void build(){ _dialog= new MyDialog(_f,data); } protected void activate(){ _dialog.setVisible(true); } } 74

Session 1703

MyDialogAction Extends LazyBuildAction (2) public class MyDialogAction extends LazyBuildAction { private MyDialog _dialog; private JFrame _f; public MyDialogAction(JFrame f){ super(“myDialog”); _f= f; } protected void build(){ _dialog= new MyDialog(_f,data); } protected void activate(){ _dialog.setVisible(true); } } 75

Session 1703

MyDialogAction Extends LazyBuildAction (3) public class MyDialogAction extends LazyBuildAction { private MyDialog _dialog; private JFrame _f; public MyDialogAction(JFrame f){ super(“myDialog”); _f= f; } protected void build(){ _dialog= new MyDialog(_f,data); } protected void activate(){ _dialog.setVisible(true); } } 76

Session 1703

Create the Dialog

MyDialogAction Extends LazyBuildAction (4) public class MyDialogAction extends LazyBuildAction { private MyDialog _dialog; private JFrame _f; public MyDialogAction(JFrame f){ super(“myDialog”); _f= f; } protected void build(){ _dialog= new MyDialog(_f,data); } protected void activate(){ _dialog.setVisible(true); } } 77

Session 1703

Set the dialog visible

GUI Infrastructure Package Application Code

GUI Infrastructure

JFC/Swing 78

Session 1703

GUI Infrastructure Package Application Code Dialogs

Utilities

Numeric Entry

Table Utilities

Actions

JFC/Swing 79

Session 1703

GUI Infrastructure Package Application Code Dialogs

Utilities

Numeric Entry

Table Utilities

GeneralAction

Actions

LazyBuildAction

JFC/Swing 80

Session 1703

Complete Part 1 Finishing the Application

Session 1703

Adding the Polishing Touches • Toolbars • Splash screens with progress bars • Tool Tips and Help • Effective use of color • Complete and informative error messages • Drag and Drop

82

Session 1703

First Impressions Are Everything • First Five Minutes Rule • Does it feel easy to use – Only a novice cares if it is easy to use – The first few tasks must be easy to do

83

Session 1703

Small Features Are Important (1) • Small features greatly affect user acceptance • Simply meeting requirements... – Feels very incomplete – Only creates an average program!

84

Session 1703

Small Features Are Important (2) • Make time to add nice touches • You will not be able to justify them – Add them anyway – Everyone will love you, trust me

85

Session 1703

Start-up Time • Always use a splash screen • Generally use a progress bar • Do everything possible to speed it up – Be meticulous – Constant vigilance

86

Session 1703

Complete Part 2 Installing on Multi-platforms

Session 1703

Installation Challenges • Easy • Normal • JRE (Java™ runtime environment)

88

Session 1703

Easy Installation • Very first impression of your application • Almost Un-noticeable • Quick • Network installations are rarely easy!

89

Session 1703

Normal Installation • Just like any other application • Feels normal for that platform • No special request from the installer • Nothing else to install

90

Session 1703

The Java™ Runtime Environment (JRE) • You must guarantee it is there • You must have control over the version • Solution—Install your own

91

Session 1703

Summary • Homogeneous – Build a solid GUI infrastructure

• Extensible – Build your application around Actions

• Complete – Include the details to make it exceptional – Include a clean and easy installation

92

Session 1703

Always Remember

A good program is like a sky-scraper... If you want to go high, first you better go deep

93

Session 1703

Session 1703

Session 1703