MetaCard Corporation

A simple MetaCard calculator application

To give you an idea of what's involved in developing a GUI application using an interactive development environment, this article will describe the steps needed to build a simple application in MetaCard. The application is a simple calculator. To make the example even simpler, this calculator with actually just build up an expression that will be evaluated with the MetaCard "value" function when the "=" or return key is pressed. This saves the trouble of handling things like operator precedence (the "value" function handles this automatically) and allows us to implement a unique feature: a backspace key. Due to its simplicity, this sample application was developed in about 15 minutes from concept to complete implementation.

The complete application can be acquired with anonymous FTP from as calc.mc from ftp.metacard.com:/MetaCard/contrib/ or can be run directly from your UNIX WWW browser if you've got MetaCard configured to be a helper application. See the Get MetaCard page for instructions on setting up MetaCard as a helper application. After you've got MetaCard configured, just click on this Calculator link to run it.

The application interface is created using MetaCard's built-in Interactive Design Tool (IDT). Similar to other UNIX IDTs such as X Designer and Builder Xcessory and Windows tools like PowerBuilder and Visual Basic, the MetaCard layout tools allow you to create controls, position them, and change properties such as the colors and fonts used to draw the controls.

The first step in creating an application is to create a new window and name it. Next you populate the application window with the necessary buttons, text fields, scrollbars and other controls.

Screen Shot

Figure 1: Screen Shot of the Finished Calculator

After the interface looks about right (Figure 1), it's time to add the scripts that make it functional. To add a script to an object, you open the built in script editor by clicking on the "script" button in the "properties" dialog for a selected object. These scripts are written in a language called MetaTalk, which is a superset of the HyperTalk language used in HyperCard.

A MetaTalk script is broken into functions called "handlers", each of which handles a particular "message". Messages are sent as the result of user action, or as the result of a call from another handler. For example, the calculator application script contains the following handler, which handles the messages generated when the user clicks on one of the buttons:

on mouseUp
  if word 1 of the target is "button"
  then handle_key the short name of the target
end mouseUp
Since in this application the buttons don't have individual scripts, the messages sent to the buttons are passed up to the buttons' parent, which in this example is the "card" (which is roughly equivalent to the main XmForm widget in a UNIX Xt/Motif application). This being the case, the card's handlers get called each time the user types a key or clicks in the application's window. While this architecture can be very convenient, there is one complication: the script must distinguish clicks on buttons from clicks on the "Display" field and from clicks on the card itself. Using the "target" function, which returns the type and name of the object the message was originally sent to, is one way to do this.

The complete script for the calculator application is shown below. Most of the work is done in the "handle_key" handler. It removes and restores the "0" that should be displayed when the display has no other value, and uses the MetaTalk "value" function to evaluate an expression that the user has entered. Note that all number-to-string (and back) conversions are done automatically, and there is no need to specify the type any of the variables. The next 4 handlers handle the messages sent when the user presses special keyboard keys, each of which generates a specific message. Each of these handlers in turn calls the "handle_key" handler with a corresponding key name.

# handle keystrokes and button presses
on handle_key which
#suppress leading 0
  if field "Display" is "0
  then put empty into field "Display"
  if which is "="
  then put value(field "Display")\
       into field "Display"
  else if which is "C"
    then put 0 into field "Display"
    else if which is "BS"
      then delete last char of field "Display"
      else put which after field "Display"
#put 0 back into display if needed
  if field "Display" is empty
  then put 0 into field "Display"
end handle_key

on returnKey
  handle_key "="
end returnKey

on enterKey
  handle_key "="
end enterKey

on deleteKey
  handle_key "BS"
end deleteKey

on backSpaceKey
  handle_key "BS"
end backSpaceKey

on keyDown whichkey
#make sure user pressed a valid key
  if whichkey is in ".0123456789+-*/=C"
  then handle_key whichkey
  else beep 1
end keyDown

# since the buttons don't have scripts, all the
# mouseUp messages end up here.  Check to make
# sure that user clicked on a button and not
# the card or "Display" field, then handle the
# key specified by that button (the short name
# is the text displayed as the button's label).

on mouseUp
  if word 1 of the target is "button"
  then handle_key the short name of the target
end mouseUp

A generic "keyDown" message generated when the user presses one of the alpha-numeric keys on the keyboard. A single parameter, the key the user pressed, is passed. In this keyDown handler, the parameter is put into the variable "whichkey". If the key pressed is valid (it appears in the validation string checked with the "is in" operator), it's passed on to the "handle_key" handler. If not, the application beeps and throws away the key.

To keep the application simple, no other input validation is performed. This isn't as serious a deficiency as it would be with a C based program, however. If the user tries to specify an illegal operation (e.g., divide by zero, or entering two operators in a row), the standard MetaCard error dialog appears when the "value" function is executed. While this isn't all that user-friendly, it's certainly superior to the core dump you'd get with a C program that does too little input validation.

If a more polished interface is required, it would be trivial to add checking for invalid operations. It is even possible to override the standard error dialog if you want to rely on the MetaCard run-time system to catch the errors, yet bring them to the users attention with a more informative message than is given in the standard error dialog.

Note that in this script the object specifications in MetaTalk (e.g., field "Display") is done by description rather than by specifying a variable as is done in Motif (and in most other scripting languages for that matter). The description can either be the name of the object, its id (a unique number assigned to the object when it is created) or by number. For example, "field 1" is the first text field that was created in this application with the IDT.

It is also possible to store an object description in a variable and use the variable to refer the object as is done in other languages:

put "field Display" into somevar
set the backgroundColor of somevar to "red"
The disadvantage of this technique is that the resulting code is much less readable code that uses descriptions, especially when the variable initialization is done in a different place than the use of the variable.

Testing and debugging

After typing the script into the script editor and clicking on the "Ok" button, the script is ready to test immediately. No need to run a compile or link, or to restart the application and run it to the point needed to test the new code. This makes it possible to develop the application iteratively. If a dialog box doesn't look right or behave intuitively, you can change it immediately. This is in sharp contrast to conventional tools where a lot of code will frequently have to be discarded if any substantial changes have to be made in the controls used to implement an application.

If there are serious errors in a script, the interpreter will stop and open a dialog box that points out the nature of the problem and ask if you want to fix it. If you click on the "script" button in the error dialog, the script editor with the offending script in it and will position the cursor on the statement that caused the error. You can then fix the error and continue immediately. This is in contrast to a typical Windows or Xt/Motif development environment where errors usually result in an application crash (or maybe even a system crash) which means you have to restart the application in a debugger and repeat the exact sequence of steps that caused the error. Worse still is the case where you have to recompile a module or library with symbols if it was originally compiled without them.

Deploying the application

As with most Interactive Development Environments, to deploy a MetaCard application, just two files are required: the stack (application) and the MetaCard engine (equivalent to a dynamic Xm library or DLL, but much smaller). Both the stack and the engine can be any place on the PATH. No .Xdefaults files are required on UNIX systems, so the installation procedure doesn't require the root permissions typically required to install application resource files in /usr/lib/X11/app-defaults. If your application uses MetaCard resources such as icons, cursors or dialog boxes that haven't been moved into your application stack, the file "mctools.mc" must also be included in your distribution, or the "Resource Mover" dialog used to move the necessary components from the MetaCard tools stack into your application. Like the engines, MetaCard tools stack components can be distributed free of royalties.

Another advantage of not requiring a compiler to build your application is that you can even deploy your application on other platforms without having to build a separate binary for each. In fact, you don't even have to *have* a machine of the architecture you're deploying on. Just provide instructions about where to acquire the engine for the target platforms (all MetaCard binaries are available from the MetaCard FTP site ftp.metacard.com/MetaCard), or include the engine appropriate to the target platform in your distribution.

White Papers | High-Level Tools . Calculator . TOP . Comparisons . Strained Carrots