RCP-like Wizard Page in J2ME

[Techie's Tech Babble]
I get the idea from when I was developing with RCP. It was then, when I saw RCP wizard page concept, in which a base class is defined as a controller, while all the wizard pages are defined inside the class, making them easier to manage. You simply add the pages inside the definition, and then handle them at the exit points. Then I though, why not try adopt this to J2ME canvas pages? I always have problem in maintaining them, as I ussually arrange them into a sequence -- from WelcomePage to GameSelection, then to BattleScreen, to Animation1 or Animation2 etc. So here is my attemp to mimic them in J2ME.

First of all, let's make the pages class. Here is the source code for the class, which we will call PageCanvas.


public abstract class PageCanvas extends Canvas {
protected abstract void paint(Graphics g);
public abstract int exit();
public abstract void initialSettings();
}

There are two methods to note here. First of all, the exit() method. This method returns an exit code, which will be handled by the page handler class to direct the flow of the program to another page. While initialSetting method sets the PageCanvas object before it is displayed. we'll disscuss it's actual implementation later.

Next is the page handler. I call this class PageSequence class, which is a self managing thread. Here are the codes below:


public class PageSequence {
private MIDlet midlet;
private boolean switchPage = true;
private boolean isRunning = true;
private PageCanvas[] page;
private int pageIndex = -1;
private int pageExitCode = 0;

public PageSequence(MIDlet midlet) {
this.midlet = midlet;
display = Display.getDisplay(midlet);
initPages();
try {
Thread t = new Thread(this);
t.start();
} catch (Exception e) {
e.printStackTrace();
}
}

protected void initPages() {}

protected void firstPageController() {
//this is to initialize the first page, since the pageIndex is still -1.
//It will only be called once.
page[0].initialSetting();
pageIndex = 0;
}

public void run() {
try {
while (isRunning) {
if(switchPage) {
if (pageIndex == -1)
firstPageController();
else
pageController();
display.setCurrent(page[pageIndex]);
switchPage = false;
}
page[pageIndex].repaint();
if((pageExitCode = page[pageIndex].exit()) !=0){
switchPage = true;
}
//you can add a thread sleep method here, for the sake of sanity.
}
midlet.notifyDestroyed();
} catch (Exception e) {
e.printStackTrace();
}
}

protected void pageController() {}
}


Let me explain a bit of how this works. At the initPages() method, we declare all the PageCanvas which we'll use. Next, we put and run PageSequence in a thread, which it will continously check wether a page switch is assigned. Since it is the first time run, it is set to true. At first run, it will run firstPageController(), where the first page is initialized. Page switch is then turned of once more, then the cycle is continued.

Yes, I know. But when does it decides to switch page? The answer lies in the pageController() method, but to understand that lets try to create some sample.

First, let's create 2 PageCanvas, one is HelloPage that says hello, and ByePage that says goodbye.

public class HelloPage extends PageCanvas {
private exitCode = 0;

public void paint(Graphics g) {
g.drawString("Hello World",10,10,Graphics.LEFT|Graphics.TOP);
}

protected void keyPressed(int keyCode) {
if (keyCode == KEY_POUND)
exitCode = 1;
}

public int exit() {
return exitCode;
}


public void initialSetting() {
exitCode = 0;
}
}

public class ByePage extends PageCanvas {
private exitCode = 0;

public void paint(Graphics g) {
g.drawString("Goodbye World",10,10,Graphics.LEFT|Graphics.TOP);
}

protected void keyPressed(int keyCode) {
if (keyCode == KEY_POUND)
exitCode = 1;
}

public int exit() {
return exitCode;
}

public void initialSetting() {
exitCode = 0;
}
}


I've added a keyPressed method, so that the page will wait on user input before it switches page. An exit code 1 is returned upon it's invocation, since the main loop will wait until the exit code is changed (initially 0 at every start) before decided to switch page.

Now make some changes in the initPages() method:

public void initPages() {
page = new PageCanvas[2];
page[0] = new HelloPage();
page[1] = new Byepage();
}

and finally, the pageSequence() method:

protected void pageController() {
//control at the end of each page
if (pageIndex==0) {
page[1].initialSettings();
pageIndex = 1;
return;
}
if (pageIndex==1) {
page[0].initialSettings();
pageIndex = 0;
return;
}
}

Did you spot the trick? When entering pageController, the code check the pageIndex value, then direct the page to the corresponding index of the PageCanvas array. It might not be the most powerful technique, but this trick helps me manage better my code flow upon pages since now I'll only have to lookup PageSequence, add a page in initPages, create a logic for branching simply by making PageCanvas return different exit codes and handle them in pageController. Plus the pages are only created once in PageSequence, giving me more space in memory.

Now let's implement them on a midlet.

public class HelloMidlet extends MIDlet {

protected void startApp() throws MIDletStateChangeException {
new PageSequence(this);
}

protected void pauseApp() {}
protected void destroyApp(boolean destroy) throws MIDletStateChangeException {}
}


And that's that! You can run the midlet now and see the result. You can expand this method further, like return different exit codes for branching them into different pages. Here is an example:

protected void pageController() {
//control at the end of each page
if (pageIndex==0) {
if (pageExitCode == 1){
page[1].initialSettings();
pageIndex = 1;
}
else if (pageExitCode == 2){
page[2].initialSettings();
pageIndex = 2;
}
return;
}
}


Go ahead and experiment. Hope this been helpful to you, as it was to me ;)
Share on Google Plus

About BhimZ

Aria Bima Mahesa Putra (aka BhimZ) is an experienced software developer, with a lot of experience in various projects with different background. He is currently focused in mobile apps, and has been invested in game development ever since he was a kid in highschool. He founded BhimZ games, his one-man-army game studio as a mean to make his own brand of games during his spare times working as a software engineer in a multinational company. At leisure times he enjoys the company of his family, playing mobile games and watches Japanese tokusatsu and anime with his son.
    Blogger Comment
    Facebook Comment

3 comments:

Edi setiawan said...

Om(ga papa kan panggil om?), punya tutorial bikin game j2me ga? bagi-bagi dong! khususnya yang buat NPC? EMAIL: d307173@yahoo.com

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.