Skip to main content

Scratch

August 10, 2004

{cs.r.title}










Contents
Installation
A Guided Tour of Scratch
   Developer's Tour
Source Code Walkthrough
   Scratch
   ScratchDao
   ScratchList
   ScratchForm
   ScratchCanvas
   ScratchController
Conclusion

All of the hype around J2ME these days seems to center around game development on cell phones. While this is certainly an exciting application space, it is important to remember that not all graphical applications are games, and not all business applications are limited to text.

Scratch is an open source solution that allows you to capture signatures on a touchscreen-enabled J2ME device. While many J2ME applications seem to require cutting-edge APIs that can run on only a handful of high-end models, Scratch's requirements are bare minimum -- nothing but CLDC 1.0 and MIDP 1.0. You can run it on a low-end, sub-$100, black-and-white Palm device. I don't know of any J2ME devices other than Palms that have touchscreens, so Palms will be the target platform for the remainder of this article. If there are others out there, and you can successfully run Scratch on them, I'd love to hear about it.

Scratch can be run as a standalone program, or it can be customized and integrated into your application. The name "Scratch" has a bit of a double meaning -- it alludes to the obvious "scratchpad" functionality, while also paying homage to the adage, "Open source applications are written to scratch a particular itch." My itch was a simple solution for capturing signatures using off-the-shelf hardware and software. Your itch might be a general purpose notepad or a rudimentary drawing widget. Scratch should do to the trick.

In the spirit of full disclosure, I should tell you what Scratch doesn't do. Scratch does not do handwriting recognition. It is not meant to be a Graffiti replacement. It doesn't allow you to use multiple colors or even have an eraser. It is a simple black-and-white WYSIWYG drawing program. If your particular need runs in one of these other directions, Scratch is a jumping-off point -- that's the beauty of an open source solution. OK, the real beauty of an open source solution would be to provide you with a complete solution to your problem out of the box. The typical cranky open source developer's response to this would be something like, "Scratch your own stupid itch -- I'm busy right now."

A future release of Scratch will include a JSync Conduit that will pull the drawings from the Palm during the HotSync process and store them on the host machine's hard drive. Once you have control of the HotSync process, there is no limit to how you could extend Scratch. You could push an image up to a web server as a SVG (Scalable Vector Graphic). You could use Apache Batik to transform them into the image format of your choice. But that, as they say, is a project for another day.

Installation

To get started, you should download Scratch. Go to the project document list and download the scratch4j-1.01.zip bundle. Unzip it to the directory of your choice (for example, c:\apps\scratch4j). I'll refer to this directory as $SCRATCH_HOME from now on.

Inside $SCRATCH_HOME/bin, you'll find compiled binaries ready for installation. Scratch4j.jar and Scratch4j.jad can be deployed to any J2ME device, and Scratch4j.prc is ready to be installed on a Palm PDA.

To run the application, you have two choices: either run it on an actual Palm PDA or download the free emulator. For more information about the Palm OS Emulator (POSE) and the Palm OS5 Simulator, go to Palm's site.

Of course, to run Scratch on a Palm, you'll need to have a JVM (or KVM, in J2ME parlance) installed. Look for an application labeled Java HQ. Most modern Palms come with the KVM preinstalled. If yours didn't, you can download it from the MIDP for Palm OS page. MIDP 1.0 for Palm will run on PalmOS 3.5 and higher. The installation also comes with a Converter that allows you to transform JARs and JADs into PRCs (the native Palm format for applications). If you plan to do any J2ME/Palm development, you should have this handy.

Finally, if you want to customize Scratch, you'll need a copy of the Java 2 Platform, Micro Edition Wireless Toolkit (WTK). To download it, go to its home page. For installation and configuration instructions, check out the Wireless Development Tutorial, Part 1. For the sake of simplicity, this article assumes that you are doing your development on a Windows platform. There are similar tools out there for ambitious Linux and Mac OS X J2ME developers.

A Guided Tour of Scratch

Now that you're done with the scavenger hunt that plagues all J2ME developers, let's take a look at the fruits of your labor.

Scratch is composed of three basic screens. The main screen, shown in Figure 1, is a list of all of your signatures.

Figure 1. Main Scratch screen
Figure 1. Main Scratch screen

To create a new signature, click on the New button. Deleting items is as simple as highlighting an item and clicking Delete.

Click on the arrow next to any item in the list, and you will get a form showing you the details of the signature. From the form, you can open a canvas that displays the actual signature, as seen in Figure 2. Click Save and the signature will be written to the filesystem.

Figure 2. Signature canvas screen
Figure 2. Signature canvas screen
Developer's Tour

If you are happy with Scratch's functionality out of the box, then you are done. Happy trails. If, however, you'd like to customize Scratch, keep reading.

The first thing you should do is get the project set up in the WTK. Here are the steps to create the Scratch4j project in the WTK.

  1. Start the WTK; it's cleverly labeled KToolbar.
  2. Click New Project on the toolbar.
    1. Project name: Scratch4j
    2. MIDlet Class Name: org.scratch4j.ScratchController
    3. Click Create Project.
  3. Set Target Platform to MIDP 1.0 and click OK.

Figure 3 shows the New Project window described above.

Figure 3. Setting up WTK project
Figure 3. Setting up WTK project

This will create a stubbed-out directory structure for the project under the $WTK_HOME/apps directory. Copy $SCRATCH_HOME/src to $WTK_HOME/apps/Scratch4j/src. You'll also want to copy $SCRATCH_HOME/palm to $WTK_HOME/apps/Scratch4j/palm. The palm directory contains the conversion script that will take your JAR and JAD files and transform them into a PRC.

To verify that everything is OK up to this point, click on the Build button on the toolbar. If you don't get any error messages during the compile, you should be in good shape. Check out $WTK_HOME/apps/Scratch4j/bin. You should see Scratch4j.jar and Scratch4j.jad.

To complete the build for the palm device, run $WTK_HOME/apps/Scratch4j/palm/convert.bat. After you run it, you should see Scratch4j.prc in $WTK_HOME/apps/Scratch4j/bin. Converter.jar is a part of the MIDP 1.0 for Palm download. It is an executable JAR with a GUI, but the GUI doesn't allow you to do one important thing -- set the Creator ID of the Palm app. If you plan to write a custom JSync Conduit (which allows you to extract info from the Palm to the host machine during the HotSync process), you need to register for a unique Creator ID with Palm. See the Palm OS Developer Program for details.

Source Code Walkthrough

Now that your build environment is set up, let's look at the six classes that make up Scratch.

  • Scratch: The base object, a JavaBean.
  • ScratchDao: Stores and retrieves Scratch objects from the
    filesystem.
  • ScratchList: The main screen, which shows a list of signatures.
  • ScratchForm: Shows the details of a signature.
  • ScratchCanvas: The drawing portion of the application; shows the actual signature.
  • ScratchController: The brains of the operation; ties everything together.

If you are familiar with the MVC (Model/View/Controller) pattern, you should feel right at home in Scratch. For those of you who aren't, here is a 30-second overview.

The Model stores the data. In our case, the model is the Scratch object.

The View is the GUI. Scratch has three screens: ScratchList, ScratchForm, and ScratchCanvas.

The Controller is the glue that holds everything together. It passes messages between the Model and the View. In our case, every button click from the View goes through the Controller and gets converted into an instruction for the persistence layer (retrieve, insert, update, or delete).

The whole point of a MVC framework is to enforce a clean separation of concerns. In other words, your View should not contain any persistence artifacts. For example, if your View iterated through a ResultSet, you would be tied to using JDBC for your Model. Later, if you chose a different persistence strategy such as XML, you would have to rewrite both your Model tier and your View tier. If you keep your View neutral and have it iterate through a generic Vector, you can swap out Models easily at any point during the development process.

The reverse holds true as, well -- the Model shouldn't make assumptions about how the data is going to be presented. It shouldn't pre-format the data as HTML, Swing elements, or anything else. It should return the data in a View-neutral manner.

The Controller is the go-between. Since your Model and View aren't directly dependent upon one another, the Controller allows you to mix and match them. You could have several Views that use the same Model, or a single View that gets its data from several disparate Models. The Controller is what allows this magic to happen.

Let's see how Scratch implements the MVC pattern. Here is a description of each class in the application.

Scratch

The Scratch object is pretty straight forward. It is a simple JavaBean that represents an individual signature (the Vector named lines) and its metadata (height, width, and name). If you would like to store additional metadata about the signature, you can create your own getters and setters here. (Remember that MIDP doesn't support Float or Double values.)

The toString() method is used for display on the main screen (ScratchList). The static methods getDelimiter() and setDelimiter() allow you to programmatically change the separator character from the default (|). If you add additional fields, you'll most likely want to add them to toString().

RMS (Record Management System) is the I/O subsystem for J2ME applications. The methods getBytes() and setBytes() allow ScratchDao to easily serialize and deserialize the data from storage.

Finally, getSVG() is a convenience method that allows you to quickly dump the Scratch object out as a SVG string. The style (stroke:black; stroke-width:3) is hardcoded in this method. If you wanted to parameterize these values, you could either create class variables or instance variables to facilitate this.

The Scratch MIDlet doesn't use getSVG() directly. A custom conduit, however, could use this to quickly save the signature out in a renderable format that is also plain ASCII and therefore easy to transport via HTTP or web services. The source code for getSVG() is shown below. Notice that no XML or SVG framework is being used. When resources are tight and objects are simple, sometimes hand-rolling your own XML output is the easiest way to go.

  public String getSVG()
  {
    StringBuffer sb = new StringBuffer(300);
    sb.append("\n<svg height="" + getHeight() +
             "" width="" + getWidth() + "">");
    sb.append("\n\t<desc>" + getName() + "</desc>");

    sb.append("\n\t<g style="fill:none; stroke:black; " +
              "stroke-width:3">");

    for(int i=0, size=lines.size(); i < size; i+=4)
    {
      sb.append("\n\t\t<line x1="");
      sb.append(((Integer)lines.elementAt(i)).intValue());
      sb.append("" y1="");
      sb.append(((Integer)lines.elementAt(i+1)).intValue());
      sb.append("" x2="");
      sb.append(((Integer)lines.elementAt(i+2)).intValue());
      sb.append("" y2="");
      sb.append(((Integer)lines.elementAt(i+3)).intValue());
      sb.append(""/>");
    }

    sb.append("\n\t</g>");
    sb.append("\n</svg>");

    return sb.toString();
  }
ScratchDao
ScratchDao handles all of the persistence for the application. A DAO (Data Access Object) is a layer of abstraction -- it allows everything upstream to think in terms of Vectors and JavaBeans and insulates the messy details of persistence from the rest of the application. Scratch uses the native RMS subsystem for storage, but there are other J2ME-enabled databases out there. If you chose to use one of them in place of RMS, the changes to the application would be limited to this one class. I didn't create a DAO interface or a factory class for the sake of simplicity, but this would be an ideal place to extend the application if you needed to support multiple persistence strategies.

ScratchList

This is the first of three GUI screens in Scratch. It is the main screen that you see when you run the application. It simply walks through the Vector of Scratch objects passed to it, calls toString() on each, and displays them on the screen. All button clicks are passed back to the CommandListener, which in our case is ScratchController.

ScratchForm

Click on any item in the ScratchList, and this form will be displayed. It allows you to store metadata about the Scratch object. Since Height and Width are derived from the physical dimensions of the ScratchCanvas screen, they don't show up here. If you add any additional fields to the Scratch object, this would be the place to allow users to fill in the values. As with the ScratchList, all button clicks are handed back to the CommandListener. Again, ScratchController is the CommandListener.

ScratchCanvas

This is the screen that allows the user to write out his or her signature. The signature is stored as a series of lines. Each line has a starting point (x1, y1) and an ending point (x2, y2).

The method that does the actual drawing on the screen is paint(). Depending on what mode the canvas is in, paint() will do one of three things:

  1. clearMode means that the user clicked the Clear button. To clear the screen, paint() draws a white rectangle that has the dimensions of the screen. Here's the portion of paint() that handles clearMode.
        if(clearMode)
        {
          clearMode = false;

          //set background to white
          g.setColor(255,255,255);
          g.fillRect(0,0, getWidth(), getHeight());

          x1 = 0;
          y1 = 0;
          x2 = 0;
          y2 = 0;

          return;
        }
  2. buildMode means that the canvas should redraw an existing signature for display purposes. The Scratch object contains a Vector of Integers named lines. paint() iterates through these, four Integers at a time, using them as x1, y1, x2, and y2 for drawLine() calls.
        else if(buildMode)
        {
          buildMode = false;
          g.setColor(0,0,0);

          for(int i=0, size=lines.size(); i<size; i+=4)
          {
            g.drawLine(
                ((Integer)lines.elementAt(i)).intValue(),
                ((Integer)lines.elementAt(i+1)).intValue(),
                ((Integer)lines.elementAt(i+2)).intValue(),
                ((Integer)lines.elementAt(i+3)).intValue()
                );
          }

          return;
        }
  3. drawMode means that the user is actively drawing a signature. When the user presses the stylus to the screen, pointerPressed() is invoked. This stores the starting point of the line (x1, y1). When the user stops moving the stylus, pointerDragged() is called. This captures the end point (x2, y2), and calls repaint() (which in turn calls paint()). The line gets drawn to the screen and saved to the Vector.
        //If we get to this point, we are neither
        //clearing the screen (clearMode) nor building it
        //from an existing Scratch object (buildMode).
        //This means that we are in the implicit
        //"drawMode". drawMode means that the user
        //is interactively drawing on the screen.

        //set pen color to black
        g.setColor(0,0,0);
        g.drawLine(x1, y1, x2, y2);

        //persist data
        lines.addElement(new Integer(x1));
        lines.addElement(new Integer(y1));
        lines.addElement(new Integer(x2));
        lines.addElement(new Integer(y2));

        //new starting point is the current position
        x1 = x2;
        y1 = y2;

All button clicks (Save, Back, or Clear) are sent back to the CommandListener for processing. Once again, ScratchController is our CommandListener.

ScratchController
ScratchController is Command Central. All messages come into this class and are then dispatched out to their appropriate destinations.

Every button click gets handled by the commandAction() method. The two parameters of the commandAction() method are the button that was clicked (Command) and the screen where the button was displayed (Displayable). Based on this information, commandAction() performs the necessary logic and displays different screens based on which button or menu item was selected.

  public void commandAction(Command c, Displayable d)
  {
    if(c.getLabel().equals("Exit"))
    {
      destroyApp(false);
      notifyDestroyed();
    }
    else if(c.getLabel().equals("About Scratch"))
    {
      displayAboutScreen();
    }

   ...

Conclusion

Capturing signatures in the field doesn't have to cost a fortune or run on proprietary handheld devices. Scratch should allow you to do this with a minimum of effort.

When I'm evaluating a new open source project, there are three questions I usually ask:

  1. Can I run it out of the box?
  2. Can I set up the build environment easily?
  3. Is the design transparent/self-evident enough for me to easily customize it?

Hopefully Scratch (and this article) satisfies each of those requirements for you. If not, I'd love to hear from you.

For further reading on the basics of J2ME development, J2ME in a Nutshell is an excellent guide; a five-part online series of excerpts is available on ONJava.

Scott Davis is a senior software engineer and instructor in the Denver, Colorado area.
Related Topics >> Mobility   |   Programming   |