在這一篇中,我將向大家介紹圖形用戶界面中的低級圖形用戶界面。所謂低級圖形用戶界面,指的是那種我們可以自己在上面畫圖的控件,它是和TextBox,List等等這些用戶控件剛好相對的概念,因為這些用戶控件的形狀是事先畫好的,無需我們程序員操心,所以稱為高級圖形界面。低級圖形用戶界面什么東西都需要我們自己畫,所以比較復(fù)雜,當(dāng)然也更加靈活,只有想不到,沒有畫不出,所以我們先介紹它。
在J2ME開發(fā)中,低級圖形用戶界面是由javax.microedition.lcdui.Canvas類實現(xiàn)的,我們只要繼承這個類,并實現(xiàn)這個類的paint方法,就可以隨心所欲的進(jìn)行繪畫了。當(dāng)然,繪畫之前,我們少不了要了解我們的手機屏幕究竟有多大的畫圖空間,這可以通過調(diào)用Canvas類的getWidth和getHeight方法實現(xiàn)。下面是一個簡短的程序,向大家演示了怎么獲畫布的大小,同時,也算是一個小小的框架。首先,當(dāng)然是創(chuàng)建我們自己的畫布,代碼如下:
package?com.xkland.j2me;

import?javax.microedition.lcdui.Canvas;
import?javax.microedition.lcdui.Graphics;


/**?*//**
?*
?*?@author?海邊沫沫
?*/

public?class?MyCanvas?extends?Canvas?
{
????

????/**?*//**?Creates?a?new?instance?of?MyCanvas?*/

????public?MyCanvas()?
{
????}
????

????public?void?clearBackground(Graphics?g)
{
????????int?color?=?g.getColor();
????????g.setColor(0xffffff);
????????g.fillRect(0,0,getWidth(),getHeight());
????????g.setColor(color);
????}
????

????public?void?paint(Graphics?g)
{
????????//清除背景
????????clearBackground(g);
????????
????????//顯示可供繪圖的區(qū)域的大小
????????g.drawString("寬度:",10,10,Graphics.LEFT|Graphics.TOP);
????????g.drawString(String.valueOf(getWidth()),50,10,Graphics.LEFT|Graphics.TOP);
????????g.drawString("高度:",10,25,Graphics.LEFT|Graphics.TOP);
????????g.drawString(String.valueOf(getHeight()),50,25,Graphics.LEFT|Graphics.TOP);
????}
????
} 第二個類當(dāng)然就是我們的Midlet了,因為它是主程序嘛。在程序啟動的時候調(diào)用display.setCurrent將畫布設(shè)置為主界面,同時設(shè)置事件監(jiān)聽器。代碼比較簡單,如下:
package?com.xkland.j2me;

import?javax.microedition.midlet.*;
import?javax.microedition.lcdui.*;


/**?*//**
?*
?*?@author??海邊沫沫
?*?@version
?*/

public?class?CanvasTest?extends?MIDlet
{
????private?Canvas?canvas?=?new?MyCanvas();
????private?Display?display?=?null;
????private?Command?exitCommand?=?new?Command("退出",Command.EXIT,1);
????

????public?void?startApp()?
{

????????if(display==null)
{
????????????display?=?Display.getDisplay(this);
????????????canvas.addCommand(exitCommand);
????????????canvas.setCommandListener(new?MyCommandListener(this,canvas));
????????????display.setCurrent(canvas);
????????}
????}
????

????public?void?pauseApp()?
{
????}
????

????public?void?destroyApp(boolean?unconditional)?
{
????}
} 第三個類當(dāng)然是我們的事件監(jiān)聽器類了,等一下我們會講到,Canvas支持許多低級事件,比如鍵盤的按鍵事件,所以我們這里把事件監(jiān)聽器單獨抽取出來,代碼如下:
package?com.xkland.j2me;

import?javax.microedition.lcdui.CommandListener;
import?javax.microedition.lcdui.Command;
import?javax.microedition.lcdui.Displayable;
import?javax.microedition.lcdui.Canvas;


/**?*//**
?*
?*?@author?海邊沫沫
?*/

public?class?MyCommandListener?implements?CommandListener
{
????
????private?CanvasTest?app;
????private?Canvas?canvas;
????

????/**?*//**?Creates?a?new?instance?of?MyCommandListener?*/

????public?MyCommandListener(CanvasTest?app,Canvas?canvas)?
{
????????this.app?=?app;
????????this.canvas?=?canvas;
????}
????

????public?void?commandAction(Command?cmd,?Displayable?displayable)
{

????????if(cmd.getLabel().equalsIgnoreCase("退出"))
{
????????????app.destroyApp(false);
????????????app.notifyDestroyed();
????????}
????}
????
} 下面是運行效果:

知道了畫圖區(qū)域的大小,同時又知道Canvas可以支持許多低級事件,我們就可以發(fā)揮我們自己的想象力創(chuàng)建一個小游戲了。下面,我將寫一個簡單的拼圖游戲,只需要使用上下左右四個方向鍵操作即可,在事件監(jiān)聽器中,我們只需響應(yīng)Canvas的keyPressed()事件即可。代碼也不復(fù)雜,只需把上面的程序稍加擴展即可。當(dāng)然,我們還需要準(zhǔn)備一些圖片當(dāng)素材。
首先,在網(wǎng)上隨便找一張圖片,使用圖形編輯軟件調(diào)整圖片的大小,然后再裁成3*4共12幅圖象。把這12幅圖象分別命名為1.png到12.png,同時還要準(zhǔn)備一張全白的圖片,命名為0.png,這張圖片和前面的12張圖片一樣大小。在項目所在的文件夾下建立一個文件夾,取名為pictures,把這些圖片都拷貝進(jìn)去。在NetBeans IDE左邊的文件選項卡中可以看到這些文件,如圖:

但是,在生成項目的時候,這些文件并不會自動打包到項目中,我們必須將這個文件夾捆綁為該項目的資源。在項目上點右鍵,在彈出的菜單中選擇屬性,彈出如下對話框,選中左邊的“庫和資源”,在右邊點擊“添加文件夾”按鈕即可:

下面是我的MyCanvas類的全部代碼,其它兩個類的代碼沒有改變。在這里,我使用的圖片是174*280的大小,切割后的小圖片每一個都是58*70的大小,空白的圖片也是58*70的大小。請看代碼:
package?com.xkland.j2me;

import?javax.microedition.lcdui.Canvas;
import?javax.microedition.lcdui.Graphics;
import?javax.microedition.lcdui.Image;
import?java.util.Random;


/**?*//**
?*
?*?@author?海邊沫沫
?*/

public?class?MyCanvas?extends?Canvas?
{
????public?int[][]?pics?=?new?int[4][4];
????public?Image[]?images?=?new?Image[13];
????public?int?step?=?0;
????public?int?spaceX?=?3;
????public?int?spaceY?=?0;
????public?int?spaceValue?=?0;
????

????/**?*//**?Creates?a?new?instance?of?MyCanvas?*/

????public?MyCanvas()?
{
????????//隨機填充數(shù)組

????????for(int?i=0;i<4;i++)
{

????????????for(int?j=0;j<3;j++)
{
????????????????pics[i][j]?=?i*3?+?j?+?1;
????????????}
????????}???????
????????pics[0][3]?=?0;
????????
????????Random?rand?=?new?Random();

????????for(int?i=0;?i<4;?i++)
{
????????????int?x1?=?rand.nextInt(3);
????????????int?y1?=?rand.nextInt(4);
????????????int?x2?=?rand.nextInt(3);
????????????int?y2?=?rand.nextInt(4);
????????????int?n?=?pics[y1][x1];
????????????pics[y1][x1]?=?pics[y2][x2];
????????????pics[y2][x2]?=?n;
????????}
????????
????????//載入圖片

????????for(int?i=0;?i<13;?i++)
{

????????????try
{
????????????????images[i]?=?Image.createImage("/"?+?String.valueOf(i)?+?".png");

????????????}catch(Exception?e)
{
????????????????//不做處理
????????????}
????????}
????}
????

????public?void?clearBackground(Graphics?g)
{
????????int?color?=?g.getColor();
????????g.setColor(0xcccccc);
????????g.fillRect(0,0,getWidth(),getHeight());
????????g.setColor(color);
????}
????

????public?void?paint(Graphics?g)
{
????????//清除背景
????????clearBackground(g);
????????
????????//繪制網(wǎng)格
????????g.setColor(0x000000);
????????g.drawRect(1,3,236,284);
????????g.drawLine(1,74,237,74);
????????g.drawLine(1,145,178,145);
????????g.drawLine(1,216,178,216);
????????g.drawLine(60,3,60,287);
????????g.drawLine(119,3,119,287);
????????g.drawLine(178,3,178,287);
????????
????????//根據(jù)pics數(shù)組和images數(shù)組的內(nèi)容繪圖到網(wǎng)格中

????????for(int?i=0;?i<4;?i++)
{

????????????for(int?j=0;?j<3;?j++)
{
????????????????g.drawImage(images[pics[i][j]],j*59+2,i*71+4,Graphics.TOP|Graphics.LEFT);
????????????}
????????}
????????g.drawImage(images[pics[0][3]],179,4,Graphics.TOP|Graphics.LEFT);
????????
????????//繪制所用的步驟
????????g.drawString("步數(shù):",182,140,Graphics.TOP|Graphics.LEFT);
????????g.setColor(0xffffff);
????????g.fillRect(182,158,50,18);
????????g.setColor(0xff0000);
????????g.drawString(String.valueOf(step),187,160,Graphics.TOP|Graphics.LEFT);

????}
????
???????

????public?void?keyPressed(int?keyCode)
{

????????switch(getGameAction(keyCode))
{
????????????case?RIGHT:
????????????????right();
????????????????break;
????????????case?LEFT:
????????????????left();
????????????????break;
????????????case?UP:
????????????????up();
????????????????break;
????????????case?DOWN:
????????????????down();
????????????????break;
????????}
???????repaint();
????}
????

????public?void?up()
{

????????if(spaceY?<?3)
{
????????????pics[spaceY][spaceX]?=?pics[spaceY+1][spaceX];
????????????pics[spaceY+1][spaceX]?=?0;
????????????spaceY?++;
????????????step?++;
????????}
????}
????

????public?void?down()
{

????????if(spaceY?>0)
{
????????????pics[spaceY][spaceX]?=?pics[spaceY-1][spaceX];
????????????pics[spaceY-1][spaceX]?=?0;
????????????spaceY?--;
????????????step?++;
????????}
????????
????}
????

????public?void?left()
{
????????int?rightLimit?=?2;

????????if(spaceY?==?0)
{
????????????rightLimit?=?3;
????????}

????????if(spaceX?<?rightLimit)
{
????????????pics[spaceY][spaceX]?=?pics[spaceY][spaceX+1];
????????????pics[spaceY][spaceX+1]?=?0;
????????????spaceX?++;
????????????step?++;
????????}
????????
????}
????

????public?void?right()
{

????????if(spaceX?>?0?)
{
????????????pics[spaceY][spaceX]?=?pics[spaceY][spaceX?-1];
????????????pics[spaceY][spaceX-1]?=?0;
????????????spaceX?--;
????????????step?++;
????????}
????????
????}????
} 運行項目,得到如下的效果,使用上下左右四個鍵可以移動圖片:

游戲過程中的截圖:

游戲完成后的截圖:

當(dāng)然,大家也可以自己添加拼圖完成后的判斷代碼,在拼圖成功后自動彈出提示信息。