Java Programming MIDlet Graphics using the Canvas Class

Programming MIDlet Graphics using the Canvas Class

Java Programming Notes # 2588


Preface

This is Part 1 of a two-part lesson in a series of tutorial lessons designed to teach you how to write programs using the Sun Java Wireless Toolkit for CLDC. The first lesson was titled Getting Started with MIDlets and the Sun Java Wireless Toolkit for CLDC. The previous lesson was titled Programming MIDlets for Interactive Behavior (see Resources).

What you will learn

In this lesson, you will learn how to use several methods of the Canvas class (including paint and repaint), along with several methods of the Graphics class to draw text and lines on the cell phone screen. You will learn how to use anchor point coordinates to control the position of text that is drawn on the screen. You will also learn how to handle keyPressed events fired by a Canvas object.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

  • Figure 1. Partial class hierarchy for MIDP 2.0.
  • Figure 2. Output from MIDlet named Canvas01 in Sun emulator.
  • Figure 3. Sun cell phone emulator output for the MIDlet named Canvas02.

Listings

  • Listing 1. The main class for the MIDlet named Canvas01.
  • Listing 2. Beginning of the member class named MyCanvas.
  • Listing 3. Draw eight lines and eight text strings.
  • Listing 4. Draw two more lines.
  • Listing 5. Beginning of the class for the MIDlet named Canvas02.
  • Listing 6. Remainder of the main class for the MIDlet named Canvas02.
  • Listing 7. Beginning of the member class named MyCanvas.
  • Listing 8. Beginning of the overridden paint method.
  • Listing 9. Remainder of the overridden paint method.
  • Listing 10. Overridden keyPressed method.
  • Listing 11. Source code for the MIDlet named Canvas01.
  • Listing 12. Source code for the MIDlet named Canvas02.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials. You will find a consolidated index at www.DickBaldwin.com.

General background information

If you are familiar with graphics programming in J2SE without the benefit of Java 2D and Java 3D, you will probably be reasonably comfortable with the material in this lesson. J2ME graphics is very similar to graphics programming in the early days of Java, but with some interesting new wrinkles.

Partial class hierarchy for MIDP 2.0

A partial class hierarchy for MIDP 2.0 is shown in Figure 1. Figure 1 includes all of the classes that are included in the package named javax.microedition.lcdui. In addition, Figure 1 includes three classes that are in other packages.

Figure 1. Partial class hierarchy for MIDP 2.0.

  • Object
    • Displayable
      • Screen
        • TextBox
        • Alert
        • List
        • Form
      • Canvas (abstract)
        • GameCanvas (abstract)
    • Display
    • Ticker
    • AlertType
    • Image
    • Item
      • Gauge
      • ChoiceGroup
      • CustomItem
      • DateField
      • ImageItem
      • Spacer
      • StringItem
      • TextField
    • Timer
    • TimerTask
    • Command
    • Graphics
    • Font

Classes to be illustrated

I have discussed and illustrated the classes shown in boldface Italics (plus the Choice interface, the CommandListener interface, and the ItemCommandListener interface) in earlier lessons (see Resources). I will discuss and illustrate the following classes in this lesson:

  • Canvas class
  • Graphics class
  • Font class

I will discuss and illustrate the GameCanvas class in a future lesson.  I will leave CustomItem as an exercise for the student.

The Canvas class

Here is part of what Sun has to say about the Canvas class:

“The Canvas class is a base class for writing applications that need to handle low-level events and to issue graphics calls for drawing to the display. Game applications will likely make heavy use of the Canvas class. From an application development perspective, the Canvas class is interchangeable with standard Screen classes, so an application may mix and match Canvas with high-level screens as needed. For example, a List screen may be used to select the track for a racing game, and a Canvas subclass would implement the actual game.”

The use of the Canvas class and the GameCanvas class for programming games will be the topic of a future lesson. In this lesson, I will concentrate on using the Canvas class for presenting graphic information on the cell phone screen, and handling key events that are fired by a Canvas object.

Yes, I really did mean key events

Unlike the commands that we studied in an earlier lesson, the Canvas class provides the ability to detect and handle key events in a manner that is very similar, but not identical to the JavaBeans or Delegation event model in J2SE (see Resources).

Pointer events

The Canvas class also provides the ability to detect and handle pointer (mouse like) events on hardware implementations that support them.  However, in these lessons, I am constrained to the use of the Sun cell phone emulator, which does not appear to support pointer events. (If it does support pointer events, I haven’t figured out how to make it do so.) Therefore, I will have very little, if anything, to say about pointer events.

Canvas also supports commands

Just like other Displayable objects, Canvas objects also support commands such as EXIT, BACK, OK, etc. (see Programming MIDlets for Interactive Behavior in Resources). Therefore, you can mix command programming and real event-driven programming for Canvas objects.

Canvas is an abstract class

The Canvas class is abstract, so you must extend it in order to use it. The reason for this is that the primary use of the Canvas class is to serve as a surface on which to draw. In order to draw, you must override the paint method of the Canvas class. The only way to override a method is to extend the class to which the method belongs.

Comparison with J2SE

When programming in J2SE (using the JavaBeans source-listener event model), if you want to detect and handle key events on an object that is the source of events, you must:

  • Define a class that implements the KeyListener interface.
  • Instantiate an object of that class.
  • Register the listener object on the source object.

Event handler methods, such as keyPressed are declared in the KeyListener interface and must be defined in your new class. That is not the case with MIDP 2.0. The Canvas class already defines the following empty event-handler methods:

  • keyPressed
  • keyReleased
  • keyRepeated
  • pointerDragged
  • pointerPressed
  • pointerReleased

Handling an event

To handle one of the events in the above list, you must override the corresponding method in your subclass of the Canvas class, writing the desired behavior into your overridden method. If you don’t want to handle any of the events in the above list, just forget about the ones that you don’t want to handle. Unlike the JavaBeans event model, it is not necessary to define empty methods for the events that you don’t want to handle.

More information from Sun

According to Sun,

“Applications receive keystroke events in which the individual keys are named within a space of key codes. Every key for which events are reported to MIDP applications is assigned a key code. The key code values are unique for each hardware key unless two keys are obvious synonyms for each other.”

Sun goes on to tell us,

“MIDP defines the following key codes: KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, KEY_NUM8, KEY_NUM9, KEY_STAR, and KEY_POUND. (These key codes correspond to keys on a ITU-T standard telephone keypad.)”

Public static final variables

The Canvas class provides a public static final variable (constant) for each of the key codes listed above.  Finally, Sun tells us,

“Other keys may be present on the keyboard, and they will generally have key codes distinct from those list above. In order to guarantee portability, applications should use only the standard key codes.”

Did not adhere to the rule

As you will see later, I did not adhere to this rule in one of the sample MIDlets. I wasn’t interested in achieving portability. Rather, I was mainly interested in clarity and I found it easier to be clear using the following key names (which may be peculiar to the Sun emulator) in the MIDlet:

  • LEFT
  • RIGHT
  • UP
  • DOWN
  • SELECT

These names apply to the arrow keys and the large key in the middle of the arrow keys on the Sun cell phone emulator keypad (see Figure 2).; As mentioned above, they may not apply to similar keys in other cell phone emulators or in real cell phones for that matter. (There is a better way to deal with the arrow keys, which you will learn about in a future lesson on the GameCanvas class.)

Normal versus full-screen mode

Here is some of what Sun has to say on this topic:

“A Canvas can be in normal mode or in full-screen mode. In normal mode, space on the display may be occupied by command labels, a title, and a ticker. By setting a Canvas into full-screen mode, the application is requesting that the Canvas occupy as much of the display space as is possible. In full-screen mode, the title and ticker are not displayed even if they are present on the Canvas, and Commands may be presented using some alternative means (such as through a pop-up menu).”

A Canvas object is in normal mode by default. You will see an example of normal and full-screen modes in one of the sample MIDlets in this lesson.

Numerous methods are defined in the Canvas class. I will illustrate the use of many of those methods in the sample MIDlets in this lesson.

The Graphics class

Sun describes this class as follows:

“Provides simple 2D geometric rendering capability.”

While true, this statement hardly does justice to the importance of the Graphics class.

No public constructor

The Graphics class doesn’t have a public constructor, so you can’t directly instantiate an object of the Graphics class. I am aware of at least two ways to get access to an object of the class.

The overridden paint method

The paint method that I mentioned earlier is a callback method. Whenever your Canvas object is visible on the screen and the system needs to display graphics information on that canvas, it will call your overridden paint method. When your overridden paint method is called, it will receive a reference to an object of Graphics class.

You can think of that object as a drawing surface that represents the screen. When you call the various methods of the Graphics class to draw pictures on the Graphics object, those pictures will appear on the screen (assuming that your MIDlet currently has access to the screen).

The createImage and getGraphics methods

As you will see in one the sample MIDlets in this lesson, you can use the createImage and getGraphics methods together to get access to an off-screen drawing area that is represented by a Graphics object. When you use the various methods of the Graphics class to draw on that Graphics object, the results are not immediately visible. Rather, you are simply drawing in memory when you do that and only you know what is happening.

This makes it possible for you to compose a complex drawing in memory and then transfer it to the Canvas object (the screen) very quickly by calling the drawImage method on the Canvas passing the off-screen image’s reference as a parameter. This is often a more visually pleasing approach than composing a complex drawing on the screen in full view of the user, particularly if the time required to compose the drawing is significant.

What about circles?
Circles are constructed from 360-degree circular arcs. Note that for the case of the drawArc method, angles are specified in degrees instead of radians.

Drawing primitives

The methods of the Graphics class provide drawing primitives for text, images, lines, rectangles, and arcs. Rectangles and arcs may be filled with a solid color. Rectangles may also be specified with rounded corners.

The coordinate system

The origin of the default coordinate system is at the upper left-hand corner of the screen or off-screen drawing area. The X-axis direction is positive towards the right, and the Y-axis direction is positive downwards. You can translate the origin to some other location if you want to by calling the translate method.

For example, by using the translate method and the appropriate arithmetic operations, you could cause the origin to be relocated to the center of the screen with the positive Y-axis direction going up the screen instead of down.

You can assume that horizontal and vertical distances in the coordinate system represent equal distances on the actual device display. In other words, if you draw a square, it won’t be turned into a rectangle and if you draw a circle, it won’t be turned into an ellipse.

All coordinates are specified as integers.

Drawing text

When a character is painted, the pixels forming the character’s shape are filled with the Graphics object’s current color. The pixels that are not part of the character’s shape are left untouched. Several methods are available to draw text. As far as I know, you can only draw text horizontally.

Line stroke styles

Lines, arcs, rectangles, and rounded rectangles may be drawn with either a SOLID or a DOTTED stroke style. The default is SOLID. You can change the style by calling the setStrokeStyle method, which doesn’t affect fill, text, and image operations.

Lines, arcs, rectangles, and rounded rectangles are drawn with a stroke that is one pixel wide. If you need additional width, you must draw two or more lines in parallel.

Clipping

Sun tells us,

“The clip is the set of pixels in the destination of the Graphics object that may be modified by graphics rendering operations.”

To make a long story short, there is a single clip per Graphics object, and it is a rectangle that you can set with a call to the setClip method. The only pixels modified by graphics operations are those that lie within the clip rectangle. Pixels outside the clip rectangle are not modified by any graphics operations.

Anchor points

One of the more complex aspects of the MIDP 2.0 graphics drawing system is the concept of anchor points. Anchor points apply when you are drawing text, images, regions, and areas. (They do not apply when drawing lines, arcs, rectangles, and rounded rectangles.)

Later, I will present and explain a sample MIDlet named Canvas01 that illustrates what is meant by anchor points in conjunction with the drawing of text. (The interpretation is generally the same when drawing images, etc.) The output from the MIDlet, when run in the Sun cell phone emulator, is shown in Figure 2. I will explain the output from the MIDlet here, and explain the code that produced that output later.

Figure 2. Output from MIDlet named Canvas01 in Sun emulator.

No anchor point in J2SE graphics
The anchor parameter is not used in the argument list of the drawString method of J2SE version 1.6.

Drawing parameters

When you call the drawString method to draw text on the screen, you must provide the following four parameters:

  • String string – the text string to be drawn.
  • int x – a horizontal coordinate value.
  • int y – a vertical coordinate value.
  • int anchor – an anchor point value.

The big question…

The parameter values x and y clearly specify a point in the Cartesian coordinate system. The big question is what does the location of that point in the coordinate system have to do with the location of the text (or the image, etc.)?

Allowable anchor-point values

The allowable anchor-point values are given below in terms of public static final variables (constants) of the Graphics class:

The key on the left with the picture of the house also doesn’t fire a keyPressed event.

The key pressed order

Figure 3 shows the result of starting at the top left soft key and pressing keys going from left to right, top to bottom, excluding the two keys mentioned above. The names of most of the keys in the Sun emulator are pretty easy to correlate with the label on the key. Two that may not be clear are SELECT and CLEAR. The SELECT key is the large square key in the middle of the arrow keys. The CLEAR key is the key on the right with the picture of the audio speaker.

Comparing full-screen and normal mode

You can see one of the differences between full-screen mode and normal mode by comparing Figure 3, (which is in full-screen mode) and Figure 2, (which is in normal mode). Since neither of these MIDlets displays a title and a ticker, the main difference between Figure 2 and Figure 3 is the disappearance of the gray bar at the bottom of the screen in Figure 3 where soft key commands normally appear. (I will have more to say about this later.)

Beginning of the class for the MIDlet named Canvas02

Listing 5 shows the beginning of the class for the MIDlet named Canvas02 including the constructor.

Listing 5. Beginning of the class for the MIDlet named Canvas02.

public class Canvas02 extends MIDlet{
  Canvas myCanvas;  

  public Canvas02(){//Constructor
    System.out.println("Construct MIDlet");
    myCanvas = this.new MyCanvas();
    //Guarentee that the screen gets painted.
    myCanvas.repaint();

    //Add three commands to the Canvas
    myCanvas.addCommand(new Command("EXIT",
                                         Command.EXIT,2));
    myCanvas.addCommand(new Command("BACK",
                                         Command.BACK,2));
    myCanvas.addCommand(new Command("OK",Command.OK,2));
  }//end constructor

Three commands are added

Note that the constructor in Listing 5 adds three commands to the Canvas object. However, even if visible, the commands could not be activated because there is no CommandListener registered on the Canvas object. The commands were added to the Canvas solely to demonstrate the impact of full-screen mode versus normal mode. As mentioned earlier, when the Canvas object is set to full-screen mode, as is the case for this MIDlet, the commands are not visible.

Alternative command presentation
The Sun documentation indicates that in full-screen mode, “Commands may be presented using some alternative means (such as through a pop-up menu).” If the Sun cell phone emulator provides such an alternative presentation, I haven’t figured out what it is.

Accessing the commands

If the Canvas is switched to normal mode, the commands are displayed on the gray bar that normally appears at the bottom of the screen and also in a command menu accessible from the gray bar. You can demonstrate this behavior by modifying the code to pass true or false to the setFullScreenMode method in the MyCanvas constructor that I will discuss later.

Remainder of the main class for the MIDlet named Canvas02

Listing 6 shows the remainder of the main class for the MIDlet named Canvas02.

Listing 6. Remainder of the main class for the MIDlet named Canvas02.

  public void startApp(){
    //Make the Canvas the current display.
    Display.getDisplay(this).setCurrent(myCanvas);
  }//end startApp

  public void pauseApp(){
  }//end pauseApp

  public void destroyApp(boolean unconditional){
    System.out.println("Destroy MIDlet");
    notifyDestroyed();
  }//end destroyApp

There is nothing new in this code so further explanation should not be necessary.

Beginning of the member class named MyCanvas

Listing 7 shows the beginning of the member class named MyCanvas, including the constructor.

Listing 7. Beginning of the member class named MyCanvas.

  class MyCanvas extends Canvas{
    Vector vect = new Vector();

    MyCanvas(){//constructor
      this.setFullScreenMode(true);
    }//end constructor

The constructor calls the method named setFullScreenMode to cause the Canvas to appear on the screen in full-screen mode. If you change the parameter from true to false, the Canvas will revert to normal mode. If what you need is normal mode, you don’t need to call this method because the Canvas is in normal mode by default.

Beginning of the overridden paint method

Listing 8 shows the beginning of the overridden paint method. The method begins by painting the screen white and then setting the drawing color to black. Following this, the method declares some working variables and initializes some of them.

Listing 8. Beginning of the overridden paint method.

    public void paint(Graphics g){
      //Paint the entire screen white.
      g.setColor(0xffffff);
      g.fillRect(0,0,getWidth(),getHeight());

      g.setColor(0x000000);//Set drawing color to black

      //Declare and initialize some working variables.
      String keyData = null;
      int fontHeight = g.getFont().getHeight();
      //Number of lines of text that fit on screen.
      int cntLimit = this.getHeight()/fontHeight;
      int yOffset = 0;
      int xOffset = 0;

A two-column display

Most of the complexity of this method resides in the requirement to create two columns for drawing the text strings. This requires knowledge of the number of strings that will fit from top to bottom on the screen, which in turn requires knowledge of the vertical space occupied by each character. The code in Listing 8 gets the font height and performs that calculation.

Remainder of the overridden paint method

Listing 9 displays the data captured from the user keyboard input in two columns. When the length of the first column exceeds the height of the screen, the display wraps and starts a new column as shown in Figure 3. If the length of the second column exceeds the height of the screen, the data will simply be lost off the bottom of the screen.

Listing 9. Remainder of the overridden paint method.

      for(int cnt = 0;cnt < vect.size();cnt++){
        keyData = (String)vect.elementAt(cnt);//note cast

        if(cnt * fontHeight < this.getHeight() - 
                                              fontHeight){
          //Display in first column.
          yOffset = cnt * fontHeight;
          xOffset = 5;
        }else{
          //Display in second column
          yOffset = (cnt - cntLimit) * fontHeight;
          xOffset = this.getWidth()/2;
        }//end else
        
        //Draw the string on the Canvas.
        g.drawString(keyData,xOffset,yOffset,0);
      }//end for loop

    }//end overridden paint method

Drawing from top to bottom of the screen

Note that a value of 0 is passed as the fourth parameter to the drawString method. This causes the anchor point location to default to TOP|LEFT.

Since the direction for increasing values of the Y-coordinate is down the screen, the code in Listing 9 extracts the text data from the Vector and draws the text on the screen moving from top to bottom.

The keyReleased method
When the MyCanvas object is on the screen and the user releases one of the keys, the keyReleased method is called. In this MIDlet, the empty keyReleased method is not overridden. Calling the empty method is of no consequence. It simply returns quietly.

Overridden keyPressed method

The MyCanvas class inherits an empty method named keyPressed from the Canvas class and overrides that method. Whenever the MyCanvas object is being displayed on the screen and the used presses one of the keys shown in Figure 3, the Canvas object “fires” a keyPressed event, causing the overridden keyPressed method to be called. The overridden keyPressed method is shown in Listing 10.

Listing 10. Overridden keyPressed method.

    public void keyPressed(int keyCode){
      vect.addElement(getKeyName(keyCode));
      this.repaint();
    }//end keyPressed
  }//end member class MyCanvas

}//end class Canvas02

Behavior of the code in Listing 10

The code in Listing 10:

  • Gets the name of the key that was pressed (which may be peculiar to the Sun cell phone emulator).
  • Adds that name to the data already in the Vector object.
  • Calls the repaint method on the Canvas object.

The call to the repaint method causes the overridden paint method to be executed. As described earlier, the call to the overridden paint method:

  • Clears the canvas by painting it white.
  • Extracts the text data from the Vector (including the new data).
  • Draws the text on the screen in two columns as shown in Figure 3.

Therefore, each time the user presses a key, the screen is re-drawn, causing the contents of the Vector object to be displayed. In this case, the call to the repaint method is not superfluous as it probably was earlier.

When is the paint method called?

As mentioned above, the paint method is called whenever the program code calls the repaint method. However, that is not the only time the paint method is called. It is called at any time that the system needs to cause the Canvas to be repainted by the MIDlet for any reason. For example, if a system screen covers the Canvas temporarily, the paint method will be called to redraw the screen when the system screen goes away.

Run the programs

I encourage you to copy the MIDlet code from Listing 11 and Listing 12. Run the MIDlets in the updated MIDlet development framework named WTKFramework03 that I provided in the lesson titled Using Alerts, Images, Timers, and Gauges in MIDlets (see Resources). Experiment with the MIDlet code, making changes and running your modified MIDlets in the framework program. See if you can explain the results produced by your changes.

Don’t forget that you will need to download and install the latest version of the Sun Java Wireless Toolkit for CLDC (see Resources). As of the date this lesson is being written, the latest version of the toolkit is WTK2.5.2.

Summary

In this lesson, you learned how to use several methods of the Canvas class (including paint and repaint), along with several methods of the Graphics class to draw text and lines on the cell phone screen. You learned how to use anchor point coordinates to control the position of text that is drawn on the screen. You also learned how to handle keyPressed events fired by a Canvas object.

What’s next?

In Part 2 of this lesson, you will learn how to mix image file data and drawn graphics on a cell phone screen. You will learn how to draw various shapes such as rectangles, circles, arcs, filled triangles, and rounded rectangles. You will learn how to use an off-screen image, and how to use the event handling capability of the Canvas class for simple animation. You will also learn how to make you MIDlet animations efficient by minimizing the screen area that must be repainted.

Resources

Complete program listings

Complete listings of the programs discussed in this lesson are shown in Listing 11 and Listing 12 below.

Listing 11. Source code for the MIDlet named Canvas01.

/*Canvas01.java
Copyright 2007, R.G.Baldwin

The purpose of this program is to illustrate a simple 
MIDlet using a Canvas object and a Graphics object. It
further illustrates the use of anchor point constants to
establish the alignment of drawn text.

The MIDlet begins by painting the entire screen white.
Otherwise, the new drawing would appear on top of what
was previously on the screen.

Then it sets the drawing color to black.

Then it draws eight pairs of graphic objects.  Each pair 
consists of:

A line from 0,0 to a specific coordinate value on the
 canvas.
A string of text with the anchor point set to match the
 end of the line. The text contents of each string give
 the combination of anchor point constants used to
 position that particular string. Some text strings also
 begin with a lower case y- to show the effect of
 descenders on the alignment of the text string.

The eight pairs of graphic objects illustrate the effect 
of different combinations of the following anchor point 
constants as well as the impact of lower-case descenders
on the alignment produced by the constants:

TOP
BASELINE
BOTTOM

LEFT
HCENTER
RIGHT

An anchor point must be specified for each text string 
that is drawn. The anchor point must be produced by the
bitwise inclusive OR of one of the top three vertical 
anchor constants and one of the bottom three horizontal 
anchor constants. For example, the following would be a
valid anchor point:

TOP|RIGHT

The actual position and the alignment of the text string 
are determined by the combination of a pair of specified 
coordinate values and the bitwise inclusive OR of two 
anchor constants. The coordinates specify the position 
that will be assumed by a particular point in the text 
string. The bitwise inclusive OR of two anchor constants
determines which point in the text string will be located
at the specified coordinates.

The special anchor point value of zero is interpreted to 
mean TOP|LEFT.

A pair of straight lines is used to connect the ends of
two groups of sloping lines.  This makes it easier to
visually determine the location of the anchor point in
each text string.

This MIDlet illustrates the use of the following methods
from the Graphics class:

setColor
fillRect
drawLine
drawString

It also illustrates the use of the following method from
the Canvas class:

paint
repaint
getWidth
getHeight

The MIDlet displays the canvas for 20 seconds and then
enters the destroyed state.

Tested using a Java SE 6 compiler, targeted at a V1.4
virtual machine, and WTK 2.5.2 running under Windows XP.
*********************************************************/

package Canvas01;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

public class Canvas01 extends MIDlet{
  Canvas myCanvas;

  public Canvas01(){
    System.out.println("Construct MIDlet");
    myCanvas = this.new MyCanvas();
    //Guarentee that the screen gets painted.
    myCanvas.repaint();
  }//end constructor

  public void startApp(){

    //Make the Canvas the current display.
    Display.getDisplay(this).setCurrent(myCanvas);

    //Sleep for 20 seconds.
    try{Thread.currentThread().sleep(20000);
    } catch(Exception e){}

    //Enter the destroyed state.
    this.destroyApp(true);
  }//end startApp

  public void pauseApp(){
  }//end pauseApp

  public void destroyApp(boolean unconditional){
    System.out.println("Destroy MIDlet");
    notifyDestroyed();
  }//end destroyApp
  //----------------------------------------------------//

  //member class
  class MyCanvas extends Canvas{
    public void paint(Graphics g){
      //Paint the entire screen white. Otherwise, the new
      // drawing will simply appear over top of what was
      // previously on the screen.
      g.setColor(0xffffff);
      g.fillRect(0,0,getWidth(),getHeight());

      //Set the drawing color to black.
      g.setColor(0x000000);

      //Draw text at eight different anchor points. The
      // text shows the vertical and horizontal constants
      // required to set the respective anchor points.
      // In addition, a line is drawn from 0,0 to the
      // anchor point to visually identify the anchor
      // point. A lower-case y is used to show the effect
      // of descenders on the alignment of the text.
      g.drawLine(0,0,200,20);
      g.drawString("y-TOP|RIGHT",200,20,
                             Graphics.TOP|Graphics.RIGHT);

      g.drawLine(0,0,150,40);
      g.drawString("y-TOP|HCENTER",150,40,
                           Graphics.TOP|Graphics.HCENTER);

      g.drawLine(0,0,100,60);
      g.drawString("y-TOP|LEFT",100,60,
                              Graphics.TOP|Graphics.LEFT);

      g.drawLine(0,0,100,90);
      g.drawString("y-BOTTOM|LEFT",100,90,
                           Graphics.BOTTOM|Graphics.LEFT);

      g.drawLine(0,0,100,110);
      g.drawString("BOTTOM|LEFT",100,110,
                           Graphics.BOTTOM|Graphics.LEFT);

      g.drawLine(0,0,100,130);
      g.drawString("y-BASELINE|LEFT",100,130,
                         Graphics.BASELINE|Graphics.LEFT);

      g.drawLine(0,0,100,150);
      g.drawString("BASELINE|LEFT",100,150,
                         Graphics.BASELINE|Graphics.LEFT);

      g.drawLine(0,0,100,170);
      g.drawString("Special Case of Zero",100,170,0);

      //Draw straight lines that connect the ends of the
      // sloping lines.
      g.drawLine(200,20,100,60);
      g.drawLine(100,60,100,170);

    }//end overridden paint method
  }//end member class MyCanvas

}//end class Canvas01

 

Listing 12. Source code for the MIDlet named Canvas02.

/*Canvas02.java
Copyright 2007, R.G.Baldwin

The purpose of this program is to illustrate the 
detection and handling of key events on a Canvas object.
The MIDlet also demonstrates certain aspects of the
FullScreenMode versus the normal mode.

A Canvas object is instantiated and set to FullScreenMode.

The inherited keyPressed method is overridden to capture
a user keystroke, convert the key code to a key name, add
the key name to a Vector object, and cause the screen to
be repainted each time a keyPressed event occurs.

The paint method is overridden to clear the canvas,
extract all of the key names from the Vector, and display
the key names in two columns by using the drawString
method to draw the key names on the Canvas object.

Note, on the Sun cell phone emulator, you can terminate
the MIDlet by clicking the button on the right that has
a picture of a horizontal telephone receiver. When you
point to this button, the picture of the telephone
receiver should turn red. I did not register an EXIT
command listener because I did not want to cause the
left soft key to be occupied with a command when in
normal mode.

Tested using a Java SE 6 compiler, targeted at a V1.4
virtual machine, and WTK 2.5.2 running under Windows XP.
*********************************************************/

package Canvas02;

import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import java.util.Vector;

public class Canvas02 extends MIDlet{
  Canvas myCanvas;

  public Canvas02(){
    System.out.println("Construct MIDlet");
    myCanvas = this.new MyCanvas();
    //Guarentee that the screen gets painted.
    myCanvas.repaint();

    //Note: The following commands cannot be activated
    // because there is no CommandListener registered on
    // the Canvas object. They are here solely to
    // demonstrate the impact of FullScreenMode versus
    // normal mode. When the Canvas object is set to
    // FullScreenMode, as is the case in this MIDlet,
    // these commands are not displayed. Therefore, even
    // if a CommandListener were registered on the Canvas,
    // it would not be possible for the user to activate
    // the commands.  In normal mode, the commands are
    // displayed. If there was a CommandListener
    // registered on the Canvas, the user could activate
    // the commands. You can demonstrate this behavior by
    // modifying the code to pass true or false to the
    // setFullScreenMode method in the MyCanvas
    // constructor. 
    myCanvas.addCommand(new Command("EXIT",
                                         Command.EXIT,2));
    myCanvas.addCommand(new Command("BACK",
                                         Command.BACK,2));
    myCanvas.addCommand(new Command("OK",Command.OK,2));
  }//end constructor

  public void startApp(){
    //Make the Canvas the current display.
    Display.getDisplay(this).setCurrent(myCanvas);
  }//end startApp

  public void pauseApp(){
  }//end pauseApp

  public void destroyApp(boolean unconditional){
    System.out.println("Destroy MIDlet");
    notifyDestroyed();
  }//end destroyApp
  //----------------------------------------------------//

  //Member class
  class MyCanvas extends Canvas{
    Vector vect = new Vector();

    MyCanvas(){//constructor
      //Note: In normal mode, the gray bar where the soft
      // key commands normally appear is visible at the
      // bottom of the screen.  However, in
      // FullScreenMode, that gray bar disappears. This
      // seems it make it impossible for the user to
      // activate commands on the Canvas when in
      // FullScreenMode. You can demonstrate this behavior
      // by either removing the following statement or
      // modifying the code to pass false to the
      // setFullScreenMode method. Passing false to the
      // method will switch the Canvas to normal mode.
      this.setFullScreenMode(true);
    }//end constructor

    public void paint(Graphics g){
      //Paint the entire screen white.
      g.setColor(0xffffff);
      g.fillRect(0,0,getWidth(),getHeight());

      g.setColor(0x000000);//Set drawing color to black

      //Declare and initialize some working variables.
      String keyData = null;
      int fontHeight = g.getFont().getHeight();
      //Number of lines of text that fit on screen.
      int cntLimit = this.getHeight()/fontHeight;
      int yOffset = 0;
      int xOffset = 0;

      //Display the data captured from the user keyboard
      // input in two columns using graphic display
      // capabilities. If the length of the second
      // column exceeds the height of the screen, the
      // data will simply fall off the bottom of the
      // screen.
      for(int cnt = 0;cnt < vect.size();cnt++){
        keyData = (String)vect.elementAt(cnt);//note cast

        if(cnt * fontHeight < this.getHeight() - 
                                              fontHeight){
          //Display in first column.
          yOffset = cnt * fontHeight;
          xOffset = 5;
        }else{
          //Display in second column
          yOffset = (cnt - cntLimit) * fontHeight;
          xOffset = this.getWidth()/2;
        }//end else

        //Draw the string on the Canvas.
        g.drawString(keyData,xOffset,yOffset,0);
      }//end for loop

    }//end overridden paint method
    //--------------------------------------------------//

    //Override the keyPressed method to:
    // capture keystrokes
    // save them in a Vector object
    // repaint the canvas.
    public void keyPressed(int keyCode){
      vect.addElement(getKeyName(keyCode));
      this.repaint();
    }//end keyPressed
  }//end member class MyCanvas

}//end class Canvas02

 


Copyright

Copyright 2008, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin’s Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor’s degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

[email protected]

Latest Posts

Related Stories