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