Triggers

So you're working in VisualAge's Visual Composition Editor (VCE) and you're getting really tired of setting up the same six connections for umpteen buttons that do almost exactly the same thing?  Here's a trick that will save your wrists from the evil connection daemons...

I apologize for this one assuming some knowledge of the Visual Composition Editor.   Eventually I'll set this up as a full tutorial example that assumes no knowledge and walks you completely through the example.

I'm writing this stupid calculator and all the buttons connections are the same...

So there I was, writing a four-function calculator as an example of how you could write a decently-complex application with around six lines of code.  I keep adding connections to the number buttons.  They're all the same, except the number on the key is different.  very frustrating to do this 10 times!

I factor stuff when I write code, why can't I do it in the VCE?

The more I thought about this, the more I thought about it...

Then it hit me!

Properties can fire change events!  What if I defined an object whose sole purpose in life is to do all the common work,  triggered when its property changes?  And instead of having each of the other buttons do three or four connections, just have them do one connection on actionPerformed, setting the property of the trigger object to their "this" property?

I'm lost, Scott... Please speak in English.

Better yet, I'll give an example.

Let's create a simple application that has a phone pad, where each button will have three actions when its pushed:

  1. Append its text to a label on the screen.
  2. Make a tone.
  3. Have Michael Caine say the number.

Because we don't have the tools handy for all of these, nor do I have the patience to type directions for them right now, just create an object that has three methods features

and just define them to be something like System.out.println("I'm appending "+text) and so on...

Add one of these beans to the design area of the VCE (drop it somewhere outside the Frame so it's not contained by any other bean.)

Create a subclass of Frame and design it in the VCE.   Make the Frame have a GridLayout with columns=3 and rows=0.  (Remember, this means "3 columns, any number of rows")

Add twelve buttons to the frame, and label them as follows:

1	2	3

4	5	6

7	8	9

*	0	#

Now instead of hooking up those three connections for every darn button, we'll create a trigger that can do most of the work for us!

Define a bean in VisualAge that's a subclass of java.lang.Object that only has one property -- a reference to a java.awt.Button.  Name the property button and make sure you specify that it is a bound property.  (The easiest way to do this is to open the Class to Bean Info (Open To->Bean Info from the class' pop-up menu) and press the "Add new propery feature" on the toolbar.)

Specifying the property as bound sets up some event handling that will be triggered any time the property value changes.

After you have defined the property, go to its setButton method:

public void setButton(java.awt.Button button) {

    /* Get the old property value for fire property change event. */

    java.awt.Button oldValue = fieldButton;

    /* Set the button property (attribute) to the new value. */

    fieldButton = button;

    /* Fire (signal/notify) the button property change event. */

    firePropertyChange("button", oldValue, button);

    return;

}                

Make a simple change -- change the line

java.awt.Button oldValue = fieldButton;

to

java.awt.Button oldValue = null;

This makes sure that when you set the property, it's really seen as a change when firePropertyChange is called.  Otherwise, if you press the same button twice in a row, the property change event will not get fired the second time.

Next, set up connections for the "real work".  Connect the button event to the methods you want to call.  Make sure you select the button method and not the property.  If you select the "Connect->Button" from the pop-up menu of the trigger, you're really telling VisualAge to make a "property-to-something" connection.  We really want an "event-to-something" connection.  For this example it won't matter, as VisualAge will know what you really mean.  But if you wanted the change to be used to set another bean's property to something else like a constant, VisualAge would make a property-to-property connection, which is incorrect.

Read that paragraph fifty times until you're really lost.

Bottom line: don't select the "Connect->button" option from the trigger's pop-up menu; do select the "Connect->All features" option and select "button" from the event pane.

So make three connections from the trigger to call the three methods in the "kernel" object (the one with  appendToLabel, makeTone, speak.)  Tear off the button property of the trigger, and use its label property as the parameter to those connections.

Finally, set up a connection from each button's actionPerformed event to the button property of the trigger object, setting the button property to the "this" property of the Button.  (An alternative for this particular example would be to have the trigger have a String property and set it to the Button's label property.)

You've just saved two connections per button minus the three connections that the trigger is source for; 21 connections saved!

But you've added an extra event in the process.  Isn't that slower?

Yes, we've added an extra event.  But that's not going to add any noticeable delay unless you're using a 4MHz machine.  OK, maybe 33MHz... I dunno.

The key here is that we'll take a negligible time hit for a monster gain in maintainability.  The fewer connections you have, the fewer mistakes you could make, and the easier it is to make a change.