How to build a Canvas based list in Java ME
This article explains how it is possible to build a Canvas based List in Java ME.
It is possible to see this code in action on this page: Java ME Canvas based list in action
Source code: CanvasList
To start, you should define the CanvasList class, that will extend Canvas:
public class CanvasList extends Canvas
{
}
First thing to do now is to 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;
// this will hold the whole list height
int listHeight = 0;
// 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;
}
// set current list height
listHeight = top;
// 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)
{
scrollList(- SCROLL_STEP);
}
// 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())
{
scrollList(SCROLL_STEP);
}
// is there a following item?
else if(selectedItem < itemLines.length - 1)
{
selectedItem++;
repaint();
}
}
}
}
protected void scrollList(int deltaY)
{
scrollTop += deltaY;
if(scrollTop < 0)
scrollTop = 0;
else if(scrollTop + getHeight() > listHeight)
scrollTop = listHeight - getHeight();
repaint();
}
About the getTextRows() method, you can grab its implementation on this other Wiki article: J2me Scrollable Text
Source code: sample usage
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);
Download code
You can download CanvasList source code here: CanvasList.java



Tyler45 - touchscreen
how can we implement touch screen?tyler45 14:40, 22 August 2011 (EEST)