这个案例描述了如何使用低级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.javaGUI.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 } // end if UP button was pressed else if (keyCode == DOWN) { currentlySelectedIndex++; if (currentlySelectedIndex >= menuOptions.length) { currentlySelectedIndex = menuOptions.length - 1; // stay within limits } clearScreen(); menu.drawActiveMenu(this, g, currentlySelectedIndex); // repaint active menu } // end if DOWN button was pressed else if (keyCode == FIRE) { // 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 } // end if menu is active else { // 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; } // end if "Options" was pressed else if (keyCode == RIGHT_SOFTKEY_CODE) { 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 } // end if draw unselected menu option else { // draw selected menu option g.setColor(0x0000ff); // blue } // end if draw 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