<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    騎豬闖天下

    J2ME隨筆,記錄成長的腳步

    統計

    留言簿(3)

    閱讀排行榜

    評論排行榜

    [J2ME] MIDP低級界面開發

    MIDP低級界面開發
    <轉載>

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

    }
    }
    paint方法傳入了Grpahics類型的參數g,具體的繪畫將由Graphics的g實現。可以看出Canvas類和Graphics類的關系是畫布與畫筆的關系。
    5.1.2 低級API與低級事件
    Canvas可以處理低級事件,但并非處理所有的系統事件。設備支持哪些系統事件,必須由硬件的支持程度來判斷。Canvas提供一些方法判斷硬件支持程度。
    功能
    檢測方法
    低級事件/回調函數
    鍵盤事件
    支持
    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)
    機器一定會支持的鍵盤事件有keyPressed()、keyReleased(),屏幕事件showNotify()、hideNotidy(),以及重繪事件paint()。
    注意:除了showNotidy()之外,其它回調函數只有在此Canvas是目前屏幕上的畫面時才會被調用。
    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)
    {
    }
    }
    任何時候都可以自行調用repaint()產生重繪事件。repaint()有兩個同名方法,其中一個需要四個參數,用來指定重畫區域的X、Y坐標,寬度與高度;另外一個無參數,代表重繪整個屏幕。調用repaint()之后會立刻返回,繼續下面工作,調用paint()回調函數的工作則由一個專門處理UI的線程來完成。若希望等到paint()完成后再返回,可以在repaint()之后立刻調用serviceRepaints()方法。
    注意:serviceRepaints()用來強制隊列中的重繪事件快點做完,如果隊列中沒有重繪事件,則serviceRepaints()什么也不會做,因此在調用serviceRepaints()之前,通常伴隨一個repaint()。
    5.1.4 坐標系統
    在使用繪圖函式前,請先注意MIDP 中X 坐標與Y 坐標的定義方式。傳統的笛卡爾坐標其原點在左下角,向右X 坐標值遞增,向上Y坐標值遞增。
    但是我們在手機的屏幕上做圖時,變成向右X 坐標值遞增,向下Y 坐標值遞增。
    5.1.5 像素(Pixel)
    我們在所有圖形相關函數之中所使用的坐標所代表的并非像素本身,而是指像素和像素之間的空格所構成的坐標,如下圖所示:
    像素與像素之間所構成的坐標
    所以一般我們所說的坐標(3,1)并非指位于(3,1)這個像素,而是指像素(2,0)、(2,1)、(3,0)、(3,1)所包圍的這個部分。也正因為坐標指的并非圖素本身,所以會造成在繪制圖型和填滿區塊時有所差異,這兩者的不同我們將在以后說明。
    5.1.6 Graphics入門
    paint(Graphics g)方法會傳入一個Graphics對象作為參數,可以把該對象當作是一個抽象的畫筆,調用Graphics的方法,就可以在這個畫布上繪圖。
    編寫我們自己的Canvas時,要做的第一件事就是把畫面清空,然后才開始繪圖,避免畫面上殘留前一個畫面所遺留下的東西。
    //清屏
    public void paint(Graphics g)
    {
    g.setColor(255, 0, 255);
    g.fillRect(0, 0, getWidth(), getHeight());
    … …
    }
    上述范例中,我們使用Graphics的setColor()來設置畫筆顏色:
    setColor(int r, int g, int b)注意,rgb的值限定在0~255之間。
    或setColor(int rgb) 直接傳入0x00RRGGBB這樣的整數。
    設定好顏色后,可以使用getRedComponent()、getGreenComponent()、getBlueComponent()分別取得R、G、B的顏色設定?;蛘咧苯邮褂胓etColor()取得0x00RRGGBB這樣的整數,也就是說,最后第0~7 位代表藍色、8~15 代表藍色,16~23 代表紅色。
    getDisplayColor()較特殊,返回機器上繪圖時真正使用的顏色。有些機器不具有顯示所有顏色的能力。屏幕的灰度數可以用getGrayScale()取得,也可以用setGrayScale(),灰度數取值在0~255之間。使用這個函式的時候請特別注意,如果您已經使用了相對應的setGrayScale()來設定灰階色階數,那么getGrayScale()函式只是單純地傳回設定值。但是如果您沒有設定灰階色階數,那么呼叫getGrayScale()函式的時候,會導致系統利用目前作用色的R、G、B 值來做大量運算,并求得最接近的灰階色階數。
    5.1.7 繪制直線
    我們可以使用Graphics 類別的drawLine()函式繪制線段。DrawLine 的四個參數分別是起點X 坐標,起點Y 坐標、終點X 坐標、終點Y 坐標。舉例來說,如果我們函式呼叫為:g.drawLine(1,1,1,6)
    則實際繪制的線段如下圖所示:
    實際繪制出來的線段的位置
    我們可以發現坐標右邊的相素都會被填滿。
    如果我們函式調用為:
    g.drawLine(1,1,6,1)
    則實際繪制的線段如下圖所示:
    實際繪制出來的線段的位置
    我們可以發現坐標下方的像素都會被填滿。
    當我們繪圖形時,有所謂的筆觸(stroke style)。Graphics提供兩種筆觸,分別是Graphics.SOLID和Graphics.DOTTED:
    g.setStrokeStyle(Graphics.DOTTED);
    相應的取得目前所用筆觸:g.getStrockStyle()
    5.1.8 畫弧形
    我們可以使用Graphics 類的drawArc()方法繪制弧形。drawArc 共有6 個參數,它們分別是:前四個決定弧形所在的矩形范圍,第五個決定起始角度,第六個參數則決定弧形本身所涵蓋的角度。
    如果我們方法調用為:
    g.drawArc(20,10,width,height,45,90);
    則實際繪制的弧形如下圖所示:
    實際繪制出來的弧形
    填充弧形
    我們可以使用Graphics 類別的fillArc()函式填充弧形。fillArc 共有6 個參數,它們分別是:前四個決定弧形所在的矩形范圍,第五個決定起始角度,第六個參數則決定弧形本身所涵蓋的角度。
    如果我們方法調用為:
    g.fillArc(20,15,width,height,45,90);
    則實際繪制的填充弧形如下圖所示:
    實際繪制出來的填充弧形
    5.1.9 矩形
    畫矩形:我們可以使用Graphics 類別的drawRect()函式繪制矩形。drawRect 有4 個參數,分別是起點X 坐標、起點Y 坐標、寬度、長度。
    如果我們函數調用為:
    g.drawRect(1,1,6,8)
    則實際繪制的矩形如下圖所示:
    實際繪制出來的矩形
    我們可以發現所構成的矩形路徑,其右邊和下方的像素都被填滿了。
    畫圓角矩形:我們可以使用Graphics 類別的drawRoundRect()函式繪制圓角矩形。其實drawRoundRect()和drawRect()函式的前四個參數意義相同,唯一的差距只有在最后兩個參數,它們分別是圓角所在矩形的寬度,以及圓角所在矩形的高度。
    如果我們方法調用為:
    g.drawRoundRect(1,1,6,8,arcWidth,arcHeight)
    則實際繪制的圓角矩形,在矩形的部分和使用drawRect()的結果相同,差別只有在四個直角的樣子不再是直角,而變成圓角。
    如下圖所示:
    實際繪制出來的圓角矩形
    填充矩形:我們可以使用Graphics 類別的fillRect()函式填充矩形。fillRect 有4 個參數,分別是起點X 坐標、起點Y 坐標、寬度、長度。
    如果我們方法調用為:
    g.fillRect(1,1,6,8)
    則實際繪制的矩形如下圖所示:
    實際繪制出來的填充矩形
    我們可以發現只有包含在矩形路經之內的圖素才會被填滿,這和drawRect()函式的結果有所不同(上下都差一個圖素的大?。?。
    填充圓角矩形:我們可以使用Graphics 類別的fillRoundRect()函式填充圓角矩形。其實fillRoundRect()和fillRect()函式的前四個參數意義相同,唯一的差距只有在最后兩個參數,它們分別是圓角所在舉行的寬度,以及圓角所在矩形的高度。
    如果我們方法調用為:
    g.fillRoundRect(1,1,6,8,arcWidth,arcHeight)
    則實際繪制的圓角矩形,在矩形的部分和使用fillRect()的結果相同,差別只有在四個角的樣子不再是直角,而變成圓角,如下圖所示:
    實際繪制出來的填充圓角矩形
    5.1.10 三角形
    繪制三角形,使用三個頂點,分別畫線即可,因此MIDP只提供填充三角形的功能:
    g.fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) ;
    練習:嘗試自己繪制三角形,并填充它
    5.2 Canvas與屏幕事件處理
    Canvas本身具有兩種狀態:
    ?? 普通狀態
    ?? 全屏狀態
    可以使用setFullScreenMode()設定Canvas狀態。
    示例:
    /*
    * 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("應用程序區域被覆蓋");
    }
    public void showNotify()
    {
    System.out.println("屏幕顯示");
    }
    }
    幾個重要觀念:
    1) 對于Canvas低級API,標題、Ticker、Command區域依然有用;
    2) 全屏模式下,標題、Ticker、Command區域無法顯示,但原本對應到按鈕的地方仍然存在,只是看不見;
    3) 調用setFullScreenMode()時,不管設置成全屏模式還是正常模式,sizeChanged()都會被調用,并傳入當前屏幕的高度和寬度。
    4) 當屏幕被系統畫面(如菜單、來電顯示等)覆蓋時,會自動調用hideNotify(),告知應用程序目前的畫面被覆蓋了。當這些系統畫面消失時,系統將調用showNotify()告知應用程序。Canvas第一次顯示在屏幕上時,系統也會調用showNotify()。Canvas移出屏幕(有其它displayable被顯示,調用setCurrent())時,hideNotify()會被調用。
    5) 當我們使用Graphics繪圖時,零坐標會隨著模式的改變而改變,所以零點不是絕對的,而是相對于應用程序區而言。因為屏幕的大小會改變,所以在清除屏幕(fillRect())的時候使用canvas.getHeight()和canvas.getWidth()取得屏幕大小,而不是固定值。
    5.3 鍵盤事件處理
    當Canvas子類正作用于屏幕時,按下任何按鈕,就會引發keyPressed()方法,并傳入一個代表該按鈕的整數,而放開按鈕之后,會引發keyReleased()方法,并傳入一個代表該按鈕的整數值。系統如果傳入小于0的值,則為不合法keycode。
    某些機器上還可以支持連發事件(即一直按著按鈕持續一段時間),該事件會引發keyRepeated()
    方法,并傳入一個代表該按鈕的數值,但該事件并非所有機器都支持,所以我們有必要使用Canvas類中的hasRepeatEvents()方法詢問系統是否支持連發事件。
    示例:
    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;
    }
    結果是一樣的,這是因為回調函數都是在同一個UI的線程中執行,因此理論上,repaint()只是產生一個重繪事件就立刻返回,系統必須等到keyPressed()/keyReleased()執行完畢之后才能繼續調用paint()重繪屏幕。
    5.4 鍵盤響應
    Canvas里定義了幾個常數
    KEY_NUM0、KEY_NUM1 ~ KEYNUM9
    KEY_STAR、KEY_POUND共12個
    可以利用這幾個常數判定事件處理方法所傳進來的keyCode,得知那個按鈕被按下。
    為了程序可以跨平臺執行,建議使用這些標準的定義鍵。
    玩游戲的時候通常2、4、6、8分別代表上、下、左、右,星字鍵代表發射,井字代表跳躍。但并非所有機器上都會有相同的鍵盤排列方式,也并非一定按照此方式設定。為了設計Game的時候方便,MIDP規范中,Canvas中定義了幾個與Game鍵盤代碼相關的常數,分別是UP、DOWN、LEFT、RIGHT、FIRE、GAME_A、GAME_B、GAME_C、GAME_D。這些定義與之前的定義有所重復,但是因為有了一些抽象性,在移植的時候也就方便多了。
    常用方法:
    1. getGameAction(int keyCode);
    該方法傳入keyCode,會返回所代表的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坐標
    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("支持連發");
    }
    else
    {
    System.out.println("不支持連發");
    }
    }
    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 十字中心點x坐標
    *@parameter y 十字中心點y坐標
    */
    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 觸控屏幕的事件處理
    當Canvas是當前畫面,數控筆在屏幕上點擊,就會引發pointerPressed()方法,并傳入其
    當前處于屏幕的x與y坐標,放開出控筆后,會引發pointerReleased()方法,并傳入當前屏幕位置的x與y坐標。某些機器上可以產生拖拽事件(即一直按住屏幕拖拽),該事件會引發pointerDragged()方法,并傳入當時處于屏幕位置的x與y坐標。
    并非所有設備都支持觸控事件,我們可以使用Canva類中的hasPointerEvents()方法獲得系統是否支持觸控筆事件的信息。
    并非所有設備都支持拖拽事件, 我們可以使用Canvas類中的hasPointerMotionEvents()方法判斷系統是否支持觸控筆拖拽事件。
    示例:
    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("支持數控筆");
    }
    else
    {
    System.out.println("不支持數控筆");
    }
    if (hasPointerMotionEvents())
    {
    System.out.println("支持數控筆拖拽");
    }
    else
    {
    System.out.println("不支持數控筆事件");
    }
    }
    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低級事件和高級事件同時出現
    當高級事件和低級事件同時出現時,系統會自動判斷。如果按鈕屬于系統的,就會交給高級
    事件處理方法來處理,如果不是,才會由低級事件來做。
    5.7 繪制字符串
    Graphics類提供了繪制字符串的方法,原形如下:
    public void drawString(String str, int x, int y, int anchor)
    參數:
    x、y:相對于屏幕原點的x、y坐標
    anchor:定位點
    注意:即使x、y相同,anchor不同,具體位置還是不同的(后面詳述)
    另外,需要了解的是字符串本身顯示要占用屏幕上的一個矩形的空間。anchor的作用就是設置字符串所處矩形區域位于屏幕坐標的哪個位置。
    5.8 Image類
    Image 類是我們在處理圖形時常常會用的類別,如果根據它的產生方式, 我們可以細分成可修改( mutable ) 和不可修改(immutable)兩種。要辨別一個Image 對象是可修改還是不可修改,您可以呼叫Image 對象的isMutable()方法得知。我們可以使用getWidth()與getHeight()取得該Image 對象的寬度與高度。
    要產生不可修改的Image 對象,主要方法有三種:
    1. 從影像文件讀取:根據MIDP 的規定,所實現MIDP 的廠商至少要提供讀取PNG(Portable Network Graphics)影像文件的功能。有些廠商會支持其它如GIF 影像文件的功能,但是不建議使用,因為很可能讓您的MIDlet 無法跨平臺。
    2. 由Byte 數組建立:我們可以經由從網絡或resourcebundle 里的文字文件讀入一連串的byte 數組,然后用此數組產生不可修改的Image 對象。
    3. 從其它Image 對象(可修改或不可修改皆可)來產生。
    范例:
    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對象。第二種建立不可修改Image 對象的方法是利用其方法:
    createImage(byte[] imagedata, int imageOffset, int imageLength)
    第三種方法則是利用方法: createImage(Image source)就可以從現有可修改或不可修改的Image 對象取得一份不可修改的拷貝。
    可修改的Image 對象
    建立一個可修改的Image 對象非常簡單,只要呼叫Image 對象的靜態方法:
    createImage(int width,int height)
    即可建立一個可修改的Image 對象。事實上,可修改的Image和Double Buffering 的技術息息相關,可修改的Image 對象實際上就是一個供人在背景繪圖的off screen。因此在建立可修改的Image 對象前,您應該先呼叫Canvas 類別的isDoubleBuffered()函式來確定您的機器是否支持Double Buffering 技術,如果該函式傳回false,那么您就不該試圖建立可修改的Image 對象。
    一旦您取得了可修改的Image 對象,我們就可以呼叫Image 類別的getGraphics()取得代表off screen 的Graphics 對象,在off screen 繪圖并不會影響到正常的畫面(on screen)。
    最后,我們可以利用on screen ( 由paint 函式傳入的Graphics 物件) 的drawImage()函
    式繪出可修改Image 對象的內容。
    示例:
    Image source;
    source = Image.createImage(“... ”) ;
    //建立可修改Image對象
    Image copy = Image.createImage(source.getWidth(), source.getHeight());
    Graphics g = copy.getGraphics();//獲取copy的Graphics對象
    g.drawImage(source, 0, 0, Graphics.TOP|Graphics.LEFT);
    5.9 繪制圖片、文字以及定位點的作用
    繪制圖片、字符串或是單一文字都會用到定位點(Anchor)的概念。定位點代表的意義是,繪制圖形跟文字時,所指定的X、Y坐標指的是何種意義。
    定位點定義共有七種:
    Graphics.TOP
    Graphics.BOTTOM
    Graphics.LEFT
    Graphics.RIGHT
    Graphics.HCENTER
    Graphics.VCENTER
    Graphics.BASELINE它們對文字和圖形的控制都具有意義。
    注意:圖中標有VCENTER參數,主要是因為MIDP1.0提供了該參數。但MIDP2.0中已經不允許使用該參數,主要是因為這個參數不好計算而且實際使用的意義也不大,如果在MIDP2.0中調用該參數,將會拋出異常。
    這幾種定義可以有意義地組合。舉例來說,如果我們選擇使用TOP 加上LEFT,則繪制文字時,我們會使用函式:
    g.drawString(“文字xyzh”, 0, 0, Graphics.TOP|Graphics|LEFT) ;
    繪制圖形時,我們會使用函式:
    g.drawImage(image, 0, 0, g.TOP|g.LEFT);
    這時畫面上的結果為:
    不管是drawString()或是drawImage()其第二與第三個參數所指定的坐標指的是定位點所參考的起始地址。以上述結果為例,我們指定(0,0)為定位點參考起始位置,然后又選擇的TOP 與LEFT 作為定位點,代表(0,0)這個坐標為字符串或圖形繪制在屏幕上時左上角的點。
    再舉個例子,如果我們選擇使用BOTTOM 加上HCENTER,則繪制文字時,我們會使用函式:
    g.drawString(“文字xyzh”, 0, 0,Graphics.BOTTOM|Graphics.HCENTER) ;
    繪制圖形時,我們會使用函式:
    g.drawImage(image, 0, 0, g.BOTTOM |g.HCENTER);
    這時畫面上的結果為:
    由此我們可以歸納出,如果您使用的方法為:
    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) ;
    兩者的意義是相同。
    思考練習:居中字符串。
    5.10 字體
    當我們需要在屏幕上匯出文字時,我們常常需要一些有關字體的相關數據,這時就需要Font 類別的輔助。通常,我們會使用Font.getDefaultFont()取得代表系統預設所使用字型的Font 對象?;蛘咭部梢宰孕惺褂肍ont.getFont()來取得代表特定字型的對象。
    getFont() 共有三個參數,
    Font f = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE) ;
    他們分別是外觀( face )、樣式(style)、以及尺寸(size)。他們分別有各種選項:
    外觀: Graphics.FACE_MONOSPACE 定寬字體
    Graphics.FACE_PROPORTIONAL 比例字體
    Graphics.FACE_SYSTEM 系統字體
    樣式 : Graphics.STYLE_BOLD 加粗字體
    Graphics.STYLE_ITALIC 傾斜字體
    raphics.STYLE_PLAIN 常規字體
    Graphics.STYLE_UNDERLINED 下劃線
    尺寸 : Graphics.SIZE_LARGE 大號字體
    Graphics.SIZE_MEDIUM 中號字體
    Graphics.SIZE_SMALL 小號字體
    需要注意的是,底層不一定全部支持。getFont()還有另一個只有一個參數的重載方法,只有PONT_INPUT_TEXT和DON’T_STATIC_TEXT兩種可以選擇,這個方法用來取得系統用來顯示輸入用的字體以及一般常用的字體。
    但是最實際程序之中,我們最常使用的是Graphics 類別的getFont()方法取得當時顯示在畫面上的屏幕所使用的字型。同理,我們也可以使用Graphics 類別的setFont()方法設定所使用的字體:
    g.setFont(f);
    當我們取得代表字型的對象之后,我們就可以利用getFace()函式取得其外觀、getStyle()取得其樣式、getSize()取得其尺寸。而樣式的部分我們也可以改用isBold()、isItalic()、isPlain()、isUnderlined()函式來取得相關信息,這是因為樣式是可以合成的,一個字型的樣式很可能同時是黑體與斜體的組合。
    Font 類別除了可以幫我們取得字型的外觀、樣式與尺寸之外,還能幫助我們取得該字型在屏幕上的相關屬性,請參考下圖:
    Font 的屬性
    其中:
    charWidth()取得屏幕上某個字符使用該字體顯示時的寬度;
    charsWidth()計算一串字符顯示時的寬度;
    stringWidth()取得屏幕上某個字符串使用該字體顯示時的寬度;
    substringWidth()則是某個字符串的子字符串顯示時的寬度;
    getBashLinePosition()可以讓我們知道從字體最頂點到baseline的距離;
    getHeight()可以取得最頂點到最低點的距離。
    5.11 顏色
    Grpahics類提供了3種顏色設置方法:
    public void setColor(int r, int g, int b)
    public void setColor(int RGB)
    public void setGrayScale(int value)
    其中,setGrayScale作用是繪制灰階,只是0到255共256種;setColor方法的作用是設置RGB顏色模式以在屏幕上顯示彩色的顏色。
    RGB模型:對于彩色圖像中的每個RGB(Red、Green、Blue)分量,為每個像素指定一個0(黑色)到255(白色)之間的強度值。當三個分量相等時,結果是中性灰色;當所有分量的值均為255時,結果為白色;當這些值都為0時,結果為純黑色。
    setColor(int RGB)的參數格式是0x00RRGGBB,高2位0x00被忽略,僅僅計算RRGGBB,高2位主要用來計算色彩的Aplpha混合的。
    5.12 調整坐標原點
    Graphics類提供了調整屏幕原點位置的方法法:
    public void translate(int x, int y)
    改變原點的坐標在手機屏幕上的位置,并把相對于原來坐標系統原點的坐標(x,y)作為新的原點。需要注意的是,每次調用translate方法,都是針對當前的坐標系統原點進行調整的,并不是以屏幕左上角進行調整的。
    例如:當前坐標為(0,0),如果調用了translate(2,3)則當前原點坐標為原來屏幕的(2,3)坐標,如果再調用translate(4,5),則坐標(4,5)是相對于坐標(2,3)的,所以相對于最原始的坐標系統中的坐標(6,8)。
    一定要注意每次轉移原點都是根據當前屏幕的原點坐標為標準的。
    Grphics還提供了2個計算目前坐標與原始狀態下原點坐標的距離的方法。它們是: getTranslateX()和getTranslateY()。
    因為一個坐標系統可以進行多次坐標原點的轉移,如果希望原點恢復到原始狀態,只要再轉移一個負變量就是原點往坐標軸的負方向移動,可以使用如下代碼恢復原始狀態的圓點位置:
    g.translate(-getTranslateX(), -getTranslateY()) ;
    如果希望在已經轉移了原點的環境中使用絕對位置(ax,ay),絕對位置就是指相對于原始狀態的原點位置:
    g.translate(ax – getTranslateX(), ay – getTranslateY());
    5.14 裁剪區
    在處理圖像時,經常會碰到圖片比較大,而屏幕只能顯示圖像一部分的情況。因此需要確定圖像中哪些部分位于顯示區域內,而哪些內容落在顯示區域之外,以便只顯示落在顯示區域內的那部分圖像。這個選擇的過程成為裁剪。
    裁剪區的作用:只有在裁剪區域內的繪圖過程才會真正有效,在區域外的無效,即使在區域外之行了繪圖方法也是不會顯示的。
    Graphics類提供了簡單的裁剪方法,原形如下:
    public void setClip(int x, int y, int width, int height)
    setClip可以設置需要裁剪的開始坐標(x,y),然后指定矩形的裁剪區域的寬和高。當屏幕重繪的時候,可以保證屏幕的其它部分的內容不必重繪,僅僅重繪需要更新的部分內容。一般使用了裁剪方法以后,應該恢復到原來的裁減區域。
    例:
    int oldClipX = g.getClipX();
    int oldClipY = g.getClipY();
    int oldClipWidth = g.getClipWidth();
    int oldClipHeight = g.getClipHeight();
    //設置裁減區域
    g.setClip( 50, 50, 100, 100);
    //恢復原來的裁減區域
    g.setClip(oldClipX, oldClipY, oldClipWidth, oldClipHeight);
    5.15 重繪機制
    當需要重繪屏幕的時候,可以調用Canvas類的repaint()方法,然后程序會自動調用paint()方法完成重繪,如果僅僅需要屏幕的一部分更新,可以使用repaint方法的一個重載方法,指定需要更新區域的坐標以及寬度和高度,請求部分屏幕重繪, 例如:
    repaint(10, 10, 50, 50);
    重繪起始坐標為(10, 10),寬度為50, 高度為50的屏幕區域。
    5.16 雙緩存技術
    雙緩存技術是計算機動畫的一項傳統技術。
    屏幕閃爍的主要原因在于:一幅畫面正在顯示的時候,程序在改變它,然后在一幅圖片還沒有完全顯示完畢又請求重新繪制,于是表現為畫面閃爍。
    解決閃爍的辦法:在內存中操作需要處理的圖片,程序對內存中的圖片更新、修改、完成后再顯示它。這樣顯示出來的圖片永遠是完全畫好的圖像,程序修改的將不是正在被顯示
    的圖像。
    5.17 動畫制作
    基本的動畫,是將顯示在屏幕上的角色等的動作與描繪的位置作連續的變化,產生動態的效果。


    <轉載:http://blog.csdn.net/allan_sun/archive/2006/08/09/1043157.aspx >

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


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 全部免费毛片在线| 白白色免费在线视频| a毛片免费播放全部完整| 免费a级毛片视频| 免费无码一区二区| 国产亚洲老熟女视频| 国产免费播放一区二区| 亚洲男人天堂2020| 好吊色永久免费视频大全| 亚洲热妇无码AV在线播放| 国产成人1024精品免费| 在线观看亚洲成人| 青青草原1769久久免费播放| 亚洲AV永久青草无码精品| 最近最新高清免费中文字幕| 亚洲图片激情小说| 久久精品女人天堂AV免费观看| 亚洲精品国产摄像头| 亚洲 另类 无码 在线| 国产免费久久久久久无码| 亚洲免费在线播放| 国产成人精品免费视频网页大全 | 国产国产成年年人免费看片| 亚洲欧洲AV无码专区| 亚洲av再在线观看| a级毛片免费高清毛片视频| 亚洲精品视频观看| 日韩午夜免费视频| 国产特黄特色的大片观看免费视频 | CAOPORM国产精品视频免费| 亚洲精品V欧洲精品V日韩精品 | 亚洲精品中文字幕麻豆| 在线观看免费成人| 久久www免费人成看国产片| 亚洲黄色在线视频| 四虎永久成人免费| 久久免费视频精品| 风间由美在线亚洲一区| 亚洲三级电影网站| 国产yw855.c免费视频| 日韩内射激情视频在线播放免费|