امروز: ۱۱/۶/۱۳۹۳
بازدیدها: ۴۵۲۷۷۷
کاربران آنلاین: ۲۶
RSS

 

:: متن کامل مطلب
₪ آموزش J2ME قسمت سوم    ◊ باهنر   ( تاریخ: ۱۴/۱۱/۱۳۸۹ بازدید: 1867 )
Screenهاي سفارشي با Canvasها
اگر screenهاي آماده به نظر شما به اندازه کافي انعطاف ندارد و نيازها را برآورده نمي کند مي توان با استفاده از Canvas، screenهاي دلخواه با امکانات ترسيمات فراوان استفاده کرد. کلاس Canvas کاملا شبيه به ديگر screenها (همانند فرم، ليست و...) و از نسل Displayable است؛ يعني مي تواند شامل فرمان ها، عنوان و Ticker باشد. Canvas به خوبي خود را با هرگونه صفحه نمايش سازگار مي کند.
Canvas يک متد انتزاعي است بنا بر اين نمي توان به طور مستقل يک نمونه از آن را ايجاد کرد بلکه بايد يک کلاس از آن مشتق کرده و با استفاده از متد انتزاعي paint() آن، طراحي ها و ترسيمات مورد نظر خويش را انجام دهيم. اين متد يک پارامتر از نوع Graphics مي گيرد که تمام ترسيمات با آن انجام مي شود. براي نمايش Canvas بر روي صفحه نمايش نيز نياز به يک MIDlet داريم.
چند نکته سودمند در مورد به کارگيري Canvasها:
* با متدهاي getWidth() و getHeight() طول و عرض صفحه نمايش را به دست مي آوريم.
* معمولا دستگاه هاي همراه قسمتي از صفحه نمايش را براي نشان دادن وضعيت باطري، آنتن و ديگر اطلاعات در اختيار برنامه ها نمي گذارد، اما با استفاده از متد setFullScreenMode(true) مي توان از تمام صفحه نمايش بهره گرفت.
* هنگامي که اندازه Canvas تغيير نمايد، برنامه متد sizeChanged() از اين کلاس را فراخواني مي کند.
* با استفاده از متد repaint() مي توان مجددا عمل ترسيم (paint()) را انجام داد.
* با استفاده از متد isColor() مي توان فهميد که آيا صفحه نمايش دستگاه رنگي است يا خير (سياه و سفيد است).
* با استفاده از متد numAlphLevels() مي توان به دست آورد که آيا صفحه نمايش دستگاه از کانال هاي آلفا و شفافيت پشتيباني مي کند ياخير؛ مقدار برگشتي از اين متد يک عدد صحيح است که مقدار 1 نشاندهنده شفافيت کامل، عدد 2 نشاندهنده عدم پشتيباني و ساير مقادير ميزان ترکيب آلفا را نشان مي دهد.
* براي به دست آوردن الگوي رنگ دستگاه از متد getColor(c) شيء Display استفاده مي کنيم؛ پارامتر اين متد مي تواند يک از ثابت هاي COLOR_BACKGROUND (رنگ زمينه)، COLOR_FOREGROUND (رنگ ترسيم)، COLOR_HIGHLIGHTED_BACKGROUND (رنگ زمينه فوکوس در اشکال تو پر)، COLOR_HIGHLIGHTED_FOREGROUND (رنگ فوکوس در متون فوکوس شده)، COLOR_BORDER (رنگ کادر) و COLOR_HIGHLIGHTED_BORDER (رنگ کادر در حالت فوکوس) باشد.
* براي تنظيم رنگ ترسيم ها از متد setColor(R, G, B) يا setColor(0x00RRGGBB) استفاده مي کنيم. (با استفاده از نرم افزارهايي مثل فتوشاپ مي توانيد رنگ دلخواه خود را انتخاب کنيد).
* براي ترسيم متون و اشکال از متدهاي draw و fill استفاده مي کنيم؛ به طور مثال drawString()، drawLine()، fillRect() و...
اکنون به اين مثال ساده توجه کنيد:
import javax.microedition.lcdui.*;
public class CanvasTest extends Canvas {
  private final Display display;
  public CanvasTest(Display d) {
    display=d;
  } 
  public void paint(Graphics g) {
    int w = getWidth();
    int h = getHeight();
    int bg = display.getColor(Display.COLOR_BACKGROUND);
    int fg = display.getColor(Display.COLOR_FOREGROUND);
    g.setColor(bg);
    g.fillRect(0, 0, w, h);
    g.setColor(fg);
    g.fillRect(w/4, h/4, w/2, h/2);
  }
}
در مورد متد fillRect() بعدا صحبت مي کنيم. حال نياز به يک MIDlet ساده براي نمايش اين Canvas داريم؛ يک MIDlet ايجاد کرده و در متد startApp() آن کد ذيل را بنويسيد:
Display d = Display.getDisplay(this);
Canvas c = new CanvasTest(d);
d.setCurrent(c);
شکل ذيل اجراي مثال را نشان مي دهد:

ترسيم خطوط و اشکال
مبدء دستگاه مختصات در گوشه سمت چپ بالا قرار دارد؛ محور x به طرف راست و محور y به سمت پايين امتداد مي يابد. مي توان با متد translate(x, y) از شيء Graphics مبدء محورها را انتقال داد؛ همچنين با استفاده از متدهاي getTranslateX() و getTranslateY() ميزان انتقال و مبدء محورها را به دست آورد.
شيء Graphics مجموعه اي از متدها را براي ترسيم انواع خطوط و اشکال فراهم کرده است که در جدول ذيل برخ از پرکاربردترين آن ها را مشاهده مي کنيد (پارامترها از نوع int هستند مگر در مواردي که تصريح شود از نوع ديگرند):
رسم خط از نقطه (x1,y1) تا نقطه (x2,y2) drawLine(int, y1, x2, y2)
رسم مستطيل توخالي از نقطه (x,y) با عرض و طول مشخص drawRect(x, y, width, height)
رسم مستطيل توخالي با گوشه هاي گرد از نقطه (x,y) با عرض و طول مشخص و اندازه کمان گرد شدن گوشه ها drawRoundRect(x, y, width, height, arcWidth, arcHeight)
رسم کمان از نقطه (x,y) با عرض و طول مشخص، زاويه شروع و زاويه کمان drawArc(x, y, width, height, startAngle, arcAngle)
رسم متن؛ پارامتر anchor يک از ثابت هاي (LEFT, HCENTER, RIGHT) براي چينش افقي و (TOP, BASELINE, BOTTOM) براي چينش عمودي است. براي ترکيب آن ها نيز از خط افقي استفاده مي کنيم: TOP | RIGHT drawString(String str, x, y, anchor)
رسم مستطيل توپر از نقطه (x,y) با عرض و طول مشخص fillRect(x, y, width, height)
رسم مستطيل توپر با گوشه هاي گرد از نقطه (x,y) با عرض و طول مشخص و اندازه کمان گرد شدن گوشه ها fillRoundRect(x, y, width, height, arcWidth, arcHeight)
رسم کمان توپر از نقطه (x,y) با عرض و طول مشخص، زاويه شروع و زاويه کمان fillArc(x, y, width, height, startAngle, arcAngle)
رسم مثلث توپر با استفاده از نقاط مشخص شده fillTriangle(x1, y1, x2, y2, x3, y3)
در قطعه کد ذيل چند شکل ابتدايي ترسيم شده است:
import javax.microedition.lcdui.*;
public class CanvasTest2 extends Canvas  {
  public CanvasTest2() {
  }
  public void paint(Graphics g) {
    int w = getWidth();
    int h = getHeight();
    g.setColor(255, 255, 255);//white
    g.fillRect(0, 0, w, h);
    int pad = w / 14; //distance from edge
    int cw = w / 2; //column width
    int ch = h / 3; //column height
    int sw = cw - pad * 2 - 1; //shape width
    int sh = ch - pad * 2 - 1; //shape height
    g.setColor(0, 0, 255); //blue
    g.drawLine(pad, ch - pad, cw - pad, pad);
    g.drawRect(cw + pad, pad, sw, sh);
    g.drawRoundRect(pad, ch + pad, sw, sh, pad, pad);
    g.drawArc(cw + pad, ch + pad, sw, sh, -20, 270);
    int x1 = pad, y1 = ch + ch + pad,
      x2 = cw - pad, y2 = ch + ch + ch / 2,
      x3 = cw / 2 - pad, y3 = ch + ch + ch - pad;
    g.drawLine(x1, y1, x2, y2);
    g.drawLine(x2, y2, x3, y3);
    g.drawLine(x3, y3, x1, y1);
    g.drawArc(cw + pad, ch + ch + pad, sh, sh, 0, 360);
  }
}
در اين مثال از متغيرهايي استفاده شده است تا اشکال بر اساس طول و عرض صفحه نمايش با هر دستگاهي سازگار باشد؛ شکل ذيل اجراي کد را نشان مي دهد:

شکل : ترسيم هاي گوناگون با Canvas
اگر بخواهيم اين اشکال را به صورت توپر با يک خط کادر در اطراف آن ترسيم کنيم، ابتدا شکل را با استفاده از متدهاي fill کشيده و سپس با رنگ ديگر با استفاده از متدهاي draw کادر را ترسيم مي کنيم:
g.setColor(255,0,0) //red
g.fillRoundRect(pad + 1, ch + pad + 1, sw, sh, pad, pad);
g.setColor(0,0,0); //black
g.drawRoundRect(pad, ch + pad, sw, sh, pad, pad);
همچنين اگر بخواهيم از کادرهاي نقطه چين استفاده کنيم، مي توانيم متد draw را همراه با متد setStrokeStyle(DOTTED) استفاده کرد؛ آرگومان ديگر اين متد SOLID است.
ترسيم متون
ترسيم متون نيز به آساني توسط متد drawString() انجام مي شود:
g.drawString("Text", x, y, anchor);
پارامتر anchor براي چينش متن کاربرد دارد و مي تواند يکي از مقادير RIGHT، LEFT و HCENTER براي چينش افقي و TOP، BOTTOM و BASELINE براي چينش عمودي باشد؛ براي ترکيب آن ها با همديگر از خط افقي استفاده مي کنيم:
g.drawString("Text", x, y, Graphics.TOP | Graphics.HCENTER);
نکته ديگر در مورد ترسيم متون، تنظيمات قلم (Font) است؛ معمولا سه نوع فونت وجود دارد:
* FACE_SYSTEM: فونت پيش فرض دستگاه
* FACE_MONOSPACE: کاراکترهاي با پهناي برابر
* FACE_PROPORTIONAL : کاراکترهاي با پهناي متغير
در مورد شکل فونت نيز مقادير ذيل در دسترس است:
* STYLE_PLAIN: معمولي
* STYLE_BOLD : ضخيم
* STYLE_ITALIC: مورب
* STYLE_UNDERLINED : زيرخط دارد
در مورد اندازه قلم مي توان از خصوصيات ذيل بهره برد:
* SIZE_SMALL : کوچک
* SIZE_MEDIUM : متوسط
* SIZE_LARGE : بزرگ
خصوصيات غير هم دسته را مي توان ترکيب کرد.
يک مثال ساده را در قطعه کد ذيل مشاهده مي کنيد:
Font f = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_LARGE);
g.setFont(f);
g.drawString(...........
ترسيم تصاوير
ترسيم تصاوير نيز همانند ترسيم متون است؛ تنها تفاوت در چينش افقي است که به جاي BASELINE از VCENTER استفاده مي کنيم؛ به طور مثال:
int w = getWidth();
int h = getHeight();
Image img = null;
try{
  img=Image.createImage("/photo.png");
}
catch(IOException e){}
g.drawImage(img, w/2, h/2, Graphics.HCENTER | Graphics.VCENTER);
نکته ديگر در مورد تصاوير اين است که گاهي مي خواهيم بر روي تصويري ترسيمات انجام شود؛ در حالت عادي چنين کاري انجام پذير نيست؛ بايد مراحل ذيل را انجام دهيم:
* با استفاده از نگارش ديگر متد createImage() (که عرض و طول را به عنوان پارامتر مي گيرد) يک تصوير تغيير پذير ايجاد کنيم.
* شيء Graphics را به کمک getGraphics() از تصوير بازيابي کنيم.
* به کمک شيء Graphics برروي تصوير ترسيمات مورد نظر خويش را انجام دهيم.
قطعه کد ذيل اين مراحل را توضيح مي دهد:
import javax.microedition.lcdui.*;
public class CanvasTest3 extends Canvas {
  private Image imgTitle;
  public CanvasTest3() {
  }
  public void paint(Graphics g) {
    int w = getWidth();
    int h = getHeight();
    g.setColor(200, 200, 200);
    g.fillRect(0, 0, w, h);
    int rh = g.getFont().getHeight() + 8;
    Image mg = drawTitle(rh);
    for (int x = 0; x <= w; x += mg.getHeight()) {
      g.drawImage(mg, x, 0, Graphics.TOP | Graphics.LEFT);
    }
    g.setColor(0, 0, 0);
    g.drawString("Title Test", w/2, 4, Graphics.TOP | 
      Graphics.HCENTER);
  }
  public Image drawTitle(int height) {
    if (imgTitle == null) {
      int w = getWidth();
      imgTitle = Image.createImage(w, height);
      Graphics p = imgTitle.getGraphics();
      for (int y = 0; y < height; y++) {
        p.setGrayScale(255 - 128 * y / height);
        p.drawLine(0, y, w, y);
      }
    }
    return imgTitle;
  }
}
اکنون کد را تست کنيد:

با استفاده از متد ذيل مي توانيد ترسيمات مورد نظر خويش را بر روي هرگونه تصوير انجام دهيد:
private Image createBackImage(Image m){
   Image im = Image.createImage(m.getWidth(), m.getHeight());
   Graphics p = im.getGraphics();
   p.drawImage(m, 0, 0, Graphics.LEFT | Graphics.TOP);
   return im;
}
مديريت رويدادها
تا کنون با ترسيمات گوناگون با استفاده از Canvas آشنا شديد؛ حال بايد به کنترل و مديريت رويدادهاي آن نيز بپردازيم. همان گونه که اشاره شد، Canvas نيز از فرمان ها که عمده راه تعامل با کاربر است پشتيباني مي کند.
Canvasها مي توانند از فشردن کليدها آگاهي يافته و آن را مديريت کند؛ متدهاي keyPressed()، keyReleased() و keyRepeated() رويداد فشردن، آزادکردن بعد از فشردن و فشرده نگهداشتن کليدها را مديريت مي کنند. هريک از اين سه متد پارامتري مي گيرند که کد کليد (Key Code) گفته مي شود. علاوه بر کد کليدها، چند ثابت تعريف شده نيز وجود دارد: KEY_NUM0 تا KEY_NUM9، KEY_STAR و KEY_POUND.
همچنين Canvasها يک انتزاع (abstraction) از کد کليدها به عنوان game action ارائه مي کند؛ تبديل يک کد کليد به game action توسط متد getGameAction() صورت مي گيرد. ثابت هاي LEFT، RIGHT، UP، DOWN، GAME_A، GAME_B، GAME_C و GAME_D نيز در دسترس است.
در صفحه نمايش هاي لمسي رويدادهاي مربوط به اشاره گر (pointer) نيز مديريت مي شوند؛ فشردن اشاره گر و کشيدن (dragging)، دو رويداد معمول اين صفحه نمايش ها است. براي مديريت اين رويدادها از متدهاي pointerPreesed()، pointerReleased() و pointerDragged() استفاده مي کنيم. اين متدها دو پارامتر x و y را براي تعيين محل رويداد (نسبت به شيء مورد نظر) لازم دارند. براي آگاهي از پشتيباني دستگاه از فشردن اشاره گر، از متد hasPointerEvents() و براي آگاهي از پشتيباني از رويداد کشيدن از متد hasPointerMotionEvents() استفاده مي کنيم.
در مثال ذيل هر کليدي که فشرده شود، نام و کد آن بر روي صفحه نمايش چاپ مي شود؛ در صفحه نمايش لمسي نيز رويداد اشاره گر مربوطه چاپ مي شود:
import javax.microedition.lcdui.*;
public class CanvasTest4 extends Canvas {
  private String sMessage = "";
  public CanvasTest4() {    
  }
  public void paint(Graphics g) {
    int w = getWidth();
    int h = getHeight();
    g.setColor(255, 255, 255);
    g.fillRect(0, 0, w, h);
    g.setColor(0, 0, 0);
    g.drawString(sMessage, w / 2, h / 2, Graphics.TOP | 
       Graphics.HCENTER);
  }
  protected void keyPressed(int keyCode) {
    sMessage = "You pressed: " + getKeyName(keyCode) + ", 
      Code: " + keyCode;
    repaint();
  }
  protected void keyReleased(int keyCode) {
    sMessage = "You released: " + getKeyName(keyCode) + ", 
       Code: " + keyCode;
    repaint();
  }
  protected void keyRepeated(int keyCode) {
    sMessage = "You repeated: " + getKeyName(keyCode) + ", 
      Code: " + keyCode;
    repaint();
  }
  protected void pointerDragged(int x, int y) {
    sMessage = "Pointer dragged at: " + x + "-" + y;
    repaint();
  }
  protected void pointerPressed(int x, int y) {
    sMessage = "Pointer pressed at: " + x + "-" + y;
    repaint();
  }
  protected void pointerReleased(int x, int y) {
    sMessage = "Pointer released at: " + x + "-" + y;
    repaint();
  }
}

:: نظرها پیرامون مطلب
:: Bobs:
Touchdown! That's a really cool way of putintg it!

 
:: محمد:
خيلي خوب بود- ممنون

 
نظر شما:
نام و فامیل:  
نظر: