August 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

MIDP Programming with J2ME

  • December 26, 2002
  • By Sams Publishing
  • Send Email »
  • More Articles »

Images

The Graphics class also provides a method for drawing images. As shown in the final version of TeleTransfer application, Images can be predefined and contained in the JAR file of the MIDlet. The only file format that is mandatory for MIDP is the Portable Network Graphics (PNG) file format. The PNG format has several advantages over other graphics formats; for example, it is license free and supports true color images, including a full transparency (alpha) channel. PNG images are always compressed with a loss-less algorithm. The algorithm is identical to the algorithm used for JAR files, so the MIDP implementation can save space by using the same algorithm for both purposes.

An image can be loaded from the JAR file using the static method Image.create (String name). The name parameter denotes the filename of the image in the JAR file. Please note that this create() method may throw an IOException.

The drawImage() method in Graphics requires an Image object, the coordinates, and an integer denoting the alignment as parameters. The alignment parameter is similar the alignment of drawString(), except that the BASELINE constant is not supported. An additional alignment constant available for images only is VCENTER, which forces the image to be vertically centered relative to the given coordinates. Figure 3.16 shows the valid constant combinations and the corresponding anchor points.

Figure 3.16 Alignment constant combinations valid for images and the corresponding anchor points.

The following example first loads the image logo.png from the MIDlet JAR file in the constructor, and then displays the image three times. One image is drawn in the upper-left corner, one in the lower-right corner, and one in the center of the display, as shown in Figure 3.17:

import java.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

class ImageDemoCanvas extends Canvas {

  Image image;

  public ImageDemoCanvas () {
    try {
      image = Image.createImage ("/logo.png");
    }
    catch (IOException e) {
      throw new RuntimeException ("Unable to load Image: "+e);
    }
  }

  public void paint (Graphics g) {
    g.setGrayScale (255);
    g.fillRect (0, 0, getWidth (), getHeight ());

    g.drawImage (image, 0, 0, Graphics.TOP | Graphics.LEFT);
    g.drawImage (image, getWidth () / 2, getHeight () / 2, 
           Graphics.HCENTER | Graphics.VCENTER);
    g.drawImage (image, getWidth (), getHeight (), 
           Graphics.BOTTOM | Graphics.RIGHT);
  }
}

Figure 3.17 Output of the ImageDemo example.

Images can also be created at runtime from scratch. The static method Image.create (int width, int height) creates a new dynamic image of the given size. In contrast to images loaded from a JAR file, these images are mutable. Mutable images can be modified by calling getGraphics (). The Graphics object returned can be used for modifying the image with all the methods provided by the Graphics class. Please note that images loaded from a JAR file cannot be modified. However, it is possible to create a mutable image, and then draw any other image in the mutable image.

By modifying the constructor of the previous example canvas as follows, the image drawn in the paint() method is created and filled at runtime instead of loading an image from the JAR file:

public ImageDemoCanvas () {
  image = Image.createImage (10,10);
  image.getGraphics ().fillArc (0,0,10,10,0, 360);
}

The disadvantage of mutable images is that they cannot be used in high-level GUI elements since it is possible to modify them at any time, possibly leading to inconsistent display of widgets. For that reason, another static create method, createImage(Image image), is provided that creates an immutable image from another image.

Interaction

Because the Canvas class is a subclass of Displayable, it provides the same support for commands as the high-level screen classes. Here, you will concentrate on the additional interaction possibilities the Canvas class offers: direct key input and pointer support.

Please note that all input events and command notifications and the paint() method are called serially. That means that the application manager will call none of the methods until the previous event handling method has returned. So all these methods should return quickly, or the user will be unable to interact with the application. For longer tasks, a separate thread can be started.

Key Input

For key input, the Canvas class provides three callback methods: keyPressed(), keyReleased(), and keyRepeated(). As the names suggest, keyPressed() is called when a key is pressed, keyRepeated() is called when the user holds down the key for a longer period of time, and keyReleased() is called when the user releases the key.

All three callback methods provide an integer parameter, denoting the Unicode character code assigned to the corresponding key. If a key has no Unicode correspondence, the given integer is negative. MIDP defines the following constant for the keys of a standard ITU-T keypad: KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, KEY_NUM8, KEY_NUM9, KEY_POUND, and KEY_STAR. Applications should not rely on the presence of any additional key codes. In particular, upper- and lowercase or characters generated by pressing a key multiple times are not supported by low-level key events. A "name" assigned to the key can be queried using the getKeyName() method.

Some keys may have an additional meaning in games. For this purpose, MIDP provides the constants UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C, and GAME_D. The "game" meaning of a keypress can be determined by calling the getGameAction() method. The mapping from key codes to game actions is device dependent, so different keys may map to the same game action on different devices. For example, some devices may have separate cursor keys; others may map the number pad to four-way movement. Also, several keys may be mapped to the same game code. The game code can be translated back to a key code using the getKeyCode() method. This also offers a way to get the name of the key assigned to a game action. For example, the help screen of an application may display

"press "+getKeyName (getKeyCode (GAME_A)) 

instead of "press GAME_A".

The following canvas implementation shows the usage of the key event methods. For each key pressed, repeated, or released, it shows the event type, character and code, key name, and game action.

The first part of the implementation stores the event type and code in two variables and schedules a repaint whenever a key event occurs:

import javax.microedition.lcdui.*;

class KeyDemoCanvas extends Canvas {

  String eventType = "- Press any!";
  int keyCode;

  public void keyPressed (int keyCode) {
    eventType = "pressed";
    this.keyCode = keyCode;
    repaint ();
  }

  public void keyReleased (int keyCode) {
    eventType = "released";
    this.keyCode = keyCode;
    repaint ();
  }

  public void keyRepeated (int keyCode) {
    eventType = "repeated";
    this.keyCode = keyCode;
    repaint ();
  }

The second part prints all event properties available to the device screen. For this purpose, you first implement an additional write() method that helps the paint() method to identify the current y position on the screen. This is necessary because drawText() does not advance to a new line automatically. The write() method draws the string at the given y position and returns the y position plus the line height of the current font, so paint() knows where to draw the next line:

public int write (Graphics g, int y, String s) {
  g.drawString (s, 0, y, Graphics.LEFT|Graphics.TOP);
  return y + g.getFont ().getHeight ();
}

The paint() method analyzes the keyCode and prints the result by calling the write() method defined previously, as shown in Figure 3.18:

  public void paint (Graphics g) {
    g.setGrayScale (255);
    g.fillRect (0, 0, getWidth (), getHeight ());

    g.setGrayScale (0);

    int y = 0;
    y = write (g, y, "Key "+ eventType);
    if (keyCode == 0) return;

    y = write (g, y, "Char/Code: "+ ((keyCode < 0) ? "N/A" : ""
          +(char) keyCode) + "/" + keyCode);
    y = write (g, y, "Name: "+getKeyName (keyCode));
    String gameAction;
    switch (getGameAction (keyCode)) {
    case LEFT: gameAction = "LEFT"; break;
    case RIGHT: gameAction = "RIGHT"; break;
    case UP: gameAction = "UP"; break;
    case DOWN: gameAction = "DOWN"; break;
    case FIRE: gameAction = "FIRE"; break;
    case GAME_A: gameAction = "GAME_A"; break;
    case GAME_B: gameAction = "GAME_B"; break;
    case GAME_C: gameAction = "GAME_C"; break;
    case GAME_D: gameAction = "GAME_D"; break;
    default: gameAction = "N/A"; 
    }
    write (g, y, "Action: "+gameAction); 
  }
}

Figure 3.18 Output of the KeyDemo example when the "Fire" key was released.

Pointer Events

For devices supporting a pointer device such as a stylus, touch screen, or trackball, the Canvas class provides three notification methods: pointerPressed(), pointerDragged(), and pointerReleased(). These methods work similarly to the key event methods, except that they provide two integer parameters, denoting the x and y position of the pointer when the corresponding event occurs. (Please note that pointer support is optional in MIDP, so the application should not rely on the presence of a pointer. Such devices are uncommon for devices such as mobile phones.) The following sample program demonstrates the usage of the three methods:

import javax.microedition.lcdui.*;

class PointerDemoCanvas extends Canvas {

  String eventType = "Press Pointer!";
  int x;
  int y;

  public void pointerPressed (int x, int y) {
    eventType = "Pointer Pressed";
    this.x = x;
    this.y = y;
    repaint ();
  }

  public void pointerReleased (int x, int y) {
    eventType = "Pointer Released";
    this.x = x;
    this.y = y;
    repaint ();
  }

  public void pointerDragged (int x, int y) {
    eventType = "Pointer Repeated";
    this.x = x;
    this.y = y;
    repaint ();
  }

  public void paint (Graphics g) {
    g.setGrayScale (255);
    g.fillRect (0, 0, getWidth (), getHeight ());
    g.setGrayScale (0);
    g.drawString (eventType + " " +x +"/"+y, 
           0, 0, Graphics.TOP|Graphics.LEFT);
    g.drawLine (x-4, y, x+4, y);
    g.drawLine (x, y-4, x, y+4);
  }
}




Page 6 of 8



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel