騎豬闖天下

          J2ME隨筆,記錄成長的腳步

          統(tǒng)計(jì)

          留言簿(3)

          閱讀排行榜

          評(píng)論排行榜

          [J2ME] MIDP低級(jí)界面開發(fā)

          MIDP低級(jí)界面開發(fā)
          <轉(zhuǎn)載>

          MIDP低級(jí)界面開發(fā)——使用LCDUI低級(jí)API
          高級(jí)API使用簡(jiǎn)單、有很高的可移植性,卻無法控制許多細(xì)節(jié)。要對(duì)界面更多的進(jìn)行控制,必須使用低級(jí)API。
          5.1 Canvas類開發(fā)簡(jiǎn)介
          低級(jí)界面屏幕都繼承自名為Canvas的屏幕類。Canvas類提供了一系列鍵盤低級(jí)事件和繪圖接口,具體的繪圖操作則由一個(gè)名為Graphics的圖形類來完成。
          5.1.1 Canvas類簡(jiǎn)介
          Canvas即畫布,可以在其上繪制不同圖案。Canvas提供了一個(gè)繪圖接口方法paint(Graphics g),凡是繼承Canvas的繼承類都必須實(shí)現(xiàn)paint()方法,因此可以在paint方法中實(shí)現(xiàn)屏幕的繪畫代碼。
          示例:
          class MyCanvas extends Canvas
          {
          public void paint(Graphics g)
          {

          }
          }
          paint方法傳入了Grpahics類型的參數(shù)g,具體的繪畫將由Graphics的g實(shí)現(xiàn)。可以看出Canvas類和Graphics類的關(guān)系是畫布與畫筆的關(guān)系。
          5.1.2 低級(jí)API與低級(jí)事件
          Canvas可以處理低級(jí)事件,但并非處理所有的系統(tǒng)事件。設(shè)備支持哪些系統(tǒng)事件,必須由硬件的支持程度來判斷。Canvas提供一些方法判斷硬件支持程度。
          功能
          檢測(cè)方法
          低級(jí)事件/回調(diào)函數(shù)
          鍵盤事件
          支持
          keyPressed(int keycode)
          keyReleased(int keycode)
          屏幕事件
          支持
          showNotity()
          hideNotify()
          重繪事件
          支持
          paint(Graphics g)
          是否支持雙緩沖
          Canvas.isDoubleBuffered()

          是否支持repeat
          Canvas.hasRepeatdEvent()
          keyRepeated(int keycode)
          是否支持觸控屏幕事件
          Canvas.hasPointerEvents()
          pointerPressed(int x, int y)
          pointerReleased(int x, int y)
          是否支持觸控屏幕拖拽事件
          Canvas.hasPointerMotionEvnets()
          pointerDragged(int x, int y)
          機(jī)器一定會(huì)支持的鍵盤事件有keyPressed()、keyReleased(),屏幕事件showNotify()、hideNotidy(),以及重繪事件paint()。
          注意:除了showNotidy()之外,其它回調(diào)函數(shù)只有在此Canvas是目前屏幕上的畫面時(shí)才會(huì)被調(diào)用。
          5.1.3 重繪事件
          示例:
          //CanvasTestMidlet.java
          import javax.microedition.midlet.*;
          import javax.microedition.lcdui.*;
          public class CanvasTestMidlet extends MIDlet
          {
          private Display display;
          public CanvasTestMidlet()
          {
          display = Display.getDisplay(this);
          }
          public void startApp()
          {
          MyCanvas mc = new MyCanvas();
          display.setCurrent(mc);
          }
          public void pauseApp()
          {
          }
          public void destroyApp(boolean unconditional)
          {
          }
          }
          //MyCanvas.java
          import javax.microedition.lcdui.*;
          public class MyCanvas extends Canvas
          {
          /** Creates a new instance of MyCanvas */
          public MyCanvas()
          {
          }
          public void paint(Graphics g)
          {
          }
          }
          任何時(shí)候都可以自行調(diào)用repaint()產(chǎn)生重繪事件。repaint()有兩個(gè)同名方法,其中一個(gè)需要四個(gè)參數(shù),用來指定重畫區(qū)域的X、Y坐標(biāo),寬度與高度;另外一個(gè)無參數(shù),代表重繪整個(gè)屏幕。調(diào)用repaint()之后會(huì)立刻返回,繼續(xù)下面工作,調(diào)用paint()回調(diào)函數(shù)的工作則由一個(gè)專門處理UI的線程來完成。若希望等到paint()完成后再返回,可以在repaint()之后立刻調(diào)用serviceRepaints()方法。
          注意:serviceRepaints()用來強(qiáng)制隊(duì)列中的重繪事件快點(diǎn)做完,如果隊(duì)列中沒有重繪事件,則serviceRepaints()什么也不會(huì)做,因此在調(diào)用serviceRepaints()之前,通常伴隨一個(gè)repaint()。
          5.1.4 坐標(biāo)系統(tǒng)
          在使用繪圖函式前,請(qǐng)先注意MIDP 中X 坐標(biāo)與Y 坐標(biāo)的定義方式。傳統(tǒng)的笛卡爾坐標(biāo)其原點(diǎn)在左下角,向右X 坐標(biāo)值遞增,向上Y坐標(biāo)值遞增。
          但是我們?cè)谑謾C(jī)的屏幕上做圖時(shí),變成向右X 坐標(biāo)值遞增,向下Y 坐標(biāo)值遞增。
          5.1.5 像素(Pixel)
          我們?cè)谒袌D形相關(guān)函數(shù)之中所使用的坐標(biāo)所代表的并非像素本身,而是指像素和像素之間的空格所構(gòu)成的坐標(biāo),如下圖所示:
          像素與像素之間所構(gòu)成的坐標(biāo)
          所以一般我們所說的坐標(biāo)(3,1)并非指位于(3,1)這個(gè)像素,而是指像素(2,0)、(2,1)、(3,0)、(3,1)所包圍的這個(gè)部分。也正因?yàn)樽鴺?biāo)指的并非圖素本身,所以會(huì)造成在繪制圖型和填滿區(qū)塊時(shí)有所差異,這兩者的不同我們將在以后說明。
          5.1.6 Graphics入門
          paint(Graphics g)方法會(huì)傳入一個(gè)Graphics對(duì)象作為參數(shù),可以把該對(duì)象當(dāng)作是一個(gè)抽象的畫筆,調(diào)用Graphics的方法,就可以在這個(gè)畫布上繪圖。
          編寫我們自己的Canvas時(shí),要做的第一件事就是把畫面清空,然后才開始繪圖,避免畫面上殘留前一個(gè)畫面所遺留下的東西。
          //清屏
          public void paint(Graphics g)
          {
          g.setColor(255, 0, 255);
          g.fillRect(0, 0, getWidth(), getHeight());
          … …
          }
          上述范例中,我們使用Graphics的setColor()來設(shè)置畫筆顏色:
          setColor(int r, int g, int b)注意,rgb的值限定在0~255之間。
          或setColor(int rgb) 直接傳入0x00RRGGBB這樣的整數(shù)。
          設(shè)定好顏色后,可以使用getRedComponent()、getGreenComponent()、getBlueComponent()分別取得R、G、B的顏色設(shè)定。或者直接使用getColor()取得0x00RRGGBB這樣的整數(shù),也就是說,最后第0~7 位代表藍(lán)色、8~15 代表藍(lán)色,16~23 代表紅色。
          getDisplayColor()較特殊,返回機(jī)器上繪圖時(shí)真正使用的顏色。有些機(jī)器不具有顯示所有顏色的能力。屏幕的灰度數(shù)可以用getGrayScale()取得,也可以用setGrayScale(),灰度數(shù)取值在0~255之間。使用這個(gè)函式的時(shí)候請(qǐng)?zhí)貏e注意,如果您已經(jīng)使用了相對(duì)應(yīng)的setGrayScale()來設(shè)定灰階色階數(shù),那么getGrayScale()函式只是單純地傳回設(shè)定值。但是如果您沒有設(shè)定灰階色階數(shù),那么呼叫g(shù)etGrayScale()函式的時(shí)候,會(huì)導(dǎo)致系統(tǒng)利用目前作用色的R、G、B 值來做大量運(yùn)算,并求得最接近的灰階色階數(shù)。
          5.1.7 繪制直線
          我們可以使用Graphics 類別的drawLine()函式繪制線段。DrawLine 的四個(gè)參數(shù)分別是起點(diǎn)X 坐標(biāo),起點(diǎn)Y 坐標(biāo)、終點(diǎn)X 坐標(biāo)、終點(diǎn)Y 坐標(biāo)。舉例來說,如果我們函式呼叫為:g.drawLine(1,1,1,6)
          則實(shí)際繪制的線段如下圖所示:
          實(shí)際繪制出來的線段的位置
          我們可以發(fā)現(xiàn)坐標(biāo)右邊的相素都會(huì)被填滿。
          如果我們函式調(diào)用為:
          g.drawLine(1,1,6,1)
          則實(shí)際繪制的線段如下圖所示:
          實(shí)際繪制出來的線段的位置
          我們可以發(fā)現(xiàn)坐標(biāo)下方的像素都會(huì)被填滿。
          當(dāng)我們繪圖形時(shí),有所謂的筆觸(stroke style)。Graphics提供兩種筆觸,分別是Graphics.SOLID和Graphics.DOTTED:
          g.setStrokeStyle(Graphics.DOTTED);
          相應(yīng)的取得目前所用筆觸:g.getStrockStyle()
          5.1.8 畫弧形
          我們可以使用Graphics 類的drawArc()方法繪制弧形。drawArc 共有6 個(gè)參數(shù),它們分別是:前四個(gè)決定弧形所在的矩形范圍,第五個(gè)決定起始角度,第六個(gè)參數(shù)則決定弧形本身所涵蓋的角度。
          如果我們方法調(diào)用為:
          g.drawArc(20,10,width,height,45,90);
          則實(shí)際繪制的弧形如下圖所示:
          實(shí)際繪制出來的弧形
          填充弧形
          我們可以使用Graphics 類別的fillArc()函式填充弧形。fillArc 共有6 個(gè)參數(shù),它們分別是:前四個(gè)決定弧形所在的矩形范圍,第五個(gè)決定起始角度,第六個(gè)參數(shù)則決定弧形本身所涵蓋的角度。
          如果我們方法調(diào)用為:
          g.fillArc(20,15,width,height,45,90);
          則實(shí)際繪制的填充弧形如下圖所示:
          實(shí)際繪制出來的填充弧形
          5.1.9 矩形
          畫矩形:我們可以使用Graphics 類別的drawRect()函式繪制矩形。drawRect 有4 個(gè)參數(shù),分別是起點(diǎn)X 坐標(biāo)、起點(diǎn)Y 坐標(biāo)、寬度、長度。
          如果我們函數(shù)調(diào)用為:
          g.drawRect(1,1,6,8)
          則實(shí)際繪制的矩形如下圖所示:
          實(shí)際繪制出來的矩形
          我們可以發(fā)現(xiàn)所構(gòu)成的矩形路徑,其右邊和下方的像素都被填滿了。
          畫圓角矩形:我們可以使用Graphics 類別的drawRoundRect()函式繪制圓角矩形。其實(shí)drawRoundRect()和drawRect()函式的前四個(gè)參數(shù)意義相同,唯一的差距只有在最后兩個(gè)參數(shù),它們分別是圓角所在矩形的寬度,以及圓角所在矩形的高度。
          如果我們方法調(diào)用為:
          g.drawRoundRect(1,1,6,8,arcWidth,arcHeight)
          則實(shí)際繪制的圓角矩形,在矩形的部分和使用drawRect()的結(jié)果相同,差別只有在四個(gè)直角的樣子不再是直角,而變成圓角。
          如下圖所示:
          實(shí)際繪制出來的圓角矩形
          填充矩形:我們可以使用Graphics 類別的fillRect()函式填充矩形。fillRect 有4 個(gè)參數(shù),分別是起點(diǎn)X 坐標(biāo)、起點(diǎn)Y 坐標(biāo)、寬度、長度。
          如果我們方法調(diào)用為:
          g.fillRect(1,1,6,8)
          則實(shí)際繪制的矩形如下圖所示:
          實(shí)際繪制出來的填充矩形
          我們可以發(fā)現(xiàn)只有包含在矩形路經(jīng)之內(nèi)的圖素才會(huì)被填滿,這和drawRect()函式的結(jié)果有所不同(上下都差一個(gè)圖素的大小)。
          填充圓角矩形:我們可以使用Graphics 類別的fillRoundRect()函式填充圓角矩形。其實(shí)fillRoundRect()和fillRect()函式的前四個(gè)參數(shù)意義相同,唯一的差距只有在最后兩個(gè)參數(shù),它們分別是圓角所在舉行的寬度,以及圓角所在矩形的高度。
          如果我們方法調(diào)用為:
          g.fillRoundRect(1,1,6,8,arcWidth,arcHeight)
          則實(shí)際繪制的圓角矩形,在矩形的部分和使用fillRect()的結(jié)果相同,差別只有在四個(gè)角的樣子不再是直角,而變成圓角,如下圖所示:
          實(shí)際繪制出來的填充圓角矩形
          5.1.10 三角形
          繪制三角形,使用三個(gè)頂點(diǎn),分別畫線即可,因此MIDP只提供填充三角形的功能:
          g.fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) ;
          練習(xí):嘗試自己繪制三角形,并填充它
          5.2 Canvas與屏幕事件處理
          Canvas本身具有兩種狀態(tài):
          ?? 普通狀態(tài)
          ?? 全屏狀態(tài)
          可以使用setFullScreenMode()設(shè)定Canvas狀態(tài)。
          示例:
          /*
          * FullScreenCanvas.java
          *
          * Created on 2006年2月26日, 上午5:54
          */
          import javax.microedition.lcdui.*;
          /**
          *
          * @author Allan
          */
          public class FullScreenCanvas extends Canvas implements CommandListener
          {
          public FullScreenCanvas()
          {
          setTitle("Full screen test");
          setTicker(new Ticker("running..."));
          addCommand(new Command("full screen", Command.SCREEN, 1));
          addCommand(new Command("normal", Command.SCREEN, 1));
          setCommandListener(this);
          }
          public void paint(Graphics g)
          {
          g.setColor(255, 255, 255);
          g.fillRect(0, 0, getWidth(), getHeight());
          }
          public void commandAction(Command c, Displayable s)
          {
          String cmd = c.getLabel();
          if (cmd.equals("full screen"))
          {
          setFullScreenMode(true);
          }
          else if (cmd.equals("normal"))
          {
          setFullScreenMode(false);
          }
          }
          public void sizeChanged(int w, int h)
          {
          System.out.println("width:" + w);
          System.out.println("height:" + h);
          }
          public void hideNotify()
          {
          System.out.println("應(yīng)用程序區(qū)域被覆蓋");
          }
          public void showNotify()
          {
          System.out.println("屏幕顯示");
          }
          }
          幾個(gè)重要觀念:
          1) 對(duì)于Canvas低級(jí)API,標(biāo)題、Ticker、Command區(qū)域依然有用;
          2) 全屏模式下,標(biāo)題、Ticker、Command區(qū)域無法顯示,但原本對(duì)應(yīng)到按鈕的地方仍然存在,只是看不見;
          3) 調(diào)用setFullScreenMode()時(shí),不管設(shè)置成全屏模式還是正常模式,sizeChanged()都會(huì)被調(diào)用,并傳入當(dāng)前屏幕的高度和寬度。
          4) 當(dāng)屏幕被系統(tǒng)畫面(如菜單、來電顯示等)覆蓋時(shí),會(huì)自動(dòng)調(diào)用hideNotify(),告知應(yīng)用程序目前的畫面被覆蓋了。當(dāng)這些系統(tǒng)畫面消失時(shí),系統(tǒng)將調(diào)用showNotify()告知應(yīng)用程序。Canvas第一次顯示在屏幕上時(shí),系統(tǒng)也會(huì)調(diào)用showNotify()。Canvas移出屏幕(有其它displayable被顯示,調(diào)用setCurrent())時(shí),hideNotify()會(huì)被調(diào)用。
          5) 當(dāng)我們使用Graphics繪圖時(shí),零坐標(biāo)會(huì)隨著模式的改變而改變,所以零點(diǎn)不是絕對(duì)的,而是相對(duì)于應(yīng)用程序區(qū)而言。因?yàn)槠聊坏拇笮?huì)改變,所以在清除屏幕(fillRect())的時(shí)候使用canvas.getHeight()和canvas.getWidth()取得屏幕大小,而不是固定值。
          5.3 鍵盤事件處理
          當(dāng)Canvas子類正作用于屏幕時(shí),按下任何按鈕,就會(huì)引發(fā)keyPressed()方法,并傳入一個(gè)代表該按鈕的整數(shù),而放開按鈕之后,會(huì)引發(fā)keyReleased()方法,并傳入一個(gè)代表該按鈕的整數(shù)值。系統(tǒng)如果傳入小于0的值,則為不合法keycode。
          某些機(jī)器上還可以支持連發(fā)事件(即一直按著按鈕持續(xù)一段時(shí)間),該事件會(huì)引發(fā)keyRepeated()
          方法,并傳入一個(gè)代表該按鈕的數(shù)值,但該事件并非所有機(jī)器都支持,所以我們有必要使用Canvas類中的hasRepeatEvents()方法詢問系統(tǒng)是否支持連發(fā)事件。
          示例:
          import javax.microedition.lcdui.*;
          public class KeyEventTestCanvas extends Canvas
          {
          private boolean pressed = false;
          public KeyEventTestCanvas()
          {
          }
          public void paint(Graphics g)
          {
          g.setColor(125, 125, 125);
          g.fillRect(0, 0, getWidth(), getHeight());
          if (pressed)
          {
          g.setColor(0, 0, 0);
          g.drawLine(20, 20, 120, 20);
          g.drawLine(20, 20, 20, 100);
          g.setColor(255, 255, 255);
          g.drawLine(120, 20, 120, 100);
          g.drawLine(20, 100, 120, 100);
          }
          else
          {
          g.setColor(255, 255, 255);
          g.drawLine(20, 20, 120, 20);
          g.drawLine(20, 20, 20, 100);
          g.setColor(0, 0, 0);
          g.drawLine(120, 20, 120, 100);
          g.drawLine(20, 100, 120, 100);
          }
          }
          protected void keyPressed(int keycode)
          {
          pressed = true;
          repaint();
          }
          protected void keyReleased(int keycode)
          {
          pressed = false;
          repaint();
          }
          }
          此例中,把
          protected void keyPressed(int keycode)
          {
          pressed = true;
          repaint();
          }
          protected void keyReleased(int keycode)
          {
          pressed = false;
          repaint();
          }
          改為
          protected void keyPressed(int keycode)
          {
          repaint();
          pressed = true;
          }
          protected void keyReleased(int keycode)
          {
          repaint();
          pressed = false;
          }
          結(jié)果是一樣的,這是因?yàn)榛卣{(diào)函數(shù)都是在同一個(gè)UI的線程中執(zhí)行,因此理論上,repaint()只是產(chǎn)生一個(gè)重繪事件就立刻返回,系統(tǒng)必須等到keyPressed()/keyReleased()執(zhí)行完畢之后才能繼續(xù)調(diào)用paint()重繪屏幕。
          5.4 鍵盤響應(yīng)
          Canvas里定義了幾個(gè)常數(shù)
          KEY_NUM0、KEY_NUM1 ~ KEYNUM9
          KEY_STAR、KEY_POUND共12個(gè)
          可以利用這幾個(gè)常數(shù)判定事件處理方法所傳進(jìn)來的keyCode,得知那個(gè)按鈕被按下。
          為了程序可以跨平臺(tái)執(zhí)行,建議使用這些標(biāo)準(zhǔn)的定義鍵。
          玩游戲的時(shí)候通常2、4、6、8分別代表上、下、左、右,星字鍵代表發(fā)射,井字代表跳躍。但并非所有機(jī)器上都會(huì)有相同的鍵盤排列方式,也并非一定按照此方式設(shè)定。為了設(shè)計(jì)Game的時(shí)候方便,MIDP規(guī)范中,Canvas中定義了幾個(gè)與Game鍵盤代碼相關(guān)的常數(shù),分別是UP、DOWN、LEFT、RIGHT、FIRE、GAME_A、GAME_B、GAME_C、GAME_D。這些定義與之前的定義有所重復(fù),但是因?yàn)橛辛艘恍┏橄笮裕谝浦驳臅r(shí)候也就方便多了。
          常用方法:
          1. getGameAction(int keyCode);
          該方法傳入keyCode,會(huì)返回所代表的Game鍵盤代碼。
          switch(getGameAction(keyCode))
          {
          case Canvas.FIRE:
          fire();
          break;

          }
          2. getKeyCode()
          該方法傳入Game鍵盤碼,返回所代表的keyCode。
          if (keyCode == getKeyCode(Canvas.LEFT))
          {
          moveLeft();
          }
          3. 可以利用Canvas的getKeyName()取得該keyCode所代表的按鍵名稱
          示例:
          import javax.microedition.lcdui.*;
          /**
          *
          * @author Allan
          */
          public class KeyEventTestCanvas extends Canvas
          {
          private boolean pressed = false;
          //cross坐標(biāo)
          private int x;
          private int y;
          private final int length = 20;
          private int dxy = 5;
          /** Creates a new instance of KeyEventTestCanvas */
          public KeyEventTestCanvas()
          {
          x = getWidth()/2;
          y = getHeight()/2;
          if (this.hasRepeatEvents())
          {
          System.out.println("支持連發(fā)");
          }
          else
          {
          System.out.println("不支持連發(fā)");
          }
          }
          public void paint(Graphics g)
          {
          g.setColor(128, 128, 128);
          g.fillRect(0, 0, getWidth(), getHeight());
          paintButton(g, 10, 10, 120, 90, pressed);
          paintCross(g, x, y, length);
          }
          public void paintButton(Graphics g, int x, int y, int w, int h, boolean pressed)
          {
          if (pressed)
          {
          g.setColor(0, 0, 0);
          g.drawLine(x, y, x+w, y);
          g.drawLine(x, y, x, y+h);
          g.setColor(255, 255, 255);
          g.drawLine(x+w, y, x+w, y+h);
          g.drawLine(x, y+h, x+w, y+h);
          }
          else
          {
          g.setColor(255, 255, 255);
          g.drawLine(x, y, x+w, y);
          g.drawLine(x, y, x, y+h);
          g.setColor(0, 0, 0);
          g.drawLine(x+w, y, x+w, y+h);
          g.drawLine(x, y+h, x+w, y+h);
          }
          }
          /*
          *@parameter x 十字中心點(diǎn)x坐標(biāo)
          *@parameter y 十字中心點(diǎn)y坐標(biāo)
          */
          public void paintCross(Graphics g, int x, int y, int length)
          {
          g.setColor(255, 0, 0);
          g.drawLine(x-length, y, x+length, y);
          g.drawLine(x, y-length, x, y+length);
          }
          public void keyPressed(int keycode)
          {
          //打印keycode代表的按鍵名稱
          //System.out.println(getKeyName(keycode));
          int action = getGameAction(keycode);
          switch (action)
          {
          case Canvas.UP:
          y -= dxy;
          break;
          case Canvas.DOWN:
          y += dxy;
          break;
          case Canvas.LEFT:
          x -= dxy;
          break;
          case Canvas.RIGHT:
          x += dxy;
          break;
          case Canvas.FIRE:
          pressed = true;
          break;
          }
          repaint();
          }
          public void keyReleased(int keycode)
          {
          int action = getGameAction(keycode);
          switch (action)
          {
          case Canvas.FIRE:
          pressed = false;
          break;
          }
          repaint();
          }
          public void keyRepeated(int keycode)
          {
          int action = getGameAction(keycode);
          switch (action)
          {
          case Canvas.UP:
          y -= dxy;
          break;
          case Canvas.DOWN:
          y += dxy;
          break;
          case Canvas.LEFT:
          x -= dxy;
          break;
          case Canvas.RIGHT:
          x += dxy;
          break;
          case Canvas.FIRE:
          pressed = true;
          break;
          }
          repaint();
          }
          }
          5.5 觸控屏幕的事件處理
          當(dāng)Canvas是當(dāng)前畫面,數(shù)控筆在屏幕上點(diǎn)擊,就會(huì)引發(fā)pointerPressed()方法,并傳入其
          當(dāng)前處于屏幕的x與y坐標(biāo),放開出控筆后,會(huì)引發(fā)pointerReleased()方法,并傳入當(dāng)前屏幕位置的x與y坐標(biāo)。某些機(jī)器上可以產(chǎn)生拖拽事件(即一直按住屏幕拖拽),該事件會(huì)引發(fā)pointerDragged()方法,并傳入當(dāng)時(shí)處于屏幕位置的x與y坐標(biāo)。
          并非所有設(shè)備都支持觸控事件,我們可以使用Canva類中的hasPointerEvents()方法獲得系統(tǒng)是否支持觸控筆事件的信息。
          并非所有設(shè)備都支持拖拽事件, 我們可以使用Canvas類中的hasPointerMotionEvents()方法判斷系統(tǒng)是否支持觸控筆拖拽事件。
          示例:
          public class PointerEventTestCanvas extends Canvas implements CommandListener
          {
          private int x1;
          private int y1;
          private int x2;
          private int y2;
          private Command backCommand;
          /** Creates a new instance of PointerEventTestCanvas */
          public PointerEventTestCanvas()
          {
          backCommand = new Command("返回", Command.BACK, 1);
          addCommand(backCommand);
          setCommandListener(this);
          if (hasPointerEvents())
          {
          System.out.println("支持?jǐn)?shù)控筆");
          }
          else
          {
          System.out.println("不支持?jǐn)?shù)控筆");
          }
          if (hasPointerMotionEvents())
          {
          System.out.println("支持?jǐn)?shù)控筆拖拽");
          }
          else
          {
          System.out.println("不支持?jǐn)?shù)控筆事件");
          }
          }
          public void paint(Graphics g)
          {
          g.setColor(255, 255, 0);
          g.fillRect(0, 0, getWidth(), getHeight());
          g.setColor(0, 0, 0);
          g.drawLine(x1, y1, x2, y2);
          }
          public void pointerPressed(int x, int y)
          {
          x1 = x;
          y1 = y;
          }
          public void pointerReleased(int x, int y)
          {
          x2 = x;
          y2 = y;
          repaint();
          }
          public void pointerDragged(int x, int y)
          {
          x2 = x;
          y2 = y;
          repaint();
          }
          public void commandAction(Command c, Displayable s)
          {
          if (c == backCommand)
          {
          }
          }
          }
          5.6低級(jí)事件和高級(jí)事件同時(shí)出現(xiàn)
          當(dāng)高級(jí)事件和低級(jí)事件同時(shí)出現(xiàn)時(shí),系統(tǒng)會(huì)自動(dòng)判斷。如果按鈕屬于系統(tǒng)的,就會(huì)交給高級(jí)
          事件處理方法來處理,如果不是,才會(huì)由低級(jí)事件來做。
          5.7 繪制字符串
          Graphics類提供了繪制字符串的方法,原形如下:
          public void drawString(String str, int x, int y, int anchor)
          參數(shù):
          x、y:相對(duì)于屏幕原點(diǎn)的x、y坐標(biāo)
          anchor:定位點(diǎn)
          注意:即使x、y相同,anchor不同,具體位置還是不同的(后面詳述)
          另外,需要了解的是字符串本身顯示要占用屏幕上的一個(gè)矩形的空間。anchor的作用就是設(shè)置字符串所處矩形區(qū)域位于屏幕坐標(biāo)的哪個(gè)位置。
          5.8 Image類
          Image 類是我們?cè)谔幚韴D形時(shí)常常會(huì)用的類別,如果根據(jù)它的產(chǎn)生方式, 我們可以細(xì)分成可修改( mutable ) 和不可修改(immutable)兩種。要辨別一個(gè)Image 對(duì)象是可修改還是不可修改,您可以呼叫Image 對(duì)象的isMutable()方法得知。我們可以使用getWidth()與getHeight()取得該Image 對(duì)象的寬度與高度。
          要產(chǎn)生不可修改的Image 對(duì)象,主要方法有三種:
          1. 從影像文件讀取:根據(jù)MIDP 的規(guī)定,所實(shí)現(xiàn)MIDP 的廠商至少要提供讀取PNG(Portable Network Graphics)影像文件的功能。有些廠商會(huì)支持其它如GIF 影像文件的功能,但是不建議使用,因?yàn)楹芸赡茏屇腗IDlet 無法跨平臺(tái)。
          2. 由Byte 數(shù)組建立:我們可以經(jīng)由從網(wǎng)絡(luò)或resourcebundle 里的文字文件讀入一連串的byte 數(shù)組,然后用此數(shù)組產(chǎn)生不可修改的Image 對(duì)象。
          3. 從其它Image 對(duì)象(可修改或不可修改皆可)來產(chǎn)生。
          范例:
          import javax.microedition.lcdui.*;
          public class ImageCanvas extends Canvas
          {
          private Image img;
          /** Creates a new instance of ImageCanvas */
          public ImageCanvas()
          {
          try
          {
          img = Image.createImage("/mario.PNG");
          }
          catch (Exception e)
          {
          e.printStackTrace();
          }
          }
          public void paint(Graphics g)
          {
          g.drawImage(img, 0, 0, g.TOP|g.LEFT);
          }
          }
          在此范例之中,我們使用:img = Image.createImage("/mario.PNG");
          從MIDlet Suite 之中讀取名為mario.PNG的圖片。
          然后利用g.drawImage(image, 0, 0, g.TOP|g.LEFT);畫出此Image對(duì)象。第二種建立不可修改Image 對(duì)象的方法是利用其方法:
          createImage(byte[] imagedata, int imageOffset, int imageLength)
          第三種方法則是利用方法: createImage(Image source)就可以從現(xiàn)有可修改或不可修改的Image 對(duì)象取得一份不可修改的拷貝。
          可修改的Image 對(duì)象
          建立一個(gè)可修改的Image 對(duì)象非常簡(jiǎn)單,只要呼叫Image 對(duì)象的靜態(tài)方法:
          createImage(int width,int height)
          即可建立一個(gè)可修改的Image 對(duì)象。事實(shí)上,可修改的Image和Double Buffering 的技術(shù)息息相關(guān),可修改的Image 對(duì)象實(shí)際上就是一個(gè)供人在背景繪圖的off screen。因此在建立可修改的Image 對(duì)象前,您應(yīng)該先呼叫Canvas 類別的isDoubleBuffered()函式來確定您的機(jī)器是否支持Double Buffering 技術(shù),如果該函式傳回false,那么您就不該試圖建立可修改的Image 對(duì)象。
          一旦您取得了可修改的Image 對(duì)象,我們就可以呼叫Image 類別的getGraphics()取得代表off screen 的Graphics 對(duì)象,在off screen 繪圖并不會(huì)影響到正常的畫面(on screen)。
          最后,我們可以利用on screen ( 由paint 函式傳入的Graphics 物件) 的drawImage()函
          式繪出可修改Image 對(duì)象的內(nèi)容。
          示例:
          Image source;
          source = Image.createImage(“... ”) ;
          //建立可修改Image對(duì)象
          Image copy = Image.createImage(source.getWidth(), source.getHeight());
          Graphics g = copy.getGraphics();//獲取copy的Graphics對(duì)象
          g.drawImage(source, 0, 0, Graphics.TOP|Graphics.LEFT);
          5.9 繪制圖片、文字以及定位點(diǎn)的作用
          繪制圖片、字符串或是單一文字都會(huì)用到定位點(diǎn)(Anchor)的概念。定位點(diǎn)代表的意義是,繪制圖形跟文字時(shí),所指定的X、Y坐標(biāo)指的是何種意義。
          定位點(diǎn)定義共有七種:
          Graphics.TOP
          Graphics.BOTTOM
          Graphics.LEFT
          Graphics.RIGHT
          Graphics.HCENTER
          Graphics.VCENTER
          Graphics.BASELINE它們對(duì)文字和圖形的控制都具有意義。
          注意:圖中標(biāo)有VCENTER參數(shù),主要是因?yàn)镸IDP1.0提供了該參數(shù)。但MIDP2.0中已經(jīng)不允許使用該參數(shù),主要是因?yàn)檫@個(gè)參數(shù)不好計(jì)算而且實(shí)際使用的意義也不大,如果在MIDP2.0中調(diào)用該參數(shù),將會(huì)拋出異常。
          這幾種定義可以有意義地組合。舉例來說,如果我們選擇使用TOP 加上LEFT,則繪制文字時(shí),我們會(huì)使用函式:
          g.drawString(“文字xyzh”, 0, 0, Graphics.TOP|Graphics|LEFT) ;
          繪制圖形時(shí),我們會(huì)使用函式:
          g.drawImage(image, 0, 0, g.TOP|g.LEFT);
          這時(shí)畫面上的結(jié)果為:
          不管是drawString()或是drawImage()其第二與第三個(gè)參數(shù)所指定的坐標(biāo)指的是定位點(diǎn)所參考的起始地址。以上述結(jié)果為例,我們指定(0,0)為定位點(diǎn)參考起始位置,然后又選擇的TOP 與LEFT 作為定位點(diǎn),代表(0,0)這個(gè)坐標(biāo)為字符串或圖形繪制在屏幕上時(shí)左上角的點(diǎn)。
          再舉個(gè)例子,如果我們選擇使用BOTTOM 加上HCENTER,則繪制文字時(shí),我們會(huì)使用函式:
          g.drawString(“文字xyzh”, 0, 0,Graphics.BOTTOM|Graphics.HCENTER) ;
          繪制圖形時(shí),我們會(huì)使用函式:
          g.drawImage(image, 0, 0, g.BOTTOM |g.HCENTER);
          這時(shí)畫面上的結(jié)果為:
          由此我們可以歸納出,如果您使用的方法為:
          g.drawString("Hello",x,y,g.TOP|g.LEFT) ;

          g.drawString("Hello",x,y,0) ;
          跟我們使用
          g.drawString("Hello",x + stringWidth()/2,y + getHeight(),g.BOTTOM|g.HCENTER) ;
          兩者的意義是相同。
          思考練習(xí):居中字符串。
          5.10 字體
          當(dāng)我們需要在屏幕上匯出文字時(shí),我們常常需要一些有關(guān)字體的相關(guān)數(shù)據(jù),這時(shí)就需要Font 類別的輔助。通常,我們會(huì)使用Font.getDefaultFont()取得代表系統(tǒng)預(yù)設(shè)所使用字型的Font 對(duì)象。或者也可以自行使用Font.getFont()來取得代表特定字型的對(duì)象。
          getFont() 共有三個(gè)參數(shù),
          Font f = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE) ;
          他們分別是外觀( face )、樣式(style)、以及尺寸(size)。他們分別有各種選項(xiàng):
          外觀: Graphics.FACE_MONOSPACE 定寬字體
          Graphics.FACE_PROPORTIONAL 比例字體
          Graphics.FACE_SYSTEM 系統(tǒng)字體
          樣式 : Graphics.STYLE_BOLD 加粗字體
          Graphics.STYLE_ITALIC 傾斜字體
          raphics.STYLE_PLAIN 常規(guī)字體
          Graphics.STYLE_UNDERLINED 下劃線
          尺寸 : Graphics.SIZE_LARGE 大號(hào)字體
          Graphics.SIZE_MEDIUM 中號(hào)字體
          Graphics.SIZE_SMALL 小號(hào)字體
          需要注意的是,底層不一定全部支持。getFont()還有另一個(gè)只有一個(gè)參數(shù)的重載方法,只有PONT_INPUT_TEXT和DON’T_STATIC_TEXT兩種可以選擇,這個(gè)方法用來取得系統(tǒng)用來顯示輸入用的字體以及一般常用的字體。
          但是最實(shí)際程序之中,我們最常使用的是Graphics 類別的getFont()方法取得當(dāng)時(shí)顯示在畫面上的屏幕所使用的字型。同理,我們也可以使用Graphics 類別的setFont()方法設(shè)定所使用的字體:
          g.setFont(f);
          當(dāng)我們?nèi)〉么碜中偷膶?duì)象之后,我們就可以利用getFace()函式取得其外觀、getStyle()取得其樣式、getSize()取得其尺寸。而樣式的部分我們也可以改用isBold()、isItalic()、isPlain()、isUnderlined()函式來取得相關(guān)信息,這是因?yàn)闃邮绞强梢院铣傻模粋€(gè)字型的樣式很可能同時(shí)是黑體與斜體的組合。
          Font 類別除了可以幫我們?nèi)〉米中偷耐庥^、樣式與尺寸之外,還能幫助我們?nèi)〉迷撟中驮谄聊簧系南嚓P(guān)屬性,請(qǐng)參考下圖:
          Font 的屬性
          其中:
          charWidth()取得屏幕上某個(gè)字符使用該字體顯示時(shí)的寬度;
          charsWidth()計(jì)算一串字符顯示時(shí)的寬度;
          stringWidth()取得屏幕上某個(gè)字符串使用該字體顯示時(shí)的寬度;
          substringWidth()則是某個(gè)字符串的子字符串顯示時(shí)的寬度;
          getBashLinePosition()可以讓我們知道從字體最頂點(diǎn)到baseline的距離;
          getHeight()可以取得最頂點(diǎn)到最低點(diǎn)的距離。
          5.11 顏色
          Grpahics類提供了3種顏色設(shè)置方法:
          public void setColor(int r, int g, int b)
          public void setColor(int RGB)
          public void setGrayScale(int value)
          其中,setGrayScale作用是繪制灰階,只是0到255共256種;setColor方法的作用是設(shè)置RGB顏色模式以在屏幕上顯示彩色的顏色。
          RGB模型:對(duì)于彩色圖像中的每個(gè)RGB(Red、Green、Blue)分量,為每個(gè)像素指定一個(gè)0(黑色)到255(白色)之間的強(qiáng)度值。當(dāng)三個(gè)分量相等時(shí),結(jié)果是中性灰色;當(dāng)所有分量的值均為255時(shí),結(jié)果為白色;當(dāng)這些值都為0時(shí),結(jié)果為純黑色。
          setColor(int RGB)的參數(shù)格式是0x00RRGGBB,高2位0x00被忽略,僅僅計(jì)算RRGGBB,高2位主要用來計(jì)算色彩的Aplpha混合的。
          5.12 調(diào)整坐標(biāo)原點(diǎn)
          Graphics類提供了調(diào)整屏幕原點(diǎn)位置的方法法:
          public void translate(int x, int y)
          改變?cè)c(diǎn)的坐標(biāo)在手機(jī)屏幕上的位置,并把相對(duì)于原來坐標(biāo)系統(tǒng)原點(diǎn)的坐標(biāo)(x,y)作為新的原點(diǎn)。需要注意的是,每次調(diào)用translate方法,都是針對(duì)當(dāng)前的坐標(biāo)系統(tǒng)原點(diǎn)進(jìn)行調(diào)整的,并不是以屏幕左上角進(jìn)行調(diào)整的。
          例如:當(dāng)前坐標(biāo)為(0,0),如果調(diào)用了translate(2,3)則當(dāng)前原點(diǎn)坐標(biāo)為原來屏幕的(2,3)坐標(biāo),如果再調(diào)用translate(4,5),則坐標(biāo)(4,5)是相對(duì)于坐標(biāo)(2,3)的,所以相對(duì)于最原始的坐標(biāo)系統(tǒng)中的坐標(biāo)(6,8)。
          一定要注意每次轉(zhuǎn)移原點(diǎn)都是根據(jù)當(dāng)前屏幕的原點(diǎn)坐標(biāo)為標(biāo)準(zhǔn)的。
          Grphics還提供了2個(gè)計(jì)算目前坐標(biāo)與原始狀態(tài)下原點(diǎn)坐標(biāo)的距離的方法。它們是: getTranslateX()和getTranslateY()。
          因?yàn)橐粋€(gè)坐標(biāo)系統(tǒng)可以進(jìn)行多次坐標(biāo)原點(diǎn)的轉(zhuǎn)移,如果希望原點(diǎn)恢復(fù)到原始狀態(tài),只要再轉(zhuǎn)移一個(gè)負(fù)變量就是原點(diǎn)往坐標(biāo)軸的負(fù)方向移動(dòng),可以使用如下代碼恢復(fù)原始狀態(tài)的圓點(diǎn)位置:
          g.translate(-getTranslateX(), -getTranslateY()) ;
          如果希望在已經(jīng)轉(zhuǎn)移了原點(diǎn)的環(huán)境中使用絕對(duì)位置(ax,ay),絕對(duì)位置就是指相對(duì)于原始狀態(tài)的原點(diǎn)位置:
          g.translate(ax – getTranslateX(), ay – getTranslateY());
          5.14 裁剪區(qū)
          在處理圖像時(shí),經(jīng)常會(huì)碰到圖片比較大,而屏幕只能顯示圖像一部分的情況。因此需要確定圖像中哪些部分位于顯示區(qū)域內(nèi),而哪些內(nèi)容落在顯示區(qū)域之外,以便只顯示落在顯示區(qū)域內(nèi)的那部分圖像。這個(gè)選擇的過程成為裁剪。
          裁剪區(qū)的作用:只有在裁剪區(qū)域內(nèi)的繪圖過程才會(huì)真正有效,在區(qū)域外的無效,即使在區(qū)域外之行了繪圖方法也是不會(huì)顯示的。
          Graphics類提供了簡(jiǎn)單的裁剪方法,原形如下:
          public void setClip(int x, int y, int width, int height)
          setClip可以設(shè)置需要裁剪的開始坐標(biāo)(x,y),然后指定矩形的裁剪區(qū)域的寬和高。當(dāng)屏幕重繪的時(shí)候,可以保證屏幕的其它部分的內(nèi)容不必重繪,僅僅重繪需要更新的部分內(nèi)容。一般使用了裁剪方法以后,應(yīng)該恢復(fù)到原來的裁減區(qū)域。
          例:
          int oldClipX = g.getClipX();
          int oldClipY = g.getClipY();
          int oldClipWidth = g.getClipWidth();
          int oldClipHeight = g.getClipHeight();
          //設(shè)置裁減區(qū)域
          g.setClip( 50, 50, 100, 100);
          //恢復(fù)原來的裁減區(qū)域
          g.setClip(oldClipX, oldClipY, oldClipWidth, oldClipHeight);
          5.15 重繪機(jī)制
          當(dāng)需要重繪屏幕的時(shí)候,可以調(diào)用Canvas類的repaint()方法,然后程序會(huì)自動(dòng)調(diào)用paint()方法完成重繪,如果僅僅需要屏幕的一部分更新,可以使用repaint方法的一個(gè)重載方法,指定需要更新區(qū)域的坐標(biāo)以及寬度和高度,請(qǐng)求部分屏幕重繪, 例如:
          repaint(10, 10, 50, 50);
          重繪起始坐標(biāo)為(10, 10),寬度為50, 高度為50的屏幕區(qū)域。
          5.16 雙緩存技術(shù)
          雙緩存技術(shù)是計(jì)算機(jī)動(dòng)畫的一項(xiàng)傳統(tǒng)技術(shù)。
          屏幕閃爍的主要原因在于:一幅畫面正在顯示的時(shí)候,程序在改變它,然后在一幅圖片還沒有完全顯示完畢又請(qǐng)求重新繪制,于是表現(xiàn)為畫面閃爍。
          解決閃爍的辦法:在內(nèi)存中操作需要處理的圖片,程序?qū)?nèi)存中的圖片更新、修改、完成后再顯示它。這樣顯示出來的圖片永遠(yuǎn)是完全畫好的圖像,程序修改的將不是正在被顯示
          的圖像。
          5.17 動(dòng)畫制作
          基本的動(dòng)畫,是將顯示在屏幕上的角色等的動(dòng)作與描繪的位置作連續(xù)的變化,產(chǎn)生動(dòng)態(tài)的效果。


          <轉(zhuǎn)載:http://blog.csdn.net/allan_sun/archive/2006/08/09/1043157.aspx >

          posted on 2008-09-01 19:43 騎豬闖天下 閱讀(1300) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 木兰县| 土默特左旗| 河北省| 正定县| 疏附县| 文化| 郓城县| 依安县| 凌云县| 乌拉特前旗| 喜德县| 安顺市| 昭苏县| 曲沃县| 昆山市| 和顺县| 静乐县| 汾阳市| 读书| 雅安市| 衢州市| 南开区| 江口县| 闵行区| 沾益县| 东至县| 榕江县| 宜春市| 措勤县| 德清县| 名山县| 瓦房店市| 金阳县| 山阴县| 溆浦县| 仁怀市| 长顺县| 雷山县| 聂荣县| 儋州市| 河源市|