用Canvas创建高级菜单

这个案例描述了如何使用低级UI API,也就是Canvas来创建高级菜单

本案例共包括三个类,MIDlet,GUI和Menu。其中,当MIDlet启动后,Options和exit会绘制在屏幕

的底部,当用户按左或者右软键的时候,程序会根据键值响应不同的动作。例如选择options后,

会弹出menu供用户选择。

GUI类持有一个Menu对象,并且根据用户的输入来改变Menu的状态,然后重新绘制屏幕。事实上menu只有两种状态,一种是激活的,一种是非
激活的。只有激活状态下,菜单才会显示出来,并且可以接受用户的上下左右选择,当用户选择了Menu里面的选项之后,GUI会把用户的选择显示在屏幕上。
代码如下所示:

//Midlet.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class Midlet extends MIDlet {

private Display display;
private GUI gui;

public void startApp() {
display = Display.getDisplay(this);
if (display == null) {
destroyApp(false);
} // end if display is not allocated

gui = new GUI(this);
display.setCurrent(gui);
gui.start();
} // end startApp

public void pauseApp() {
} // end pauseApp

public void destroyApp(boolean unconditional) {
display.setCurrent(null);
notifyDestroyed();
} // end destroyApp

} // end Midlet.java
//GUI.java

import java.util.*;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;

import javax.microedition.media.*;
import javax.microedition.media.control.*;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.io.file.*;


class GUI extends GameCanvas {

private Midlet midlet;

private Display display;

private Graphics g;

private Font font;

private int width = 0;
private int height = 0;

private Menu menu;

private String leftOption;
private String rightOption;
private String[] menuOptions;

private int currentlySelectedIndex = 0;

private boolean menuIsActive = false;

/**
* Creates a new instance of GUI.
*/
public GUI(Midlet midlet) {

super(false);

this.midlet = midlet;
font = Font.getFont(Font.FACE_SYSTEM,
Font.STYLE_PLAIN, Font.SIZE_SMALL);

setFullScreenMode(true);

width = getWidth();
height = getHeight();

g = getGraphics();

leftOption = "Options";
// will be displayed only when menu is not active
rightOption = "Exit";
// will be displayed only when menu is not active
menuOptions = new String[] {"Option #1", "Option #2", "Option #3",
"Option #4"};
menu = new Menu(leftOption, rightOption, menuOptions);
} // end constructor

public void start() {
clearScreen();
menu.drawInactiveMenu(this, g);
} // end start


// softkey codes may vary from phone to phone
// -6 and -7 values are OK on Nokia phones

private int LEFT_SOFTKEY_CODE = -6;
// check it for your phone model
private int RIGHT_SOFTKEY_CODE = -7;
// check it for your phone model

protected void keyPressed(int keyCode) {
// work with menu according to its current state
if (menuIsActive) { // draw active menu
if (keyCode == RIGHT_SOFTKEY_CODE) {
// draw inactive menu again
clearScreen();
menu.drawInactiveMenu(this, g);
menuIsActive = false;
} // end if "Cancel" was pressed on active menu

// otherwise check navigation
keyCode = getGameAction(keyCode);
if (keyCode == UP) {
currentlySelectedIndex--;
if (currentlySelectedIndex < 0) {
currentlySelectedIndex = 0; // stay within limits
}
clearScreen();
menu.drawActiveMenu(this, g, currentlySelectedIndex);
// repaint active menu
} else if (keyCode == DOWN) { // end if UP button was pressed
currentlySelectedIndex++;
if (currentlySelectedIndex >= menuOptions.length) {
currentlySelectedIndex = menuOptions.length - 1;
// stay within limits
}

clearScreen();
menu.drawActiveMenu(this, g, currentlySelectedIndex);
// repaint active menu

} else if (keyCode == FIRE) { // end if DOWN button was pressed
// menu option is selected

// simply draw selected option
clearScreen();
g.setColor(0x000000); // black
g.drawString("[" +
menuOptions[currentlySelectedIndex] +
"] was selected", 10, 15, g.LEFT | g.TOP);
menu.drawInactiveMenu(this, g);
menuIsActive = false;
} // end if FIRE button was pressed

} else { // end if menu is active, draw inactive menu

// check if the "Options" or "Exit" buttons were pressed
if (keyCode == LEFT_SOFTKEY_CODE) { // "Options" pressed
clearScreen();
currentlySelectedIndex = 0;
menu.drawActiveMenu(this, g, currentlySelectedIndex);
// activate menu

menuIsActive = true;
} else if (keyCode == RIGHT_SOFTKEY_CODE) { // end if "Options" was pressed
exitGUI();
} // end if "Exit" was pressed
} // end if menu is not active
} // end keyPressed

public void exitGUI() {
midlet.destroyApp(false);
midlet.notifyDestroyed();
} // end exitGUI

public void clearScreen() {
g.setColor(0xffffff); // white
g.fillRect(0, 0, width, height);
flushGraphics();
} // end clearScreen

} // end GUI.java
//Menu.java

import java.util.*;

import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;


public class Menu {

private String leftOption;
// will be displayed when menu is inactive
private String rightOption;
// will be displayed when menu is inactive
private String cancelOption = "Cancel";
// also may be "Back" or something else
private String[] menuOptions;

private int padding = 5; // just like in CSS

/**
* Creates a new instance of Menu.
*/
public Menu(String leftOption, String rightOption, String[]
menuOptions) {
this.leftOption = leftOption;
this.rightOption = rightOption;
this.menuOptions = menuOptions;
} // end constructor


public void drawInactiveMenu(GameCanvas canvas, Graphics g) {

// create inactive menu font
Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,
Font.SIZE_MEDIUM);
int fontHeight = font.getHeight();

// clear inactive menu background
int width = canvas.getWidth();
int height = canvas.getHeight();

g.setColor(0xcccccc); // grey color
g.fillRect(0, height - fontHeight - 2 * padding, width, height);

// draw left and right menu options
g.setFont(font);
g.setColor(0x000000); // black

g.drawString(leftOption, padding, height - padding,
g.LEFT | g.BOTTOM);
g.drawString(rightOption, width - padding, height - padding,
g.RIGHT | g.BOTTOM);
canvas.flushGraphics();

} // end drawInactiveMenu

public void drawActiveMenu(GameCanvas canvas,
Graphics g, int selectedOptionIndex) {
// create active menu font
Font font = Font.getFont(Font.FACE_SYSTEM,
Font.STYLE_BOLD, Font.SIZE_MEDIUM);
int fontHeight = font.getHeight();

// clear menu bar background
int width = canvas.getWidth();
int height = canvas.getHeight();

g.setColor(0xcccccc);
g.fillRect(0, height - fontHeight - 2 * padding,
width, height);

// draw default menu bar options
g.setFont(font);
g.setColor(0x000000); // black

// draw "Cancel" option
g.drawString(cancelOption, width - padding, height - padding,
g.RIGHT | g.BOTTOM);
canvas.flushGraphics();

// draw menu options
if (menuOptions != null) {
// check out the max width of a menu
// (for the specified menu font)

int menuMaxWidth = 0;
int menuMaxHeight = 0;
int currentWidth = 0;

// we'll simply check each option and find the
// maximal width

for (int i = 0; i < menuOptions.length; i++) {
currentWidth = font.stringWidth(menuOptions[i]);

if (currentWidth > menuMaxWidth) {
menuMaxWidth = currentWidth; // update
}

menuMaxHeight += fontHeight + padding;
// for a current menu option

} // end for each menu option

menuMaxWidth += 2 * padding;
// padding from left and right
// now we know the bounds of active menu
// draw active menu's background

g.setColor(0xcccccc);
g.fillRect(0, // x
height - fontHeight -
2 * padding - menuMaxHeight, // y
menuMaxWidth,
menuMaxHeight);

// draw menu options (from up to bottom)
g.setFont(font);
int menuOptionX = padding;
int menuOptionY = height - fontHeight - 2 * padding
- menuMaxHeight + padding;

for (int i = 0; i < menuOptions.length; i++) {

if (i != selectedOptionIndex) {
// draw unselected menu option
g.setColor(0x000000); // black

} else {
// end if draw unselected menu option, draw selected="selected" menu option
g.setColor(0x0000ff); // blue

} // end if draw selected="selected" menu option

g.drawString(menuOptions[i], menuOptionX,
menuOptionY, g.LEFT | g.TOP);

menuOptionY += padding + fontHeight;

} // end for each menu option

canvas.flushGraphics();

} // end if menu options were specified

} // end drawActiveMenu

} // end Menu.java