الأربعاء، 21 أبريل 2010

انشاء النوافذ - القائمة

القائمة
هي عبارة عن قائمة تحتوي مجموعة من الخيارات وتسمح لك اما الاختيار منها او تنفيذ عملية عند الضغط على أحدها ويتم ذلك حسب نوع القائمة.

انشاء القائمة
List(String title, int listType)
List(String title, int listType, String[] stringElements, Image[] imageElements)
يمكن انشاء القائمه عن طريق تمرير عنوان القائمة ونوعها كما يمكنك ارسال الخيارات الابتدائية للقائمة والصورة لكل خيار. مع ملاحظة أن مصفوفة الصور يجب ان تكون مساوية في العدد للخيارات الموجودة في القائمة كما يمكنك تمرير القيمة null اذا كنت لا ترغب باضافة صور.

أنواع القائمة
Implicit: هي قائمة يتم فيها اختيار العناصر ضمنيا بمجرد تحديده وعند الضغط على ال Fire Button في الهاتف فانه سيتم استدعاء ال commandAction في المتنصت المضاف لهذة القائمة.

Exclusive: هي قائمة تسمح لك باختيار أحد الخيارات فقط.

Multiple: هذه القائمة تسمح لك باختيار مجموعة من الاختيارات في نفس الوقت.

معالجة الأحداث
معالجة الأحداث في القائمة implicit يتم بطريقة مختلفة قليلا حيث سوف يتم ارسال SELECT_COMMAND الى ال commandAction الموجودة في المتنصت وهذا ال command معرف داخل ال List Class.
public void commandAction(Command c, Displayable s) {
if (c == nextCommand)
// ...
else if (c == List.SELECT_COMMAND)
// ...
}
مثال
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.*;

public class Lists extends MIDlet implements CommandListener {
List mainList;
List implicitList;
List exclusiveList;
List multipleList;
Command cmdExit = new Command( "Exit", Command.EXIT, 0 );
Command cmdBack = new Command( "Back", Command.BACK, 0 );

public void startApp() {
String[] options = {"Implicit", "Exclusive", "Multiple"};
mainList = new List("List Example", Choice.IMPLICIT, options, null);
mainList.setCommandListener(this);
mainList.addCommand(cmdExit);

options = new String[] {"A", "B", "C"};
implicitList = new List("Implicit List", Choice.IMPLICIT, options, null);
implicitList.addCommand(cmdExit);
implicitList.addCommand(cmdBack);
implicitList.setCommandListener(this);

exclusiveList = new List("Exclusive List", Choice.EXCLUSIVE, options, null);
exclusiveList.addCommand(cmdExit);
exclusiveList.addCommand(cmdBack);
exclusiveList.setCommandListener(this);

multipleList = new List( "Multiple List", Choice.MULTIPLE, options, null );
multipleList.addCommand(cmdExit);
multipleList.addCommand(cmdBack);
multipleList.setCommandListener(this);

Display.getDisplay(this).setCurrent( mainList );

}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
if(c == List.SELECT_COMMAND && d == mainList) {
int index = mainList.getSelectedIndex();
if( index == 0 ) {
Display.getDisplay(this).setCurrent(implicitList);

} else if(index==1) {
Display.getDisplay(this).setCurrent(exclusiveList);

} else if(index == 2) {
Display.getDisplay(this).setCurrent(multipleList);

}

} else if(c == cmdBack ) {
Display.getDisplay(this).setCurrent(mainList);

} else if(c == cmdExit) {
destroyApp(true);
notifyDestroyed();

}

}
}
في السطور من 10-13 قمنا بتعريف أربعة قوائم الأولى هي القائمة الرئيسة التي سوف تختار منها نوع القائمة التي تريد عرضها. في السطور من 18-21 تم انشاء القائمة الرئيسة واضافة الخيارات لها ثم تم اضافة الأمر cmdExit والمتنصت.

في السطور ما بين 23-27 تم انشاء القائمة الضمنية implicitList واضافة الأمران cmdExit و cmdBack واضافة المتنصت. ثم تمت اعادة العملية لكل من القائمة exclusiveList والقائمة multipleList. ثم في السطر 39 تم عرض القائمة الرئيسة.

الان سوف ننتقل الى ال commandAction في السطر 49 وبها سوف نتأكد في البداية من الأمر التابع للقائمة الضمنية مع ضرورة التأكد أن الأمر تم حدوثه في النافذة الرئيسة وليس في النافذة الداخلية حيث أنه توجد قائمتان ضمنيتان وهذا تم في السطر 50. بعد ذلك قمنا بمعرفة العنصر المحدد من القائمة والذي قام المستخدم بتحديدة ثم عرضنا القائمة المناسبة لهذا العنصر.

اذا تم اطلاق الأمر رجوع cmdBack نقوم بالعودة للقائمة الرئيسة عن طريق عرضها على نافذة الهاتف.

الجمعة، 16 أبريل 2010

انشاء النوافذ - نافذة التنبيه

نافذة التنبيه
هي نافذة تقوم بعرض بيانات للمستخدم لمدة معينة من الوقت ثم تختفي. تستخدم هذه النافذة عادة لعرض رسائل الاخطاء والتحذيرات وغيرها من المعلومات للمستخدم.

انشاء نافذة التنبيه
public Alert(String title)
public Alert(String title, String alertText, Image alertImage, AlertType alertType)
أنواع التنبيهات
Info: تستخدم لعرض معلومات عامة للمستخدم.
Alarm: يستخدم لعرض رسالة تنبية عند حدوث حدث معين يكون المستخدم قد طلب تنبيهة علية مثل منبة الساعة او منبة حدوث اجتماع.
Confirmation: يستخدم لتأكيد حدوث شئ ما للمستخدم.
Error: يستخدم لتنبية المستخدم على حدوث خطأ ما في البرنامج.
Warning: ويستخدم لتحذير المستخدم من عملية خطيرة مثل مسح بعض البيانات وغيرها من العمليات.

التحكم في مدة ظهور النافذة
تظهر نافذة التنبية لمدة معينة ثم تختفي ويمكن تغيير هذه المده عن طريق الامر التالي:
setTimeout(int time)
ويكون الوقت المرسل بال milliseconds ويمكنك أن ترسل الية القيمه Alert.FOREVER وبذلك لن تختفي شاشة التنبية حتى يأمرها المستخدم بذلك.

مثال
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.*;

public class Alerts extends MIDlet implements CommandListener {
private Form mainForm;
private Command cmdExit;
private Command cmdInfo;
private Command cmdAlarm;
private Command cmdConfirm;
private Command cmdError;
private Command cmdWarning;

public void startApp() {
mainForm = new Form( "Alerts" );
cmdExit = new Command( "Exit", Command.EXIT, 0 );
cmdInfo = new Command( "Info", Command.SCREEN, 0 );
cmdAlarm = new Command( "Alarm", Command.SCREEN, 0 );
cmdConfirm = new Command( "Confirm", Command.SCREEN, 0 );
cmdError = new Command( "Error", Command.SCREEN, 0 );
cmdWarning = new Command( "Warning", Command.SCREEN, 0 );

mainForm.addCommand( cmdExit );
mainForm.addCommand( cmdInfo );
mainForm.addCommand( cmdAlarm );
mainForm.addCommand( cmdConfirm );
mainForm.addCommand( cmdError );
mainForm.addCommand( cmdWarning );
mainForm.setCommandListener( this );

Display.getDisplay(this).setCurrent(mainForm);

}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
if( c == cmdExit ) {
destroyApp(true);
notifyDestroyed();

} else if( c == cmdInfo ) {
Alert alert = new Alert( "Alert", "Info", null, AlertType.INFO );
Display.getDisplay(this).setCurrent( alert );

} else if( c == cmdAlarm ) {
Alert alert = new Alert( "Alert", "Alarm", null, AlertType.ALARM );
Display.getDisplay(this).setCurrent( alert );


} else if( c == cmdConfirm ) {
Alert alert = new Alert( "Alert", "Confirmation", null, AlertType.CONFIRMATION );
Display.getDisplay(this).setCurrent( alert );

} else if( c == cmdError ) {
Alert alert = new Alert( "Alert", "Error", null, AlertType.ERROR );
Display.getDisplay(this).setCurrent( alert );

} else if( c == cmdWarning ) {
Alert alert = new Alert( "Alert", "Warning", null, AlertType.WARNING );
alert.setTimeout( Alert.FOREVER );
Display.getDisplay(this).setCurrent( alert );

}

}
}
في السطور من 21-34 قمنا بانشاء أمر الخروج و 5 أوامر أخرى لعرض نوافذ التنبيهات. في السطور من 28-33 قمنا باضافة هذه الأوامر الى النافذة التي سوف نعرضها على شاشة الهاتف. في السطر 34 أضافنا المتنصت الى اللنافذة mainForm. في السطر 36 عرضنا النافذة mainForm على شاشة الهاتف. الان اذا قام المستخدم بضغط أي أمر فان ال commandAction سوف تستدعى تلقائيا ويرسل لها الامر الذي ضغط علية المستخدم. في ال commandAction قمنا بفحص الامر المرسل والاستجابة بشكل صحيح لكل أمر. جميع نوافذ التنبية تعرض لمدة معينه ثم تختفي وتعود نافذة ال mainForm الى شاشة الهاتف الا النافذة الاخيرة فهي لا تختفي الا اذا ضغط المستخدم على الأمر Done المرفق معها وذلك بسبب وجود الامر
alert.setTimeout( Alert.FOREVER );  

الأربعاء، 14 أبريل 2010

انشاء النوافذ - النافذة النصية

النافذة النصية
كما تحدثنا في الموضوع السابق فان النافذة النصية هي نافذة تغطي كامل شاشة الهاتف وتسمح للمستخدم ادخال النصوص.

انشاء النافذة النصية
public TextBox(String title, String text, int maxSize, int constraints)
أنواع قيود النافذة النصية

ANY: يمكنك ادخال اي حرف أو رقم أو رمز داخل المربع النصي.
EMAILADDR: يمكنك ادخال عنوان بريد الكتروني فقط.
NUMERIC: يمكنك ادخال أرقام صحيحة فقط.
PHONENUMBER: يمكنك ادخال رقم هاتف فقط.
URL: يمكنك ادخال رابط تشعبي فقط.
DECIMAL: يمكنك ادخال رقم نسبي.
PASSWORD: يمكنك من ادخال كلمة مرور.

مثال

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.*;

public class TextBoxDemo extends MIDlet implements CommandListener {

private TextBox txtAny;
private Command cmdExit = new Command("Exit", Command.EXIT, 0);

public TextBoxDemo() {
txtAny = new TextBox("Any", "", 100, TextField.ANY);
txtAny.addCommand(cmdExit);
txtAny.setCommandListener(this);

}

public void startApp() {
Display.getDisplay(this).setCurrent(txtAny);

}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
destroyApp(true);
notifyDestroyed();

}

}
في هذا المثال أنشأنا نافذة نصية في ال constructor وهي تقبل أي نص ثم قمنا بوضعها على الشاشة في السطر 22.

الأحد، 11 أبريل 2010

الاستجابة للأحداث

ادارة ال Commands في النوافذ:
في موضوع اليوم سوف نتعرف على كيفية الاستجابة للأحداث باستخدام ال commands. تتم اضافة ال commands الى اي Displayable Class عن طريق الأمر التالي:

public void addCommand(Command cmd)
ويمكن حذفها باستخدام الأمر المضاد وهو:

public void removeCommand(Command cmd)
تعريف ال Commands:

Command c = new Command("OK", Command.OK, 0);
Command c = new Command(
"Run", // short label
"Run simulation", // long label
Command.SCREEN, // command type
0); // priority

يعتمد مكان ظهور ال Command في النافذة على ال نوع ال Command وعلى أولويتة وطبعا هي تختلف من من هاتف الى أخر. فعلى سبيل المثال في أجهزه ال Nokia جميع الأوامر السلبيه مثل Back, Exit, Cancel توضع على يمين الشاشة اما الأوامر الايجابيه Ok, Options تكون على يسار الشاشة والعكس تماما يحدث عند تشغيل البرنامج على هاتف Sony Ericsson. اذا كل ما علي فعله هو تحديد نوع ال Command وأهميته وسف يتولى الهاتف مهمه وضعه في المكان المناسب الذي اعتاده مستخدم الهاتف دون كتابه الكود بشكل مختلف لكل هاتف.

أنواع ال Commands:

Okلتأكيد الااختيار
Cancelالغاء عمليه معينه
Backالرجوع الى الشاشه السابقة
Stopايقاف العمليه الحاليه
Helpاظهار شاشة المساعدة
Screenأمر عام يستخدم لباقي الأومر

الاستجابة للأوامر:
أولا يحب اضاف المتنصت على النافذة المراد معالجة الأوامر عليها باستخدام الأمر التالي:

public void setListener(CommandListener l)
بعدها يجب كتابة ال commandAction() method التابعة للمتنصت.

مثال:

public class Commander extends MIDlet
implements CommandListener {
public void startApp() {
Displayable d = new TextBox(
"TextBox",
"Commander",
20,
TextField.ANY);

Command c =
new Command("Exit", Command.EXIT, 0);
d.addCommand(c);
d.setCommandListener( this );
Display.getDisplay(this).setCurrent(d);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
destroyApp( true );
notifyDestroyed();
}

}
في السطور من 4-14 قمنا بتعريف نافذة واحدة وهي مربع نصي، ثم عرفنا Command واحد نوعة EXIT ثم اضفناة ال ى هذه النافذة. بعدها جعلنا ال Commander Class هو المتنصت على الأحداث. ثم عرضنا النفذة على شاشة الهاتف.

في السطور 24-25 استجبنا للأمر Exit الذي سوف يقوم باستدعاء commandAction عندما يقوم المستخدم بالضغط عليه وبالتالي الخروج من البرنامج عن طريق notifyDestroyed.

الان ماذا لو كان هناك أكثر من أمر فكيف لي أن أحدد الأمر الذي تم طلبه من المستخدم. ماذا لو تمت اضافه نفس الامر لأكثر من نافذة يشتركون في نفس المتنصت فكيف لي أن أعرف النافذة التي وقع فيها الحدث. يمكن حل الاشكالين السابقين باستخدام المتغيرات المرسلة لل commandAction() حيث أن الأول يمثل الأمر الذي طلبه المستخدم تحديدا والثاني يمثل النافذة التي وقع عليه الحدث فلة كان عندي نافذه بها مجموعه من الأوامر يمكنني حل المشكله كالتالي:
public void commandAction(Command c, Displayable d) {
if( c == cmdExit ) {
destroyApp(true);
notifyDestroyed();

} else if( c == cmd1 ) {
// do action1

} else if( c == cmd2 ) {
// do action2

} else if( c == cmd3 ) {
// do action3

}
}

الأربعاء، 7 أبريل 2010

انشاء واجهة مستخدم عالية المستوى ( مقدمة )

مقدمة
اليوم سوف نترك الأمور النظرية وننطلق الى أول موضوع عملي في JME. في هذا الموضوع سوف نقوم بشرح كيفية انشاء واجهة مستخدم عالية المستوى. في البدايه سوف نقوم بالقاء نظرة على واجهة المستخدم التي تقدمها لنا JME.



كما نلاحظ من الصورة السابقة فان ال Classes المسؤوله عن انشاء النوافذ في الواجهات عالية المستوى توجد داخل مكتبة lcdui. ال Class الأب لجميع النوافذ هو ال Displayable. النوافذ في الواجهات عالية المستوى تضم ال Classes التالية: Alert, List, Form, TextBox. سوف نتحدث عن كل واحد منها بالتفصيل ان شاء الله.

نظرة عامة على النوافذ في الواجهات عالية المستوى

Alert
مربع الحوار وهو يستخدم لعرض رسائل الى المستخدم مثل رسائل الأخطاء والتنبيهات وغيرها.

TextBox
الصندوق النصي وهو عبارة عن صندوق يغطي كامل شاشة الموبايل ويسمح للمستخدم بالكتابة داخله.


List
القائمة وهي تغطي كامل شاشة الموبايل وتحتوي على مجموعة من الخيارات تسمح للمستخدم باختيار احداها او مجموعة منها حسب نوع القائمة.

Form
النموذج وهو نافذة تحتوي على أدوات داخلها تسمح للمستخدم بالتفاعل مع البرنامج.

كيفية عرض النافذة على شاشة الموبايل:


public void startApp() {
Display d = Display.getDisplay( this );
d.setCurrent( form );
}

الفئة Display مرتبطة بشاشة الموبايل الحقيقية وعن طريقها تستطيع أن نأمر أي نافذة بالظهور على شاشة الموبايل الحقيقية عن طريق setCurrent التي يمكن أن تمرر لها احدى النوافذ الأربع السابق ذكرها.

الاثنين، 5 أبريل 2010

كتابة أول برنامج

السلام عليكم...
في هذا الموضوع سوف نقوم بكتابة اول برنامج باستخدام JME.
  1. قم بتشغيل NetBeans.
  2. من قائمة File اختر New Project.
  3. في مربع حوار New Project تحت خيار Categories قم بتحديد Java ME ثم قم باختيار Mobile Application تحت خيار Projects ثم انقر على Next.
  4. في مربع حوار New Mobile Application قم بتعبئة HelloJME في خانة Project Name. تأكد من وجود اشارة صح أمام خانة Set As Main Project وازالة الاشاره من أمام خانة Create Hello MIDlet ثم انقر Next.
  5. في مربع حوار Default Platform Selection قم باختيار المحاكي من خانة Emulator Platform، يمكنك تحديد المحاكي الافتراضي وهو Java Platform Micro Edition SDK 3.0. في خانه ال Device يمكنك تحديد الجهاز الذي تريد ان تجربه. أنا شخصيا أفضل DefaultCldcPhone1. بعدها قم بتحديد ال configuration وال profile الذي تريد أن تعتمده. الخيار الاكثر شهرة هو CLDC 1.1 و MIDP 2.0. انقر على Next.
  6. انقر على Finish.
  7. في نافذه Projects انقر بزر الفأره الايمن على Source Packages ثم اختر New ثم اختر MIDlet.
  8. في خانة MIDlet Name ضع الاسم Hello JME وفي خانة MIDP Class Name ضع HelloJME ثم انقر Finish.
  9. نقوم بكتابة البرنامج التالي:




import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.*;

public class HelloJME extends MIDlet {    
private Form form;    
public void startApp() {        
form = new Form( "Hello JME" );        
form.append( "This is my first JME application!!" );        
Display.getDisplay( this ).setCurrent( form );            
}    
public void pauseApp() {    }    
public void destroyApp(boolean unconditional)     {}    
}

في السطر رقم 9 قمنا بتعريف نموذج من أجل عرضه على شاشه الموبايل. في السطر 10 اضفت StringItem على النموذج ثم في السطر 11 قمنا بعرضه على شاشه الموبايل. لا تقلق ان لم تفهم الكود سوف نقوم بشرح تفصيلي للعديد من الأمثله في المستقبل القريب بعون الله.

الجمعة، 2 أبريل 2010

دورة حياة ال MIDlet

في هذا الموضوع سوف نتعرف على دوره حياه تطبيقات ال MIDlets. ما يجب ان نعرفه ان تطبيقات الموبايل تختلف عن تطبيقات الجافا الاعتياديه فنحن نعلم ان كل برامج الجافا يجب ان تحتوي على Main Class وهو Class يحتوي على main method التي يبدأ منها البرنامح بالتنفيذ.



Class SomeClass {
public static void main(String args[] ) {
// init application here
}
}


ولكن الوضع مختلف في تطبيقات الموبايل حيث لا وجود لل main method واستبدلت بثلاث methods رئيسه تمثل ثلاث حالات يمكن ان تكون بها ال MIDlet الا وهي:
  1. paused
  2. active
  3. destroyed
يتحكم في دوره حياه ال MIDlet برنامج يوجد على الهاتف يسمى
Application Management Stystem أو اختصارا بال AMS فهو الذي ينشئ ال MIDlet استجابه لطلب المستخدم بتنفيذ البرنامج وهو الذي ينقلها لحاله ال paused استجابه لوقوع حدث معين مثل استقبال مكالمه هاتفيه او انطلاق المنبه. الان سوف نحاول فهم دورة حياه ال MIDlet والحالات التي يمكن ان تمر بها.


عندما يقوم المستخدم بطلب تشغيل تطبيق ال MIDlet سوف يقوم ال AMS بنقل ال MIDlet من حالة الموت الى الحاله active وذلك يتم عن طريق استدعاء startApp() method من داخل ال MIDlet وبذلك تكون ال MIDlet قد بدأت بالعمل. الان اذا امر المستخدم البرنامج بالانتهاء فانه سوف يتم استدعاء destroyApp() method وبعدها سوف تنتقل ال MIDlet الى حالة destroyed وبذلك لن يمكنك العوده الى البرنامج الا عن طريق اعادة تشغيله مرة اخرى عبر المرور ب ()startApp. اخر حالة وهي عندما يكون التطبيق في حاله active فانه يمكن ان يحدث حدث خارجي مثل استقبال مكالمه مما يضطر ال AMS الى نقل ال MIDlet الى الحالة paused عن طريق استدعاء pauseApp() method ليتمكن المستخدم من الرد على المكالمة وبعدها يمكنه العودة للبرنامج عن طريق نقل ال MIDlet مره أخرى من حالة paused الى حالة active عن طريق استدعاء ()startApp مره اخرى.

لذلك فان تطبيقات ال MIDP يجب ان تحتوي على الاقل على MIDlet واحده وهي عباره عن class يورث من ال MIDlet class ويحتوي على هذه الثلاثة methods كالتالي:




public class Application extends MIDlet {
public Application() { }

// Called when the MIDlet is created or re-started
public void startApp() { }

// Called to pause the MIDlet
public void pauseApp() { }

// Called to terminate the MIDlet
public void destroyApp(boolean unconditional)
{ }
}