Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

How to create an advanced menu in Java ME using the low-level graphical API

From Wiki
Jump to: navigation, search
Article Metadata
Article
Created: User:Axs (03 May 2007)
Last edited: hamishwillee (08 Aug 2013)

Contents

Overview

This example will show you how to create an advanced menu in mobile Java applications using the low-level graphical API:

Inactive menu.png Active menu.png

The solution presented here consists of three Java classes: the Midlet, the GUI and the Menu. The Menu is drawn at the bottom of mobile screen, and in the inactive state mobile user can see only the menu bar with default menu items: "Options" and "Exit". When "Options" item is selected (by pressing the left soft-key on the phone) the menu goes into the active state and draws all menu options on the screen.

The code presented here is quite short and might be customized in many different ways. However, it is far, far away from the optimized one, and its purpose was only to show the principles of drawing highly customized menu by using the low-level graphical API.

Architecture

The MIDlet class simply initializes the GUI and shows it to the mobile user.

The GUI class keeps inside a Menu object, and changes the state of Menu according to the user's inputs.

The Menu class after all simply draws itself on a canvas according to its current state.

Drawing the menu

The main thing about drawing the Menu is just to remember that it should be (re)drawn according to its current state, and state changes are made by the user through the "UP", "DOWN", "SELECT" ("LEFT" and "RIGHT") buttons.

This simple menu can be only in two states: active and inactive.

In the inactive state the menu bar is displayed only:

Inactive menu.png

Here you can see two major options: the "Options" for activating the menu; and "Exit" for exiting the MIDlet.

The inactive menu is drawn by the method drawInactiveMenu(), which you can find from the Menu.java

The active state means drawing menu options on the top of menu bar, and also changing the menu bar's texts:

Active menu.png

"Option #1" will be always selected by default. Note, that instead of "Exit" option here we draw "Cancel" option. This is the usual way of how the menu logic is implemented. This, however, could be customized in many ways.

The active menu is drawn by the method drawActiveMenu(), which you can find from the Menu.java

Option selecting logic

Now you can press "UP" and "DOWN" navigations buttons in order to make your choice:

Option 3 selected.png

The GUI class traces user inputs through the keyPressed() method, and changes the state of Menu. The logic hided in the keyPressed() method could be placed inside the Menu class, but to make code more easier to understand, the Menu class keeps only the graphical methods.

The option selecting graphics could be implemented in many different ways, but the simplest one is either underlining option's text or changing its color.

When option is chosen, press "Select" or "FIRE" button and the GUI class will notify Menu about the user's choice:

Option 3 selected finally.png

After pressing the "Select" button the menu state will be changed to inactive, and the drawInactiveMenu() method will be called.

If user will press the "Cancel", then no option will be selected and inactive menu will be drawn once again.

The source code

Please note, that the code presented here is far, far, far away from the optimized one. The reason for implementing everything in separated methods was to give the developer a possibility to easily change the code and see immediately how changes are affecting on GUI and its look-and-feel.

Also the option selecting logic should be stored inside the Menu class, but for making code more simpler, it remains inside the GUI class.

I hope now you have the basic idea of how the advanced menu could be implemented in the J2ME applications using the low-level graphical API.

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
 
} // 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
 
/**
* The simplest way to separate selected menu option
* is by drawing it with different color.
* However, it also may be painted as underlined text
* or with different background color.
*/

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
This page was last modified on 8 August 2013, at 03:59.
140 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×