Issue 65 * February 12 2009

Meet your new friend, Behaviors
With Revolution 3.5, potential tragedies can have a happy ending

by Trevor DeVore

The other day I started working on a new desktop application in Revolution. Usually I'm happy to have the native operating system appearance for my software. But this application is a complement to an existing Web application and I needed to mimic the look-and-feel of the website, down to pixel precision. The website contains numerous non-standard, custom option menus that look something like this:

Custom Option Menu
Stylized Option Menu

So I set out to create a custom control that provided the same appearance by assembling various Revolution objects. Here is what I ended up with:

  1. A field that displays the "label" of the menu.
  2. A field that displays the category of the menu
  3. A button whose icon is the triangle image.
  4. A hidden popup button that is displayed when the user clicks on the menu.

All of these controls were contained in a group, as follows:

Group of object comprising the Option menu.
My group as it appears in the Application Browser

Control group in Revolution
My group as it appears on-screen

So far, so good. But now that I had the controls grouped together, I had to script all of the user interactions that I would normally get "for free" had I used Revolution's built-in Option menu. Once I had the basics of the control in place, I started using it in the application. The first card I had to work on required five instances of this custom menu control. Of course, as I continued putting the application together, I had to go back to my custom control's script to fix bugs or add new functionality. Now, on a normal day I would have grown weary of changing the group script in one of the custom controls and then copying and pasting the changes into the other four instances. Each time a change was made I would have repeated this same exercise over and over again. But this was no ordinary day. No, this was a special day because I was using the developer preview release of Revolution 3.5, which introduces a new feature called Behaviors, or "parent scripts." Rather than copying and pasting my code between the five groups each time a change was made, I simply updated the script of a single button and the behavior of all five of my custom controls was instantly -- if not magically -- updated.

Introducing parentScript Behaviors
What is a parentScript? This new feature enables sharing of code in Revolution like never before because it allows you to easily share behaviors between your objects without duplicating scripts. Revolution has accomplished this by adding a new 'parentScript' property to all objects. The 'parentScript of' an object is a reference to a button whose script becomes part of the message path for that object. The parent script sits behind the object and in this sense acts as a sort of personal backScript to the object. In order to put this new property in context, let us first look at a diagram showing how the closeField message would be passed down the message chain if the parentScript property of a field was assigned to the "ParentScript" button.

parentScript message path
A parentScript inserts itself just after the script of an object,
but before groups and cards.

Notice how the "ParentScript" button script receives the message right after the field control. The field appears to have it's own personal backscript, right? Yes, but it is even better than just having a private backscript. What is really cool is that the script in the "ParentScript" button thinks it is the script of the field control.

The Importance of 'me'
Let's look at what this case of "flexible" identity means to us developers. Normally, the keyword 'me' refers to the object that contains the currently running handler. If I have a script in a field with the line:

put the text of me

Then 'me' refers to the field the script is in. But in the context of a parent script 'me' refers to the control the parent script is attached to, not the object where the script actually resides. So while writing "put the text of me" in a button would normally return the text of the button, when that button is the parentScript of a field, that same code would return the text of the field. In practice this means you can use the 'me' keyword throughout your parent scripts and the code will always refer to whatever object you attach it to.

Because of how 'me' is resolved in parent scripts you'll find it easy to migrate your existing handlers. You can simply copy and paste code that once resided in a field or group into a button and it will more than likely work if you used 'me' references throughout. I was able to convert one such script in under 10 minutes.

Sharing Behaviors
Now that we have a little background on parent scripts we are going to look at two examples that demonstrate how you can share behaviors using them. The first example is a field that formats user input. In the diagram below you can see that there are two fields, both of which require that any input be a number. One is for entering a dollar amount and the other is for entering a number. Whenever the closeField message is received, the script makes sure that a number is displayed in the field.

Without parent scripts you would have to copy the script into each field that required numeric input or add a closeField handler somewhere in the message path (frontScript, group, card, stack, library or backScript) that determined whether or not the control receiving the closeField message required numeric input.

Neither solution is optimal:

  • In the first case where you are copying script lines, every time you want to enhance the behavior of the script or correct a bug, you have to make your edits twice. As your scripts grow longer and more complex, errors inevitably creep in.
  • In the second case, where you are placing code at the group or card level, you need to check whether the target of the closeField message is one of the fields you want to convert to a numeric value, otherwise you'll be over-writing valid text entry in the other fields. And, if you add new fields that require numeric entry, you'll have to modify the group or card script to add that special case. Your code spends more time deciding whether it should trigger than handling the behavior itself, and gets cluttered up with if statements. Messy, messy!

But with parent scripts you simply create a single button (mine is named "Number Formatter") and add the closeField handler to it. Once you assign the button as the parentScript of a field, that field will automatically start converting any input into a number.

Sharing code with parent scripts
With parent scripts, your code resides in a single location
but can be reused by multiple controls.

Here's another example. Mac OS X and Windows operate very similarly, but have some important differences in their user interface requirements. One of the most annoying is that the position of the "OK" and "Cancel" buttons is swapped. While Revolution handles most interface differences for you automatically, it won't touch your custom modal dialogs (which are usually implemented as substacks). If you want to have a nice, cross-platform application then you either have to pick one or the other way of handling these buttons (upsetting the nitpickers on the other platform, or possibly leading to the wrong button being clicked by accident), or you have to code a solution that automatically arranges the buttons properly. Not a problem if you have only one custom dialog, but how about if you have several? It becomes a headache for the same reasons listed above.

The solution is a parent script that arranges controls based on platform:

Parent script that is shared by two separate dialog substacks
Parent script that is shared by two separate dialog substacks

With the introduction of parent scripts Revolution 3.5 will change the way that behaviors are shared in Revolution. Not only can you easily create and reuse behaviors in your own applications, but this opens the door for 3rd party developers to create and share useful custom controls with the Revolution community.

About the Author

Trevor DeVore is a partner in Blue Mango Learning Systems, creator of Screensteps and long time Revolution user.


Main Menu

What's New

Get One Day Training