How to build a Canvas based List in J2ME

Quite a bit of time is passed since the last Java ME tutorial.. so It’s time for something new, don’t you think?

Today we’ll see how it is possible to implement a simple Canvas based List, with the following features:

  • customizable style (colors, margins, font)
  • vertical scrolling
  • image and text support (as for standard Java ME Lists)

Java ME Canvas based List screenshot

It is possible to see this code in action on the emulator page.

Writing the code

First thing you should define some style-related properties, that will be used to paint the List items. Name of single properties is self-explaining.

int linePadding = 2;
int margin = 2;
int padding = 2;
Font font = Font.getDefaultFont();
 
int bgColor = 0xffffff;
 
int foreColor = 0x000000;
int foreSelectedColor = 0xffffff;
int backColor = 0xffffff;
int backSelectedColor = 0x0000ff;
 
int borderWidth = 3;
int borderColor = 0x000000;
int borderSelectedColor = 0xff0000;

Now, here are some internal properties, that will be used to handle list items content and positioning.

// will contain item splitted lines
String[][] itemLines = null;
// will hold items image parts
Image[] images = null;
// will hold selected item index
public int selectedItem = 0;
 
// these will hold item graphical properties
int[] itemsTop = null;
int[] itemsHeight = null;
 
// these will hold List vertical scrolling
int scrollTop = 0;
final int SCROLL_STEP = 40;

Now, here is the CanvasList constructor. Its arguments are (similarly to javax.microedition.lcdui.List constructor):

  • the screen’s title
  • set of strings specifying the string parts of the List elements
  • set of images specifying the image parts of the List elements

This article will not cover the handling of different types of Lists (e.g.: exclusive, multiple, ..).

public CanvasList(String title, String[] items, Image[] imageElements)
{
	setTitle(title);
 
	this.images = imageElements;
 
	itemLines = new String[items.length][];
 
	itemsTop = new int[itemLines.length];
	itemsHeight = new int[itemLines.length];
 
	for(int i = 0; i < itemLines.length; i++)
	{
		// get image part of this item, if available
		Image imagePart = getImage(i);
 
		// get avaiable width for text
		int w = getItemWidth() - (imagePart != null ? imagePart.getWidth() + padding : 0);
 
		// and split item text into text rows, to fit available width
		itemLines[i] = getTextRows((String) items[i], font, w);
	}
}

Here are the 2 utility methods found in the CanvasList constructor:

public int getItemWidth()
{
	return getWidth() - 2 * borderWidth - 2 * padding - 2 * margin;
}
Image getImage(int index)
{
	return images != null && images.length > index ? images[index] : null;
}

Now, here is the paint() method:

protected void paint(Graphics g)
{
	// paint List background
	g.setColor(bgColor);
	g.fillRect(0, 0, getWidth(), getHeight());
 
	// translate accordingly to current List vertical scroll
	g.translate(0, - scrollTop);
 
	int top = 0;
 
	g.setFont(font);
 
	// loop List items
	for(int i = 0; i < itemLines.length; i++)
	{
		int itemRows = itemLines[i].length;
 
		Image imagePart = getImage(i);
 
		int itemHeight = itemRows * font.getHeight() + linePadding * (itemRows - 1);
 
		itemsTop[i] = top;
		itemsHeight[i] = itemHeight;
 
		// is image part higher than the text part?
		if(imagePart != null && imagePart.getHeight() > itemHeight)
		{
			itemHeight = imagePart.getHeight();
		}
		itemHeight += 2 * padding + 2 * borderWidth;
 
		g.translate(0, top);
 
		if(borderWidth > 0)
		{
			// paint item border
			g.setColor(i == selectedItem ? borderSelectedColor : borderColor);
			g.fillRect(margin, margin, getWidth() - 2 * margin, itemHeight);
		}
 
		// paint item background
		g.setColor(i == selectedItem ? backSelectedColor : backColor);
		g.fillRect(margin + borderWidth, margin + borderWidth, getWidth() - 2 * margin - 2 * borderWidth, itemHeight - 2 * borderWidth);
 
		// has this item an image part?
		if(imagePart != null)
		{
			g.drawImage(imagePart, margin + borderWidth + padding, margin + borderWidth + padding, Graphics.TOP | Graphics.LEFT);
		}
 
		// paint item text rows
		g.setColor(i == selectedItem ? foreSelectedColor : foreColor);
 
		int textLeft = margin + borderWidth + padding + (imagePart != null ? imagePart.getWidth() + padding : 0);
 
		for(int j = 0; j < itemRows; j++)
		{
			g.drawString(itemLines[i][j], textLeft, margin + borderWidth + padding + j * (linePadding + font.getHeight()), Graphics.TOP | Graphics.LEFT);
		}
 
		g.translate(0, - top);
 
		top += itemHeight + 2 * margin;
	}
	// finally, translate back
	g.translate(0, scrollTop);
}

And finally, to handle user key events, here is the keyPressed() event:

protected void keyPressed(int key)
{
	int keyCode = getGameAction(key);
 
	// is there 1 item at least?
	if(itemLines.length > 0)
	{
		// going up
		if(keyCode == Canvas.UP)
		{
			// current item is clipped on top, so can scroll up
			if(itemsTop[selectedItem] < scrollTop)
			{
				scrollTop -= SCROLL_STEP;
 
				repaint();
			}
			// is there a previous item?
			else if(selectedItem > 0)
			{
				selectedItem--;
 
				repaint();
			}
		}
		//going down
		else if(keyCode == Canvas.DOWN)
		{
			// current item is clipped on bottom, so can scroll down
			if(itemsTop[selectedItem] + itemsHeight[selectedItem] >= scrollTop + getHeight())
			{
				scrollTop += SCROLL_STEP;
 
				repaint();
			}
			// is there a following item?
			else if(selectedItem < itemLines.length - 1)
			{
				selectedItem++;
 
				repaint();
			}
		}
	}
}

About the getTextRows() method, you can grab an implementation (but you could find a lot of other ones on the Web) on this other article written some time ago: J2ME Scrollable Text.

How to use CanvasList class

Here is a sample usage of CanvasList class, that will display a list (without image parts):

String[] items = new String[]{"Item 1", "Item 2", "Item 3"};
 
CanvasList myCanvas = new CanvasList("Test canvas", items, null);

To add images to your items, it’s necessary to instantiate an Image array, and pass it to CanvasList constructor as its third argument:

Image[] images = null;
try
{
	images = new Image[]{
		Image.createImage("/item1.png"),
		Image.createImage("/item2.png"),
		Image.createImage("/item3.png")
	};
}
catch(Exception e)
{
	e.printStackTrace();
}
String[] items = new String[]{"Item 1", "Item 2", "Item 3"};
 
CanvasList myCanvas = new CanvasList("Test canvas", items, images);

Related resources

You can download full CanvasList source code here: CanvasList.java

Be Sociable, Share!