Posts Tagged ‘canvas’

How to add sliding transitions between Canvas in J2ME

Monday, June 23rd, 2008

Today we’ll see a simple way to add sliding transition between Canvas in a Java ME application. Just take a look at it in the emulator page to see how it performs: Canvas sliding transitions in action!

j2me canvas sliding transition screenshot

The source code

FxBaseCanvas

First of all, we know that Canvas paint() method is protected, so, to access it from the class we’ll build, we must extend its visibility by extending Canvas class itself. We’ll do it by defining our FxBaseClass in this simple way:

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
 
public class FxBaseCanvas extends Canvas
{
	public void paint(Graphics g)
	{
	}
}

CanvasSlideFx

Now, we start building our CanvasSlideFx class, that will extend Canvas itself. We start defining some useful properties:

// time related properties
long startTime = 0;
long duration = 0;
 
// current state of the transition
boolean running = false;
 
// direction of sliding
int direction = LEFT;
 
// the previous and next Canvas instances
FxBaseCanvas fromCanvas = null;
FxBaseCanvas toCanvas = null;
 
// the current Display object
Display display = null;
 
// properties used to correctly place the 2 Canvas
int deltaX = 0;
int deltaY = 0;

Now, we define our class constructor, that will initialize coordinate properties according to the specified transition direction. The detailed argument list is:

  • The current Display object, that will be used to retrieve the current displayed Canvas, and to set the next one
  • The destination Canvas, that will extend the previously defined FxBaseCanvas class
  • The transition direction (one of Canvas.UP, RIGHT, DOWN or LEFT)
  • The transition duration, in milliseconds
public CanvasSlideFx(Display display, FxBaseCanvas toCanvas, int direction, long duration)
{
	this.display = display;
	this.fromCanvas = (FxBaseCanvas)display.getCurrent();
	this.toCanvas = toCanvas;
	this.direction = direction;
	this.duration = duration;
 
	switch(direction)
	{
	case UP:
		deltaY = - getHeight(); break;
	case RIGHT:
		deltaX = getWidth(); break;
	case DOWN:
		deltaY = getHeight(); break;
	case LEFT:
		deltaX = - getWidth(); break;
	}
}

Now, we define a startTransition() method, that will actually start the animation. To implement the animation itself, we let our class implement Runnable.

void startTransition()
{
	this.startTime = System.currentTimeMillis();
 
	running = true;
 
	new Thread(this).start();
}

And here’s the run() method implementation, that we must implement from Runnable interface. As long as the animation is running, we will repaint our animated Canvas, with a given interval of 50 milliseconds (but you can freely change this). When it finishes (so, running is false), we will exit the main loop and set the current Displayable to our toCanvas.

public void run()
{
	try
	{
		while(running)
		{
			repaint();
 
			synchronized(this)
			{
				wait(50L);
			}
		}
	}
	catch(Exception e)
	{
		e.printStackTrace();
	}
	display.setCurrent(toCanvas);
}

Finally, we have our paint() method, that will actually paint our transition. It will do this by painting both the source and the destination Canvas, translating them according to the transition direction, and to the elapsed time.

protected void paint(Graphics g)
{
	if(!running)
		startTransition();
 
	long diff = System.currentTimeMillis() - startTime;
 
	if(diff >= duration)
	{
		running = false;
 
		diff = duration;
	}
 
	int perc = (int)(100 * diff / duration);
 
	int dx = deltaX * perc / 100;
	int dy = deltaY * perc / 100;
 
	g.translate(dx, dy);
 
	fromCanvas.paint(g);
 
	g.translate(- deltaX, - deltaY);
 
	toCanvas.paint(g);
 
	g.translate(deltaX - dx, deltaY - dy);
}

How to use it?

Now we’ll see how to integrate the CanvasSlideFx within an existing code that already uses Canvas.
So, let’s assume that our application currently has, somewhere in its code, these lines:

MyCanvas firstCanvas = new MyCanvas();
 
Display.getDisplay(myMidlet).setCurrent(firstCanvas);
...
//and somewhere else
MyOtherCanvas secondCanvas = new MyOtherCanvas();
 
Display.getDisplay(myMidlet).setCurrent(secondCanvas);

where MyCanvas and MyOtherCanvas will likely extend Canvas.

Now here are the required steps to integrate transitions in our code:

  1. First of all, we must make MyCanvas and MyOtherCanvas extend FxBaseCanvas instead of directly Canvas. So, we’ll have:
    public class MyCanvas extend FxBaseCanvas ...
  2. Then, let’s say we want to animate the transition between firstCanvas and secondCanvas, we will remove the code:
    Display.getDisplay(myMidlet).setCurrent(secondCanvas);

    and replace it with:

    CanvasSlideFx fxCanvas = new CanvasSlideFx(
    	Display.getDisplay(myMidlet),
    	secondCanvas,
    	Canvas.LEFT,
    	500L
    );
     
    Display.getDisplay(myMidlet).setCurrent(fxCanvas);
  3. and we’ve done it! :)

Resources and download

You can download the code explained in this article with the following links:

A J2ME Calendar for all your Canvas!

Friday, May 16th, 2008

You know that J2ME support for Canvas is quite ridiculous.. One list, some form items, and stop. Canvas is left to its terrible destiny, with nothing more than a couple of lines and circles.. isn’t it sad?
So, after this melodramatic introduction, we’re ready for today’s code: a fully featured, customizable, Canvas based calendar!

J2me Canvas Date Picker screenshot

If you prefer a live demonstration rather than a simple screenshot, just go here: Canvas Calendar in action.

So, how to use it?

  1. Download its source code (CalendarWidget.java) and put it straight in your project
  2. Instantiate it within your Canvas with its plain-old-unique constructor:
    CalendarWidget calendar = new CalendarWidget(new Date());
  3. Customize it with the colors/fonts/padding you prefer:
    calendar.headerFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
    calendar.weekdayFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_MEDIUM);
    calendar.weekdayBgColor = 0xccccff;
    calendar.weekdayColor = 0x0000ff;
    calendar.headerColor = 0xffffff;
  4. After you’ve customized it, remember to always call its initialize() method:
    calendar.initialize();
  5. Now, to paint it, you can simply call its paint() method from your Canvas paint(), like this:
    protected void paint(Graphics g)
    {
        g.setColor(0xffffff);
        g.fillRect(0, 0, getWidth(), getHeight());
        calendar.paint(g);
    }
  6. Now you must allow users to interact with it, so you can, for example, use Canvas keyPressed() method to interact with calendar:
    protected void keyPressed(int key)
    {
        int keyCode = getGameAction(key);
        if(keyCode == FIRE)
        {
            Display.getDisplay(midlet).setCurrent(
                new Alert("Selected date", calendar.getSelectedDate().toString(), null, AlertType.CONFIRMATION)
            );
        }
        else
        {
            calendar.keyPressed(keyCode);
            repaint();
        }
    }

    As you see, what we do is this:

    • if the user press FIRE button, we alert the current selected date
    • otherwise we call calendar keyPressed() method, to make it behave accordingly
  7. Other customizable properties include:
    • MONTH_LABELS: change this to customize month labels in your own language
    • WEEKDAY_LABELS: as above, change this to customize weekday labels
    • startWeekday: this represents the week starting day, and its values range goes from 0 (for Monday) to 6 (for Sunday)

You can download source code of the example described above here: CalendarCanvas.java.

To get some more details about CalendarWidget source code, you can take a look at my article on Forum Nokia Wiki: Building a J2ME Canvas based Calendar / Date picker.

J2ME Table component with focus and scroll

Tuesday, April 22nd, 2008

Sometimes it happens that you must draw a table within a J2ME application. Even if there are some nice UI frameworks out there, they’re simply oversized if you need only a simple, plain, scrollable table.

This is the reason why I’ve decided to write a custom component that you can use to draw tables, with the following features:

  • Focusable cells
  • Vertical scrolling
  • Auto-sizing columns

J2ME canvas table screenshot

Some nice features to be added in a future version could be, for example:

  • Cell wrap when moving from a cell to another
  • Horizontal scrolling, to support tables with a lot of columns
  • Support for headers

You can see a live version on the emulator page. Full midlet source code is available here.