Skip to main content

If you don't have an IBM ID and password, register here.

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

Custom GUI development with MIDP 2.0

Build custom GUI elements, with the new, extendable CustomItem class

Mikko Kontio (mikko.kontio@softera.fi), Technology Manager, Softera
Mikko Kontio works as a Technology Manager for the leading-edge Finnish software company, Softera. He holds a Masters degree in Computer Science and is the author and co-author of several books, the latest being Professional Mobile Java with J2ME, published by IT Press. Mikko can be reached at mikko.kontio@softera.fi.

Summary:  MIDP 2.0 is an exciting step forward for user-interface development on MIDP. In this article, wireless developer Mikko Kontio uses a simple working exercise to introduce one of the most important new features of MIDP 2.0: the CustomItem class.

Date:  13 May 2003
Level:  Introductory

Comments:  

The J2ME MIDP (Mobile Information Device Profile) 2.0 has been out of the box since November 2002. In terms of scope and vision, the new profile is an improvement over the original. Whereas the original MIDP specification was seemingly designed to meet the needs of a limited device group, the new profile has a much better grip on the potential of handset technology. New gaming and audio APIs, extended security and networking capabilities, and OTA (over the air) provisioning make MIDP 2.0 a full-service wireless development profile. And to top it all off, the expanded user interface API will give your applications a better look-and-feel and expanded usability.

The new user interface API includes a class specifically intended for building unique or custom UI elements. CustomItem, like its parent class, Item, offers a simple framework for developing individual GUI forms. Unlike its parent class, CustomItem's base functionality can be extended easily and effectively, allowing for all kinds of variation on the standard Item template.

In this article I'll take the new MIDP 2.0 user interface API for a test drive. By developing a simple, custom GUI component (or Item), you will learn a little bit about the CustomItem class, as well as some of the other new features of MIDP 2.0.

What's new in MIDP 2.0

MIDP 2.0 brings many exciting new features to the MIDP UI API. I can't address all of them here, so I'll just go over some of the biggest changes, as well as introducing the new features I'll actually work with in the programming exercise that follows.

  • Display size: MIDP 2.0 introduces the concept of size to the Item and CustomItem classes. For every item, custom or standard, you can now set both the minimum display size and the preferred display size. An item's minimum size is the smallest size at which it can display and function properly. Its preferred size will yield minimum text wrapping and optimum display results. Whereas components developed with the Item class can take standard display settings, the minimum and preferred settings have to be established manually for CustomItems.

  • Interaction modes: CustomItems can take both keypad and pointer input. Modes of interaction are KEY_PRESS, KEY_RELEASE, KEY_REPEAT, POINTER_DRAG, POINTER_PRESS, and POINTER_RELEASE. For every interaction, the application must find out which of the modes is supported by calling the getInteractionModes() method, which returns a bitmask of the available interaction modes.

  • User input: A subclass of CustomItem makes it easy to create interactive components such as spreadsheets or calendars. The class allows users to revise or update content directly in an existing component or in a secondary component such as a TextField. Revisions that have been entered into a secondary component are automatically copied into the original component when the session is complete.

  • Traversal: There are two kinds of traversal: internal and external. Internal traversal is the movement within a given component, such as the movement of the cursor between one cell and another cell. External traversal is the movement between one component and another in a Form, such as the move from a TextField to a ChoiceGroup.

Now, I'll put some of these exciting new features to work building a custom GUI element.


Building a custom element

The CheckItem element is a simple GUI element that gives you a choice of any two options; in the case of my example it will be Male or Female. You likely have some experience with this type of element, which is normally created using the standard MIDP class ChoiceGroup. My CheckItem class will emulate the functionality of the ChoiceGroup, but I'll develop it from scratch using the CustomItem class.

Figure 1 shows a Form that includes two TextItems and our simple CheckItem element.


Figure 1. The CheckItem element
The CheckItem element

In Listing 1 you can see the skeleton of my new CheckItem class. Because CustomItem is an abstract class it must be subclassed to enable the desired functionality. Because I want my CheckItem to be able to accept commands, such as Edit, it will implement the ItemCommandListener class. The ItemCommandListener class was introduced with the MIDP 2.0 specification. It enables me to set command listeners for a particular item on a form, rather than setting one listener for the whole form.


Listing 1. The beginnings of a CheckItem class

package com.kontio;

import javax.microedition.lcdui.*;

public class CheckItem
    extends CustomItem
    implements ItemCommandListener {

    public CheckItem (String title, Display d, String caption1, String caption2) {
    }

    protected int getMinContentHeight() {
    }

    protected int getMinContentWidth() {
    }

    protected int getPrefContentHeight(int width) {
    }

    protected int getPrefContentWidth(int height) {
    }

    protected void paint(Graphics g, int w, int h) {
    }

    protected boolean traverse(int dir, int viewportWidth, int viewportHeight,
                               int[] visRect_inout) {
        return true;
    }

    public void commandAction(Command c, Item i) {
    }

    protected void sizeChanged(int w, int h){
    }
}


The get methods for minimum and preferred width and height are defined abstract in the CustomItem, so I have to implement them. In these methods I can either calculate or directly define the minimum and preferred width and height of each item. Another option that I have not utilized in this example would let me handle size change within the item, such as when the system reduces or expands the size of the available screen. The sizeChanged() method takes parameters that allow the application to redraw an item as its given size changes.

paint() is an abstract method whose job it is to paint the content of an item. The translation is set so that the upper left corner of my new item is at (0,0), so the application must paint every pixel within the item's area.

The traverse() method is called by the system whenever the user moves the cursor within or into the CheckItem. The traverse() method will return true if the traversal is internal and false if it should proceed out to another item in the form. Depending on the value returned, traverse() will either activate the item or just move the cursor around within the item. The method's parameters indicate the direction of traversal, the size of the viewable area, and other information about the area. It will be up to you to define when the traverse() method should return false, resulting in the activation of the next item on the form.


Implementing the CheckItem

The CheckItem has two basic functions: it responds to the movement of the cursor and sets the selected value (Male or Female in this example). Listing 2 shows the first part of CheckItem class, showing all the fields of the class, the implementation of the constructor, and the implementation of the get methods for minimum and preferred widths and heights. UPPER and LOWER are constants for the position of the cursor on the form. UPPER means that the cursor is on the form somewhere above the item, and LOWER means it's somewhere below the item. IN indicates that the cursor is inside the item. status is for keeping the position, location is the location of the item's own cursor, and checked is for the checked value.


Listing 2. The CheckItem class

public class CheckItem
    extends CustomItem
    implements ItemCommandListener {

    private final static int UPPER = 0;
    private final static int IN = 1;
    private final static int LOWER = 2;
    // status tells us where the cursor is on the form, UPPER, IN or LOWER
    private int status = UPPER;
    // location tells us where the cursor is inside the item
    private int location = 1;
    // checked tells which of the choices is selected
    private int checked=1;
    private String caption1;
    private String caption2;

    private final static Command CMD_EDIT = new Command("Edit", Command.ITEM, 1);

    public CheckItem(String title, String caption1, String caption2) {
        super(title);
        this.caption1 = caption1;
        this.caption2 = caption2;
        setDefaultCommand(CMD_EDIT);
        setItemCommandListener(this);
    }

    protected int getMinContentHeight() {
        return 40;
    }

    protected int getMinContentWidth() {
        return 95;
    }

    protected int getPrefContentHeight(int width) {
        return 40;
    }

    protected int getPrefContentWidth(int height) {
        return 95;
    }



The constructor is quite simple; it sets the title, the captions, and the command object. For the sake of an example, the get methods in Listing 2 return constants. In real life, of course, I would have to calculate height and width according to the size of the content or the available area of the item.

In Listing 3 I show the second part of the CheckItem class. As previously mentioned, the paint() method is responsible for the visual appearance of the item. In this example, the method paints a rectangle around the element with a dotted line, although some emulators and devices will automatically do this for you.

Next, the paint() method draws the circles, cursor, and labels for my checkbox. In this case, the "selected" circle is a filled arc of 360 degrees. For a more sophisticated GUI, I might use images rather than pixels to denote the circles. The CheckItem class could also use the sizeChanged() method to match the size of the circles to the size of the screen, or to fit better with other items in the form.


Listing 3. The paint() method

protected void paint(Graphics g, int w, int h) {
      // First the outer rectangle
      g.setStrokeStyle(Graphics.DOTTED);
      g.drawRect(0, 0, 94, 39);
      g.setStrokeStyle(Graphics.SOLID);

      // Then the circles
      g.drawArc(4, 4, 13, 13, 0, 360);
      g.drawArc(4, 22, 13, 13, 0, 360);

      // Then draw the selected value
      if (checked==1) g.fillArc(4, 4, 13, 13, 0, 360);
      else g.fillArc(4, 22, 13, 13, 0, 360);

      // Then the 'cursor'
      if (location==1) g.drawRect(2, 2, 90, 17);
      else g.drawRect(2, 20, 90, 17);

      // And finally the texts
      g.drawString(caption1, 22, 4, Graphics.TOP|Graphics.LEFT);
      g.drawString(caption2, 22, 22, Graphics.TOP|Graphics.LEFT);
    }




Listing 4 shows the third and final part of the CheckItem class: the traverse() and commandAction() methods. The traverse() method is called whenever the cursor has entered the item or traversal is occurring inside the item. The traverse() method is responsible for setting the inner state of the object so that it will be painted correctly. The parameter dir indicates the direction of traversal. Canvas.UP, Canvas.DOWN, Canvas.LEFT, Canvas.RIGHT, and CustomItem.NONE are all possible fields of the dir parameter.

In this case I ignore left and right and am only interested in UP and DOWN. If the direction is DOWN, the status will be checked. If the cursor has entered the item, the status will be set to IN. This ensures that the next traversal to occur will happen inside the element. If the cursor enters the element from above, and if it is the first traversal to occur in the form, the location will be set to 1, meaning the upper choice. As long as the traverse() method returns true, movement will occur within the element. When it returns false, the system can move the traversal outside of the element.


Listing 4. traversal() and commandAction()

 protected boolean traverse(int dir, int viewportWidth, int viewportHeight,
                               int[] visRect_inout) {
      switch (dir) {
        case Canvas.DOWN:
          if (status == UPPER) {
            status = IN;
          } else {
            if (location==1) location=2;
            else if (location==2) return false;
          }
          repaint();
          break;

        case Canvas.UP:
          if (status == LOWER) {
            status = IN;
          } else {
            if (location==2) location=1;
            else if (location==1) return false;
          }
          repaint();
          break;
      }
      return true;
    }

    public void commandAction(Command c, Item i) {
      if (c == CMD_EDIT) {
        checked=location;
        repaint();
        notifyStateChanged();
      }
    }

    public int getState(){
      return checked;
    }
}




The commandAction() method sets the active choice checked. In the emulator this happens both by choosing the Edit command and pressing the Choose (fire) button. notifyStateChanged() causes the form to notify the item ItemStateListener that the item's state has been changed. The last method is for checking which of the choices is or was selected.


Using the CheckItem

My new CheckItem class can be used and added to the form just like any other Item. For example, Figure 2 shows a CheckItem implementation for a quiz with three questions.


Figure 2. A CheckItem implementation for a quiz
A CheckItem implementation for a quiz

Listing 5 shows the CheckItemDemo class. In this example the instances of CheckItem were created inside the append method, but they could just as easily have been created elsewhere.


Listing 5. The CheckItemDemo class

package com.kontio;

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

public class CheckItemDemo extends MIDlet implements CommandListener {
    private final static Command CMD_EXIT = new Command("Exit", Command.EXIT, 1);
    private Display display;

    protected void startApp() {
        display = Display.getDisplay(this);

        Form mainForm = new Form("CustomItemDemo");

        mainForm.append(new CheckItem("How much is 8 divided by 2?", "3", "4"));
        mainForm.append(new CheckItem("What is the capital of France?", "Paris", "Milano"));
        mainForm.append(new CheckItem("Which is a mammal?", "Pike", "Dog"));
        mainForm.addCommand(CMD_EXIT);
        mainForm.setCommandListener(this);
        display.setCurrent(mainForm);
    }

    public void commandAction(Command c, Displayable d) {
        if (c == CMD_EXIT) {
            destroyApp(false);
            notifyDestroyed();
        }
    }

    protected void destroyApp(boolean unconditional) {
    }

    protected void pauseApp() {
    }
}





In conclusion

In real life, of course, it wouldn't make much sense to develop a custom CheckItem class when you could simply use the ChoiceGroup. The CheckItem was chosen merely for the sake of the exercise. To continue learning about MIDP 2.0, you may want to apply some of what you've learned here to building more useful custom elements, such as spreadsheets, image maps, and charts. See Resources to learn more about MIDP 2.0.


Resources

  • Visit the MIDP homepage to download MIDP 2.0.

  • OnJava.com's "Introducing MIDP 2.0" is a good starting place for learning about the new features of MIDP 2.0.

  • You can follow that up with Michael Abernethy's excellent primer, "Mobile device optimization with J2ME", which includes an overview of MIDP 2.0. (developerWorks, January 2003)

  • If you're completely new to MIDP (and J2ME), you may want to read Todd Sundsted's "J2ME grows up", which includes a good introduction to MIDP and MIDlets. (developerWorks, May 2001)

  • Soma Ghosh's "Think small with J2ME" offers an architectural overview of J2ME, including the role of profiles. (developerWorks, November 2001)

  • "Networking with J2ME" focuses on the networking capabilities of MIDP. (developerWorks, September 2002)

About the author

Mikko Kontio works as a Technology Manager for the leading-edge Finnish software company, Softera. He holds a Masters degree in Computer Science and is the author and co-author of several books, the latest being Professional Mobile Java with J2ME, published by IT Press. Mikko can be reached at mikko.kontio@softera.fi.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in

If you don't have an IBM ID and password, register here.


Forgot your IBM ID?


Forgot your password?
Change your password


By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. This profile includes the first name, last name, and display name you identified when you registered with developerWorks. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)


By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=12268
ArticleTitle=Custom GUI development with MIDP 2.0
publish-date=05132003
author1-email=mikko.kontio@softera.fi
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).