Sophie

Sophie

distrib > Mageia > 7 > armv7hl > by-pkgid > bb2b8c852b14bdf2b0a1d61fba1cd492 > files > 2

buoy-1.9-10.mga7.noarch.rpm

<html>
<body>
<div align="center">
<h1>Buoy</h1>
<h2>A Better User Interface Toolkit</h2>
by Peter Eastman<br>
Version 1.9, released May 1, 2009
</div>

<h2>Introduction</h2>
Buoy is a toolkit for creating user interfaces in Java programs.  You can 
think of it as a replacement for Swing and AWT, although that is not 
entirely correct.  Buoy is built on top of Swing, so when you use Buoy to 
create a user interface, Swing components are still being created behind 
the scenes.  A better description might be to say that Buoy is a replacement
for the Swing API, although it is really more than just that.
<p>
Perhaps the best way to introduce Buoy is to show a simple program which 
uses it.  Here is a program that displays a window with the message,
"Hello World!", and quits when the user clicks the OK button.  The version
on the left uses Buoy, and the one on the right uses Swing.
<p>
<table border="1">
<tr>
<td><tt><pre>
import buoy.event.*;
import buoy.widget.*;

public class HelloWorld
{
  public static void main(String args[])
  {
    BFrame f = new BFrame();
    BorderContainer content = new BorderContainer();
    f.setContent(content);
    content.add(new BLabel("Hello World!"), BorderContainer.CENTER);
    RowContainer rc = new RowContainer();
    content.add(rc, BorderContainer.SOUTH);
    BButton b = new BButton("OK");
    rc.add(b);
    b.addEventLink(CommandEvent.class, new Object() {
      void processEvent()
      {
        System.exit(0);
      }
    });
    f.pack();
    f.setVisible(true);
  }
}
</pre></tt></td>
<td><tt><pre>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class HelloWorld
{
  public static void main(String args[])
  {
    JFrame f = new JFrame();
    Container content = f.getContentPane();
    content.add(new JLabel("Hello World!"), BorderLayout.CENTER);
    JPanel p = new JPanel();
    content.add(p, BorderLayout.SOUTH);
    JButton b = new JButton("OK");
    p.add(b);
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent ev)
      {
        System.exit(0);
      }
    });
    f.pack();
    f.setVisible(true);
  }
}
</pre></tt></td>
</tr>
</table>
<p>
For such a simple program, there really is very little difference between
the two versions.  There is almost a perfect line-to-line correspondence
between them.  At a first glance, you might think I have done little beyond
changing some "J"s to "B"s.
<p>
On closer inspection, however, you will note some subtle differences.  For
example, the Buoy version sets the window's content pane rather than getting
it.  And then there is the very curious form of that event handler.  We will
look at these differences in detail later on.
<p>
Why would you want to use Buoy instead of the standard Swing API?  Quite 
simply, because it's better.  It is easier to learn and easier to use.  
It lets you do what you want to do with fewer lines of code.  It produces 
programs which are simpler, more readable, and easier to maintain.
<p>
This document describes the design of Buoy, how it is different from Swing 
and why I chose to implement it the way I did.  By the time you finish 
reading it, I hope I will have convinced you that Buoy is Simply Better.
<p>
The current version is 1.9.  It is stable and suitable for production use.
Please report bugs at the
<a href="http://sourceforge.net/tracker/?group_id=84219&atid=572144">Buoy project page</a>
on SourceForge.

<h2>Components and Widgets</h2>

A <tt>Widget</tt> is in Buoy what a <tt>Component</tt> is in AWT/Swing.  
It represents a graphical object on the screen.  In fact, there is an 
exact mapping between Widgets and Components.  For every Widget, a 
corresponding Component is created to "implement" that Widget.  In a 
sense, you could think of a Widget as simply being a wrapper around a 
Component, but I don't recommend it.  It is better to think of the Widget 
as being the graphical object itself, and of the Component as simply a 
side effect of how the Widget is implemented behind the scenes.
<p>
In all cases, Widgets present a far simpler API than the corresponding 
Components.  For example, the J2SE 1.4.2 version of JComponent has 306 
public methods.  The current version of Widget has 37.
<p>
Where did all those method go?  Well, about 40 of them are deprecated and 
should not really be counted, but that is only a small fraction of the 
total methods.  A number of methods are related to the Swing event 
handling mechanism: all of the addXListener(), removeXListener(), and 
processXEvent() methods.  Buoy uses a different event handling mechanism
which does not require separate methods for every event type.
<p>
Some methods are simply redundant.  JComponent has ten different methods 
for querying the current location and size of a component (not including 
deprecated methods like bounds() and size()).  Widget has one.
<p>
Finally, there are some methods that are simply artifacts of bad design, 
and have no business being there in the first place.  The get/set 
alignment methods are excellent examples of this.
<p>
That still leaves a lot of methods which provide legitimate but 
infrequently used features.  Swing is a very complicated library, but also 
a very powerful one.  Some of the complexity is simply the result of bad 
design, but some of it is an inevitable result of the huge number of 
features that it offers.
<p>
Buoy does not attempt to encapsulate every last feature of Swing.  
Instead, it offers a simple API for the subset of features that are used 
90% of the time.  For the less frequently used features, you must still 
access Swing directly.  Fortunately, that is a very easy thing to do.  In 
particular, you can call <tt>getComponent()</tt> on any Widget to get the
Component used to implement it.
<p>
As an example of this, consider the <tt>JList</tt> and <tt>BList</tt> 
classes.  There are two ways to set the contents of a <tt>JList</tt>: you can set 
the entire content at once, by passing in an array or <tt>Vector</tt>; or you can 
create an object that implements the <tt>ListModel</tt> interface, set it as
the model for the list, and manipulate the list contents indirectly through the 
model.  The former method is too limited for anything except the very 
simplest cases.  This means that in practice, nearly any use of a
<tt>JList</tt> requires working with a <tt>ListModel</tt>.
<p>
In contrast, <tt>BList</tt> provides a default model which is powerful enough for 
the vast majority of cases, then hides the fact that there is a model 
involved at all.  You simply call <tt>add()</tt> on the <tt>BList</tt> to add an item to the 
list, <tt>remove()</tt> to remove an item, and so on.  <tt>BList</tt> also allows you
to set a custom model for the rare cases where you actually need one, but usually
that is not necessary.
<p>
What about even less frequently used features: custom <tt>ListSelectionModel</tt>s,
<tt>ListCellRenderer</tt>s, and the like?  <tt>BList</tt> does not provide methods
for setting these directly, but that is not a problem.
Simply call <tt>getComponent()</tt> on the <tt>BList</tt> to 
obtain the underlying <tt>JList</tt>, then call the appropriate methods exactly
as you normally would.
<p>
A more extreme example is provided by <tt>JTable</tt> and <tt>BTable</tt>.  Even
a very simple use of a <tt>JTable</tt> requires dealing with a complex API and a
large number of objects, including the <tt>JTable</tt> itself, a <tt>TableModel</tt>,
a <tt>TableColumnModel</tt>, two different <tt>ListSelectionModel</tt>s, and a
whole array of <tt>TableColumn</tt> objects.  Buoy hides that complexity, and
replaces it with a single <tt>BTable</tt> object with a simple, easy to use API.
The complexity is still there when you really need it.  Usually, you won't.
<p>
Another important link between AWT/Swing and Buoy is provided by the <tt>AWTWidget</tt>
class.  This is a Widget that acts as a wrapper around an arbitrary Component.
If you have a legacy or third party Component, you are free to use it in Buoy
programs.  Simply wrap it in an <tt>AWTWidget</tt>, and then treat it like
any other Widget.

<h2>Laying Out Widgets</h2>

Swing separates the concept of a Container (any Component which holds
other Components) from a LayoutManager (which determines how those
Components should be arranged inside their parent container).  In theory,
any LayoutManager can be used with any Container, offering enormous
flexibility in how Components are layed out.
<p>
The reality is very different from the theory.  In practice, the vast
majority of Swing containers are JPanels.  The few exceptions to this rule
(such as JRootPane and JScrollPane) typically have their own "personal"  
LayoutManagers to which they are intimately bound.  In short, most
LayoutManagers have one, and only one, Container class with which they are
ever used.
<p>
Furthermore, this unused flexibility comes at a price.  Components must be
added to Containers with the same methods, regardless of what
LayoutManager will be used to arrange them.  This requires that those
methods be extremely generic in nature: <tt>add(Component comp, Object
constraints)</tt>.  All layout information must be shifted to a separate
"constraints" object.  Of course, there is nothing to prevent you from
passing a constraints object which is entirely inappropriate for the
LayoutManager in use.  In fact, except by reading the documentation, there
is no way to determine what type of object the current LayoutManager
expects.  Nor is there any way to identify a particular object as being
intended for use in layout.  There is no "LayoutConstraint" interface
which constraint objects must implement, or any other way for them to
identify themselves.
<p>
In contrast, Buoy combines the Container and LayoutManager into a
single <tt>WidgetContainer</tt> class.  This is an abstract class, with
subclasses that layout their children in different ways:  
<tt>ExplicitContainer</tt>, which lets you explicitly set the position of
each Widget; <tt>BorderContainer</tt>, which is similar to a
<tt>BorderLayout</tt>;  <tt>GridContainer</tt>, which is similar to a
<tt>GridLayout</tt>; and so on.  As a result, each container can provide 
add() methods that are appropriate for that container.  The result is a 
cleaner API that requires less information to be placed in separate 
objects.
<p>
In addition, Buoy's WidgetContainers are much more consistent than Swing's 
LayoutManagers.  Swing often feels as if its pieces were written by 
different people who never spoke to each other.  Every LayoutManager is 
completely different from every other.  Learning to use a BorderLayout 
teaches you nothing about how to use a GridBagLayout, which in turn 
teaches you nothing about how to use a BoxLayout.
<p>
Once you learn to use one WidgetContainer, on the other hand, you are much 
of the way to understanding all of them.  For example, there is a single 
<tt>LayoutInfo</tt> class that many different WidgetContainers use to 
store detailed layout information for a particular Widget.  They allow you 
to set a default LayoutInfo for everything in the container, or to 
override it one Widget at a time.  The result is a much simpler, cleaner, 
and more consistent API.

<h2>Events, part I: What Is An Event?</h2>

Event handling is the area where Buoy differs most dramatically from 
AWT/Swing.  I will therefore break it up into a few pieces, and examine each
piece separately.
<p>
Swing uses one class for each category of events.  For example, 
<tt>MouseEvent</tt> is used for all events relating to the mouse, such as 
being pressed, released, moved, dragged, etc.
<p>
Buoy, on the other hand, uses a separate class to represent every distinct 
type of event: <tt>MousePressedEvent</tt>, <tt>MouseReleasedEvent</tt>, 
and so on.  In most cases, the Buoy event classes extend the corresponding 
Swing classes.  For example, all mouse related events subclass 
<tt>java.awt.event.MouseEvent</tt>.  This simplifies the interaction 
between Buoy and Swing.  In addition, Buoy defines its own parent classes for
various categories of events.  For example, <tt>MousePressedEvent</tt>
subclasses <tt>WidgetMouseEvent</tt>, which in turn subclasses
<tt>MouseEvent</tt>.  In most cases, you should use Buoy's parent classes
(all of which implement the <tt>WidgetEvent</tt> interface) whenever you want
to refer to a category of events.
<p>
You might expect that this would lead to a huge number of classes for 
representing different types of events, but in practice it does not.  This 
is due to another design principle of the Buoy event model, which 
eliminates entire categories of events:
<p>
<div align="center"><b>
Buoy events always represent user actions, never actions taken by the 
program itself.
</b></div>
<p>
That is an important distinction, and one which AWT/Swing completely fails to 
make.  When an event is received, it is often impossible to determine whether
that event was generated in response to a user action (i.e. the user resized
a window by hand) or a program action (i.e. the program called <tt>setSize()</tt> on it).
This is a common source of bugs in Swing programs, and a source of much
frustration and grief among Java programmers.  Furthermore, the handling
of this issue is not even consistent: some methods of some objects generate 
events when they are invoked, but others do not.  A general rule seems to be
that lightweight Components generate events in response to method calls,
but heavyweight ones do not.  Even here, however, there are exceptions
that do not follow any clear pattern.  For example, calling <tt>setText()</tt>
on a <tt>TextField</tt> <i>does</i> generate a <tt>TextEvent</tt>.
<p>
In Buoy, there is no uncertainty.  Events always represent user actions.  
For communication between different parts of the program, UI based event 
handling is rarely the best approach, and usually represents a misuse of
the Model-View-Controller design.  If you absolutely require it, you 
can always call <tt>getComponent()</tt> on a Widget and add a listener 
directly to the Component, but the situations where that is actually 
needed should be few and far between.
<p>
There are a few exceptions to this rule: <tt>FocusGainedEvent</tt> and
<tt>FocusLostEvent</tt> are always sent when a Widget's focus state
changes, whether this resulted from a user action (like clicking on a
Widget), or a program action.  Likewise, <tt>WindowActivatedEvent</tt>
and <tt>WindowDeactivatedEvent</tt> are always sent when a window
becomes active or inactive, regardless of the reason.  These exceptions
are necessary due to the nature of focus
management: the focus state of one Widget can be changed by calling
<tt>requestFocus()</tt> on a different and completely unrelated Widget.  This means
that monitoring events is really the only practical way for a Widget to
detect when its focus state has changed and update its appearance
accordingly.
<p>
Another way of looking at this is to say that the focus
state of a Widget, and the activation state of a window, are not really
properties of that Widget at all; they are properties of the windowing
environment as a whole (which Widget events will be sent to).  Perhaps a
more accurate statement of the design principle is this: "Buoy events
always represent user actions <i>or</i> programmatic changes to the global
state of the windowing environment, but never programmatic changes to
the internal state of a particular Widget."

<h2>Events, part II: What Happens To An Event?</h2>

Event notification in Swing is done through statically implemented event 
listener interfaces.  If a class wants to be notified when a button is 
pressed, it implements the <tt>ActionListener</tt> interface, which 
requires it to provide a method with a particular signature that will be 
called whenever an <tt>ActionEvent</tt> occurs:
<p>
<tt><pre>
public void actionPerformed(ActionEvent ev)
{
  ...
}
</pre></tt>
<p>
It then requests notification of events by calling an appropriate method 
on the button:
<p>
<tt><pre>
button.addActionListener(this);
</pre></tt>
<p> 
Buoy handles event notification through dynamically linked listener 
methods.  For example, if a class wants to be notified of button presses, 
it could implement a method like this one:
<p>
<tt><pre>
public void buttonPressed(CommandEvent ev)
{
  ...
}
</pre></tt>
<p>
It would then request notification of events by adding an "event link" to 
the button:
<p>
<tt>
button.addEventLink(CommandEvent.class, this, "buttonPressed");
</tt>
<p>
The three arguments to <tt>addEventLink()</tt> are the type of events
the listener wants to be notified about, the object to notify, and the
name of the method to call on it.  The method's argument type need not
exactly match the class passed to <tt>addEventLink()</tt>.  It merely needs 
to be compatible with it.  For example, the method could have been 
declared as
<p>
<tt>
public void buttonPressed(WidgetEvent ev)
</tt>
<p>
or even as
<p>
<tt>
public void buttonPressed(Object ev)
</tt>
<p>
Similarly, you can request notification of entire categories of events at 
once by passing a superclass or interface to <tt>addEventLink()</tt>.  For 
example, you could direct all mouse related events to a method by calling
<p>
<tt>
widget.addEventLink(WidgetMouseEvent.class, this, "handleMouseEvent");
</tt>
<p>
or absolutely all events of any sort by calling
<p>
<tt>
widget.addEventLink(Object.class, this, "eventOccurred");
</tt>
<p>
If you omit the third argument, Buoy will look for a method with the 
default name "processEvent".  This is a convenient shortcut when using 
anonymous inner classes as event listeners:
<p>
<tt><pre>
button.addEventLink(CommandEvent.class, new Object() {
  void processEvent(CommandEvent e)
  {
    ...
  }
});
</pre></tt>
<p>
The argument passed to the event listener can be omitted if the method does not care about
seeing the event object.  For example, if a method is only used for
handling presses of one specific button, it can simply be declared as
<p>
<tt>
private void buttonPressed()
</tt>
<p>
This can allow incredibly concise event handling in certain cases.  If the
desired response to an event is to invoke a single method which already exists,
there often is no need to write an event handler at all.  For example, suppose
you want a window to be disposed when the user clicks its close box.  This can
be accomplished with a single line of code:
<p>
<tt>window.addEventLink(WindowClosingEvent.class, window, "dispose");</tt>
<p>

<h2>Events, part III: But <i>Why?</i></h2>

Buoy's event handling system is certainly different from Swing's, but is 
it better?  If you have never used any UI library other than AWT/Swing, 
Buoy's system may seem strange, awkward, and possibly even "un-Java-like".  
Why would you want to use it?
<p>
The answer, as with all of Buoy, is simply, "Because it's better!"  It is 
more powerful and flexible.  It produces simpler programs with less wasted 
code.  Your programs will have fewer bugs, and be easier to maintain.
<p>
That is quite a claim to make, and I had better be able to back it up.  
Believe me, I am.  Let me present a number of different examples, each one 
showing a different way in which Buoy's event mechanism is better.

<h3>One Method, Many Events</h3>

Consider a common situation: you want to display a popup menu whenever the 
user performs the platform-specific trigger action (right-clicking on 
Windows, control-clicking on MacOS, etc.) on a particular Widget.  In 
theory, any mouse event can be a popup trigger, so you really should check 
all of them.  In practice, only mouse pressed and mouse released events 
are commonly used as popup triggers, so it is probably sufficient to check 
only those.
<p>
How would you do this with Swing?  The most straightforward way is to 
implement <tt>MouseListener</tt>, and handle each of these event types:
<p>
<tt><pre>
public void mousePressed(MouseEvent ev)
{
  if (ev.isPopupTrigger())
  {
    // Do whatever is necessary to show the popup menu.
  }
}

public void mouseReleased(MouseEvent ev)
{
  if (ev.isPopupTrigger())
  {
    // Do whatever is necessary to show the popup menu.
  }
}
</pre></tt>
<p>
In the above code, "Do whatever is necessary to show the popup menu,"  
could mean something fairly complex (i.e. building or configuring various
menu items based on the click location and the current state of the
program).  Having this code exactly duplicated in two different methods is
very bad style, and a great opportunity for bugs.  For example, someone
might make a change to one of these methods, but forget to make the
corresponding change to the other one.  A better solution is to move this
logic into its own method:
<p>
<tt><pre>
public void mousePressed(MouseEvent ev)
{
  if (ev.isPopupTrigger())
    showPopupMenu(ev);
}

public void mouseReleased(MouseEvent ev)
{
  if (ev.isPopupTrigger())
    showPopupMenu(ev);
}

private void showPopupMenu(MouseEvent ev)
{
  // Do whatever is necessary to show the popup menu.
}
</pre></tt>
<p>
This is an improvement, but it is still far from ideal.  We are using 
three methods to implement a single operation, which adds clutter to the 
code and increases the opportunities for bugs.
<p>
In Buoy, we can do it all with a single method:
<p>
<tt><pre>
private void showPopupMenu(WidgetMouseEvent ev)
{
  if (ev.isPopupTrigger())
  {
    // Do whatever is necessary to show the popup menu.
  }
}
</pre></tt>
<p>
And that is it.  We can direct all mouse events to that method with a 
single line:
<p>
<tt>
addEventLink(WidgetMouseEvent.class, this, "showPopupMenu");
</tt>
<p>
or, if you want to restrict it to only sending mouse pressed and mouse 
released events,
<p>
<tt><pre>
addEventLink(MousePressedEvent.class, this, "showPopupMenu");
addEventLink(MouseReleasedEvent.class, this, "showPopupMenu");
</pre></tt>
<p>
In short, Buoy allows you to handle multiple event types with a single 
method.

<h3>Many Methods, One Event Type</h3>

Now let's consider the converse situation: using different methods to 
handle the same type of event.  For example, suppose you are implementing 
a window with a menu bar.  A common design is to use a single class (most 
often the window itself) as the event listener for all of the menu items.  
In Swing, the most straightforward way of doing this is to use the "action 
command" to distinguish between different menu items.  You would create 
the menu items as follows:
<p>
<tt><pre>
JMenuItem mi;
editMenu.add(mi = new JMenuItem("Copy"));
mi.setActionCommand("copy");
mi.addActionListener(this);
editMenu.add(mi = new JMenuItem("Cut"));
mi.setActionCommand("cut");
mi.addActionListener(this);
editMenu.add(mi = new JMenuItem("Paste"));
mi.setActionCommand("paste");
mi.addActionListener(this);
...
</pre></tt>
<p>
Then you would dispatch the different events to appropriate methods based 
on the action command:
<p>
<tt><pre>
public void actionPerformed(ActionEvent ev)
{
  String command = ev.getActionCommand();
  if ("copy".equals(command))
    doCopy();
  else if ("cut".equals(command))
    doCut();
  else if ("paste".equals(command))
    doPaste();
  ...
}
</pre></tt>
<p>
How would you do this in Buoy?  You can specify the method to handle each 
menu item at the same time you create it:
<p>
<tt><pre>
BMenuItem mi;
editMenu.add(mi = new BMenuItem("Copy");
mi.addEventLink(CommandEvent.class, this, "doCopy");
editMenu.add(mi = new BMenuItem("Cut");
mi.addEventLink(CommandEvent.class, this, "doCut");
editMenu.add(mi = new BMenuItem("Paste");
mi.addEventLink(CommandEvent.class, this, "doPaste");
</pre></tt>
<p>
And that is it!  There is no need for a separate method to dispatch the 
events from different menu items to the correct handler methods.  Buoy 
takes care of that for you.  There are fewer separate pieces of code involved
in handling each command, which makes the program more readable, easier to
maintain, and less susceptible to bugs.

<h3>Only the Methods I Want!</h3>

Suppose an object wants to be notified whenever the user clicks the mouse in
a certain Component.  In Swing, it does this by implementing the
<tt>MouseListener</tt> interface, and placing the appropriate logic in the
<tt>mouseClicked()</tt> method.  Unfortunately, you cannot provide only that
method.  <tt>MouseListener</tt> defines five different methods, and so you
must implement all five of them, even though you only really want one.  This
adds clutter to your program and wastes your time by making you write
unwanted code that will never be used.
<p>
You can work around this problem by subclassing <tt>MouseAdapter</tt>, which
provides empty default implementations of all the listener methods.  This is
not always an acceptable solution, however.  The class in question may
already extend something else, which rules out the possibility of subclassing
<tt>MouseAdapter</tt>.  Alternatively, you could put the event handling code
into an inner class which extends <tt>MouseAdapter</tt>, but this too is not
always possible: if the event handling is done by an inner class, then it is
impossible for a subclass to override it and handle the event in a different
way.  Getting more complicated, you could have an inner class which extends
<tt>MouseAdapter</tt>, implements <tt>mouseClicked()</tt>, and then passes
the event to a public or protected method of the main class for handling.
Here again, we find ourselves adding extra layers to the code which
complicates the logic and introduces new opportunities for bugs.
<p>
In Buoy, none of this is an issue.  You implement handlers for only the event
types you actually care about.  You never need to write empty methods simply
because "the interface requires it". 

<h3>Invasion of Privacy</h3>

In order to implement one of the Swing event listener interfaces, all of the
event handling methods must be declared public.  That means that they become
part of the public API of the class.  In most cases, these methods are really
intended "for internal use only", and it would be inappropriate for any other
class to call them.  In any reasonable design, these methods should be
declared private or protected, and making them public pollutes your API.
<p>
You can work around this problem by using a private inner class as the event
listener, then having it pass the events on to private or protected methods
on the main class.  Once again, we find ourselves forced to add extra layers
to the code (with the attendant clutter, reduction in maintainability, and
opportunities for bugs) simply to work around the deficiencies of the Swing
event handling mechanism.
<p>
In Buoy, you are free to make your event handling methods private or
protected.  In fact, I have done so in some of the examples given earlier,
just to see if you would notice!  No extra layers are required to keep your
API clean and expose only the functions you really want to expose.

<h3>Please Sir, Can I Have Some More Events?</h3>

Both the Swing and Buoy event handling mechanisms are extensible.  You can
define new types of events, and new Components/Widgets that generate those
events.  As an example, suppose you are implementing a new Component that
can recognize mouse "gestures", patterns of motion that are more complex than
simple clicks or drags.  You want to send out an appropriate event whenever
the user performs a gesture.  Here is how you would do it with the Swing
event model:
<p>
<ol>
<li>Create a <tt>GestureEvent</tt> class to represent a gesture.</li>
<li>Create a <tt>GestureListener</tt> interface, which must be implemented
by any object that wants to receive <tt>GestureEvents</tt>.</li>
<li>Any Component that generates <tt>GestureEvents</tt> must internally
maintain a list of <tt>GestureListeners</tt>, probably as a <tt>Vector</tt>
or <tt>ArrayList</tt>.  It must implement an <tt>addGestureListener()</tt>
method for adding listeners to the list, and a <tt>removeGestureListener()</tt>
method for removing them.</li>
<li>Finally, it must provide a <tt>processGestureEvent()</tt> method, which
dispatches a <tt>GestureEvent</tt> to every listener in its list.</li>
<li>If you have more than one type of Component which can generate
<tt>GestureEvents</tt>, repeat steps 3 and 4 for each Component class.</li>
</ol>
<p>
Does it feel like Swing isn't doing a lot to help you out?  That's because it
isn't.  You are really implementing the entire thing from scratch, and it is
purely coincidental that you are naming your classes and methods in a way that
is consistent with Swing's naming conventions.
<p>
Now consider how you would do this with Buoy:
<p>
<ol>
<li>Create a <tt>GestureEvent</tt> class to represent a gesture.</li>
<li>There is no step 2.</li>
</ol>
<p>
Buoy takes care of everything else for you.  There is no need to define a
listener interface.  Nor do you need to maintain a list of listeners yourself.
Just call <tt>addEventLink()</tt> on any Widget to add a listener, and
<tt>dispatchEvent()</tt> to send out a <tt>GestureEvent</tt> to all the
registered listeners.
<p>
By the way, all of the event handling methods such as <tt>addEventLink()</tt>
and <tt>dispatchEvent()</tt> are defined by <tt>EventSource</tt>, which is
the superclass of <tt>Widget</tt>.  That means that you can even use Buoy's
event handling mechanism for events that do not directly relate to any
graphical component.  For example, you might have a class which listens on
a socket for information coming over a network.  You could have it subclass
<tt>EventSource</tt>, then send out <tt>NetworkEvent</tt> objects when certain
types of information are received.

<h3>But The Real Reason Is...</h3>

I have now given many examples of ways that Buoy's event handling mechanism
produces simpler, more easily maintainable code than Swing's.  Are you
convinced that it is better?  Well don't answer yet, because I haven't even
started!  All of the advantages I have described above are important benefits
of using Buoy, but I must admit that <i>none</i> of them was the reason I
designed it the way I did.
<p>
The true reason for Buoy's event handling mechanism is that it is vastly more
powerful than Swing's.  It makes it easy, even trivial, to do things that are
difficult or impossible with Swing.  Let me give a few examples.
<p>
Suppose that you want to monitor every event of any sort that is generated by
a particular Widget.  Simply call
<p>
<tt>
addEventLink(Object.class, this);
</tt>
<p>
and you will get them all.  Suppose you then want to "play back" those events
at a later time.  Simply pass them to the Widget's <tt>dispatchEvent()</tt>
method.  This will work even if you have no idea what types of event the
Widget might generate, even if some of the events are a custom event class
that you do not even know exists.
<p>
Doing the same thing with Swing would be an enormous undertaking.  You must
know in advance every type of event a particular Component may generate.  You
must implement the event listener interfaces for every one of those event
types, and provide a nearly identical implementation of every method defined
by every one of those interfaces.
<p>
Here is another example.  Suppose that a window's contents are variable.
Other objects may want to be notified of events being generated by Components
inside it, but that list of Components may change at any time.
<p>
To do this with Swing, an object that wants to be notified of a particular
event type would need to recursively go through the containment hierarchy,
identify every Component in the window that can generate that type of event,
and add itself as a listener to each one.  Any time the contents of the
window changed, each listener would need to repeat this process to make sure
it is still a listener for every Component.  This could possibly be done by
listening for <tt>HierarchyEvents</tt>, or alternatively the window itself
could provide a notification mechanism to inform outside objects when its
contents have changed.
<p>
An alternative solution would be to have the window (or another object) act as a "proxy" for
events generated by its contents.  The window would add itself as a listener
to each Component inside it, then forward events to other objects that wanted
to receive them.  The window would need to implement an appropriate mechanism
for objects to request notification of events generated by its contents, and
of course the entire system would need to be implemented separately for every
type of event that could be generated.  Needless to say, this system will
only work if you know in advance every type of event that might be generated
by any Component in the window.
<p>
With Buoy, proxying events is so trivial that it's almost embarassing.  Simply
create an EventSource to act as the proxy, then invoke the following method on
each of the child Widgets:
<p>
<tt>widget.addEventLink(Object.class, proxy, "dispatchEvent");</tt>
<p>
Any object can then call <tt>addEventLink()</tt> on the proxy, and be
notified of any event generated by any Widget in the window.  This works even
if you have no idea what event types the child Widgets might generate, or
which ones an outside listener might be interested in.
<p>
One more example.  Suppose you want your program's menus to be user
configurable.  This can be done by using a file to define the list of items
in each menu.  With either Swing or Buoy, the file can define the name,
position, keyboard shortcut, and action command of each menu item.  With
Buoy, you can take this a step further and actually define what method should
be called when the menu item is selected.  The is an incredibly powerful
technique, especially for programs that can be extended by means of a plugin
mechanism.

<h3>Yes, But...</h3>

I know, even after seeing all the advantages of Buoy's event handling
mechanism, something about it still just doesn't seem right.  It's so
different from how most other Java programs work.  Go ahead, let's hear the
objections and deal with them.
<p>
First of all, isn't it susceptible to errors?  Java is a strongly typed
language that relies heavily on the compiler to catch mistakes.  If you try
to call a method that doesn't exist, the compiler will catch it.  But suppose
you mistype the name of an event handler method:
<p>
<tt><pre>
addEventLink(MousePressedEvent.class, new Object() {
  void procesEvent(MousePressedEvent ev)
  {
    // Do something.
  }
});
</pre></tt>
<p>
There is no way the compiler can realize that the object is supposed to have
a method called "processEvent", and you have misspelled it.
<p>
This is true.  The error will not be caught at compile time, but it will be
caught as soon as you run the program.  When <tt>addEventLink()</tt> is
called, it will attempt to look up the method, discover it does not exist,
and throw an exception.
<p>
Now let's consider an equivalent case with Swing:
<p>
<tt><pre>
addMouseListener(new MouseAdapter() {
  public void MousePressed(MouseEvent ev)
  {
    // Do something.
  }
});
</pre></tt>
This also will compile without problem.  Unlike the Buoy case, however, it
also will run without complaint.  There will be no error message to tell you
what you have done wrong.  Your event listener will simply never be called,
and you can easily waste a lot of time pounding your head against the screen
before you finally realize that the method name is capitalized incorrectly.
Trust me.  I've done it.
<p>
OK, but here's another problem.  Java supports method overloading.  You can't
identify a method just by its name.  You also need to supply the full list of
arguments.  How can Buoy deal with overloaded methods, when all it lets you
specify is a single String?
<p>
To begin with, I should say that I cannot recall a single occasion when I
have ever been tempted to overload an event handling method.  For example,
I do not believe I have ever written a class with two methods both called
"actionPerformed", but which took different arguments.
<p>
Suppose, however, that you really did want to have two methods with the same
name, each of which either takes no argument, or takes a single argument which is
compatible with the class passed to <tt>addEventLink()</tt>.  In that case,
there is also a form of <tt>addEventLink()</tt> which takes a
<tt>Method</tt> object instead of a String.  I doubt you will ever need it,
but it's there in case you do.
<p>
Actually, there is one case where this form of <tt>addEventLink()</tt>
might be useful: if you want to use a static method as an event listener,
you can pass in the appropriate <tt>Method</tt> object directly, and
pass <tt>null</tt> for the target object.  The static method will then be
invoked whenever an event of the desired type occurs.  This is completely
impossible with Swing, of course, but that doesn't mean it isn't useful.

<h2>Custom Widgets</h2>

Both Swing and Buoy allow you to define entirely new types of
Components/Widgets, but their mechanisms for doing this are somewhat
different.  To create a custom Swing component, you define a new class which
extends <tt>JComponent</tt>.  Your subclass must override <tt>paintComponent()</tt>
to determine the appearance of the Component.
Then, if the Component needs to respond to any events, you add
appropriate event listeners to it.  (Often, the Component itself will be
the event listener, but this is not required.)
<p>
In Buoy, you use the <tt>CustomWidget</tt> class to create custom Widgets.
Unlike <tt>JComponent</tt> which is an abstract class, <tt>CustomWidget</tt>
can be instantiated directly.  To control the appearance of the Widget, you
add an event link to listen for <tt>RepaintEvent</tt>s.  There are no behaviors
which can only be controlled by overriding methods.
<p>
Of course, you will still often want to subclass <tt>CustomWidget</tt>, and
have the subclass manage its appearance and behavior itself.  This would be
the case when defining a new Widget type that will be reused in many places.
On the other hand, if a Widget will only ever appear in one window and is
tightly bound to the functionality of that window, it may be more convenient
to treat the Widget as a part of the window rather than an independent
object.  You could then simply create a <tt>CustomWidget</tt> object, and
let the class defining the window take responsibility for painting the
Widget and responding to events in it.  Buoy gives you the flexibility to
use whichever approach is more appropriate to a given situation.

<h2>Designing and Building Interfaces</h2>

If you survey the hundreds of different GUI toolkits which have been written
over the years for use on different platforms, you will find that there are
two major approaches for how a program can create its user interface.  The
first approach is for the program to do everything directly.  For every
button, menu item, or other graphical object in the interface, there is a
piece of source code to create that object and define its properties and
relationship to the rest of the interface.
<p>
The second approach is to use some form of "user interface definition
records" which are stored separately from the program itself.  These records
define the list of graphical objects in an interface, their properties,
their spatial arrangement, and possibly information about their behaviors.
When a program wants to create a window, for example, it simply references
the record which defines that window.
<p>
The second approach is widely accepted as the superior one.  Here are just
a few of its advantages:
<p>
<ul>
<li>By removing purely graphical information (the labels on buttons, their
positions within the window, etc.) from the program, the source code becomes
much simpler, cleaner, more readable, and easier to maintain.  The program
logic is no longer cluttered up by page after page of code to create buttons
and labels and arrange them within the window.</li>
<li>Similarly, the graphical information becomes much easier to work with.
There are ways of describing a user interface that are far more efficient
and readable than a series of Java method calls.  Furthermore, a
window's layout can be redesigned without worrying that you might accidentally
break the program logic that was intertwined with it.</li>
<li>Window layouts can be altered simply by editing the interface definition,
with no need to recompile (or in some cases, even rerun) the program.  This
can be a huge timesaver.</li>
<li>It is possible to use a graphical layout tool to edit the user interface
definition records.  This allows you to create your user interface simply by
dragging objects around on the screen, which is much faster and easier than
writing source code.  (There are also graphical layout tools for Swing, which
work by generating source code directly.  They produce hideous, nearly
unmaintainable code, and hardly deserve mentioning.  I have been forced to
deal with the products of these tools, and I sincerely hope you will never
have to.)</li>
<li>Internationalization becomes much easier, often requiring no code changes
at all.  Most localizable text is stored in the interface definition records,
which can easily be localized by a translator working with a graphical layout
tool.  This also makes it easy to make significant layout changes as part of
internationalization (for example, to accommodate languages that flow from
right to left versus left to right).</li>
</ul>
<p>
Unfortunately, Swing is tightly bound to the first approach.  The assumption
that all interfaces will be generated directly by the program is inherent
in nearly every aspect of its design.  As a result, even though many attempts
have been made to build Swing interfaces from external definition records,
none of these attempts has achieved more than limited success, and the vast
majority of Swing programs still create their interfaces directly in the
source code.
<p>
In contrast, Buoy has
built in support for serializing user interfaces to external files, then
reconstructing them again.  My intention is that eventually, the "normal"
way of writing a Buoy program will be to use a graphical layout tool to
create the user interface, save it to a set of interface definition files,
and have the program reconstruct the interface directly from these files.
<p>
Buoy's serialization mechanism is based on the <tt>XMLEncoder</tt> class
introduced in Java 1.4, but it adds various features both to allow Widgets to
be serialized effectively, and to make the mechanism easier to use.
To serialize a window or other piece of a user interface, you simply call
<p>
<tt>WidgetEncoder.writeObject(obj, out);</tt>
<p>
where <tt>obj</tt> is the object to save, and <tt>out</tt> is an output
stream to write the XML to.  This will save a complete representation
of the object, its children, event listeners attached to them, etc.
Reconstructing the interface is just as easy:
<p>
<tt><pre>
WidgetDecoder decoder = new WidgetDecoder(in);
BFrame frame = (BFrame) decoder.getRootObject();
</pre></tt>
<p>
<tt>WidgetDecoder</tt> also allows you to look up any Widget in the
file by name (as originally set by calling its <tt>setName()</tt>
method).  For example, if the window contains a <tt>BTextArea</tt>
in which the user is asked to enter their address, the following
code will look it up:
<p>
<tt>String address = ((BTextArea) decoder.getObject("address")).getText();</tt>
<p>

<h2>Buoy in Applets</h2>

If you want to use Buoy in an unsigned applet, there are a few restrictions you must
follow.  When I first started to write Buoy, I tested the event handling mechanism by
writing an event handler like the following one:
<p>
<tt><pre>
widget.addEventLink(WidgetEvent.class, new Object() {
  public void processEvent(WidgetEvent ev)
  {
    System.out.println(ev.getClass().getName());
  }
});
</pre></tt>
When Buoy attempted to invoke this event handler using reflection, it threw
an <tt>IllegalAccessException</tt>.  This was surprising and distressing.
The <tt>processEvent()</tt> method was public.  Why couldn't it be invoked?
<p>
A little research turned up the answer.  In order to invoke a method by
reflection, the invoking code must have permission to access both the method
(i.e. the method is declared public), and the class the method belongs to
(i.e. it is a public class).  By definition, anonymous inner classes are
never public, which meant they could never be used as event handlers.  This
threatened to be a major roadblock, since anonymous inner classes are such
a common and convenient way of implementing event listeners.
<p>
Fortunately, the problem had an easy solution.  The <tt>AccessibleObject</tt>
API allows the ordinary access restrictions to be circumvented when using
reflection, so any method may be invoked regardless of permissions.  This
eliminated the problems with anonymous inner classes, and also had a side
benefit which I mentioned earlier: it meant that event handler methods
could be declared protected or private.
<p>
Unfortunately, this solution is not perfect.  Use of the <tt>AccessibleObject</tt>
API may be restricted by a security manager.  That means that if you want
to use Buoy in an unsigned applet (or most other situations where a security
manager is in place), you are bound by two restrictions:
<p>
<ol>
<li>All event handler methods must be public.</li>
<li>All event handler methods must belong to public classes.</li>
</ol>
<p>
As a workaround for this problem, Buoy provides the <tt>EventProcessor</tt>
class which has the following trivial definition:
<p>
<tt><pre>
public abstract class EventProcessor
{
  public void processEvent(Object event)
  {
    handleEvent(event);
  }

  public abstract void handleEvent(Object event);
}
</pre></tt>
<p>
If you want to handle events with an anonymous inner class, have it extend
<tt>EventProcessor</tt> and implement <tt>handleEvent()</tt>:
<p>
<tt><pre>
widget.addEventLink(CommandEvent.class, new EventProcessor() {
  public void handleEvent(Object event)
  {
    // Handle the event
  }
});
</pre></tt>
<p>
Because <tt>processEvent()</tt> is defined by the public class <tt>EventProcessor</tt>,
Buoy is free to invoke it.  <tt>processEvent()</tt> will then invoke your
<tt>handleEvent()</tt> method.  The only disadvantage of this arrangement is
that the signature for <tt>handleEvent()</tt> is fixed by the superclass, so
it must always take an argument of type <tt>Object</tt> rather than a more
specific event class.
<p>
Remember, this only applies to cases where you are restricted by a security manager.
If you are writing an application, a signed applet, or any other type of program
which is free from security restrictions, you can ignore this section.

<h2>Terms of Use</h2>

Buoy 1.9 is hereby released into the public domain.  You are
free to use it in any way you want for any purpose.
</body>
</html>