آخرين پستهاي سايت



بازگشت   سايت تخصصي موبايل > Symbian S60, S80, S90 > Nokia Symbian OS Series 60 > مقالات آموزشی
ثبت نام ليست كاربران گروه ها علامت گذاری بفرم خوانده شده

مقالات آموزشی [لطفا قبل از ارسال پست، قوانین این بخش را مطالعه کنید]



Closed Thread
 
ابزارهاي موضوع نحوه نمايش
قديمي 30-07-2007, 14:02   #1
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض آموزش گام به گام برنامه‌نویسی سری 60 با ++c

با عرض سلام

می‌خواهیم در این تاپیک برنامه‌نویسی موبایل را با یک مثال عملی آموزش دهیم. در حقیقت می‌خواهیم یک تیوتوریال را به صورت قدم به قدم پیش برویم.

من برای برنامه تیوتوریال، بازی Snake رو که مدتی وقت پیش نوشتم، انتخاب کردم. این برنامه برای آموزش مقدمات برنامه‌نویسی موبایل عالی می‌باشد ولی چون در این بازی از خیلی از امکانات گوشی استفاده نکرده‌ایم، مطالب زیادی را تحت پوشش قرار نمی‌دهد. در بازی تنها چیزی که در صفحه نمایش نمایش خواهیم داد، تنها مستطیل و متن هستند و از هیچگونه تصویری استفاده نخواهیم کرد.

تصویر این بازی رو می‌بینید:

خود بازی را می توانید از لینک زیر دریافت نمایید:

البته من این بازی رو به صورت دو زبانه نوشته‌ام ولی در اینجا فقط یک زبان و آن هم فقط فارسی را پشتیبانی خواهیم کرد. اگر مایل بودید که زبان دیگری را هم اضافه کنید، می‌توانید از مقاله «طراحی برنامه‌های چندزبانه» که من ترجمه کرده‌ام استفاده کنید.

ضمناً لطفاً پست‌های اضافی و بی‌مورد نیز ندهید تا تاپیک زیادی شلوغ نشود و دنبال کردن تاپیک برای افرادی که بعداً میآیند، راحتتر باشد.

زبان برنامه‌نویسی مورد استفاده ما در اینجا ++C خواهد بود و از همین حالا خیال همه را راحت کنم که من زبان دیگری برای برنامه‌نویسی موبایل بلد نیستم. پس سؤال نفرمایید.

موضوع مهم دیگری که از همین حالا باید تذکر بدهم این است که در اینجا هدفمان آموزش خود برنامه‌نویسی نیست و فقط می‌خواهیم برنامه‌نویسی موبایل را با مثال عملی آموزش دهیم؛

یعنی من از خوانندگان انتظار دارم که زبان ++C را تا حد قابل قبولی بلد باشند. چون من با این فرض این آموزش را می‌نویسم. به همین خاطر در اینجا کدهایی که زیاد به موبایل ارتباط ندارند و ذاتاً فقط کد ++C هستند را توضیح نخواهم داد.

فکر میکنم با این شرایط خوانندگان تاپیک محدودتر میشوند، ولی چاره دیگری نیست!

تا اولین بخش از آموزش خدانگهدار
mousa_mk is offline  
10 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:16   #2
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

نرم‌افزارهای لازم برای شروع کار:

اولین برنامه‌ای که لازم داریم، ActivePerl است. خودمان به طور مستقیم، هیچ استفاده‌ای از این برنامه نخواهیم کرد ولی نرم‌افزارهای بعدی که معرفی خواهم کرد، از این برنامه برای کامپایل کردن استفاده خواهند کرد.

این برنامه را می‌توانید به طور رایگان از سایت زیر دانلود کنید. سایزش حدود 12 مگابایت است.
http://www.activestate.com

دومین برنامه SDK می‌باشد. SDK که مخفف عبارت Software Development Kit می‌باشد حاوی ابزارهایی مثل کامپایلر، دیباگر، شبیه‌ساز و ... می‌باشد و مهمترین نرم‌افزار ماست. ابتدا به این صفحه بروید و مشخصات گوشی که تصمیم دارید برایش برنامه بنویسید را ببینید. (مثلاً سری 60 ورژن 2 با FP 2)

حال باید SDK با این مشخصات را از جایی پیدا کنید. این بخش تقریباً سخت‌ترین قسمت ماجرا است. مرجع اصلی SDKها فروم نوکیا می‌باشد که البته این سایت هم ایران را تحریم کرده است. (البته گاهاً بدون هیچ errorی اجازه دانلود می‌دهد ولی من خودم به شخصه تا بحال نتوانستم هیچ برنامه‌ای از فروم نوکیا دانلود کنم.) صفحه مخصوص SDKها در فروم نوکیا، اینجاست:
http://www.forum.nokia.com/info/sw.n...16-3.0-mr.html

من خودم SDK ورژن 2.1 را دارم و در سرور دانشگاه شریف آپلود کرده‌ام. اگر دنبال این ورژن هستید، می‌توانید از لینک زیر دریافت کنید: (ولی متأسفانه کیفیت و سرعت این سرور، بسیار پایین میباشد و فکر نکنم موفق به دانلود آن شوید!)
http://ce.sharif.edu/~moradi/downloa...DK_2_1_NET.zip

یک SDK برای سیمبین سری 60 ورژن 3 هم دوستانمان در سایت tarahi.net به همراه چند برنامه مفید دیگر برای برنامه‌نویسی سیمبین، آپلود کرده‌اند. اگر دنبال این SDK هستید، به لینک زیر مراجعه کنید:
http://www.tarahi.net/download.asp?dir=Symbian

با کمی سرچ کردن در اینترنت هم شاید بتوانید ورژن‌های دیگر SDK را هم گیر بیاورید.

اگر توانستید این مرحله سخت را پشت بگذارید، به سراغ سومین برنامه موردنیاز میرویم:
سومین برنامه مورد نیاز Microsoft Debugging Tools می‌باشد که باید از سایت زیر دریافت کنید:
http://www.microsoft.com/whdc/devtools/debugging

ورژنی از این برنامه را روی سرور دانشگاه آپلود کردهام که میتوانید از لینک زیر دریافت کنید: (حجم: 13 مگابایت)
http://ce.sharif.edu/~moradi/downloa...86_6.5.3.8.exe

چهارمین برنامه Microsoft Visual Studio میباشد که هر ورژنی از آن را می‌توانید داشته باشد. البته از Visual Studio هم ما به صورت مستقیم استفاده نخواهیم کرد ولی برای کار کردن ابزارهای دیگر لازم است.

پنجمین و باحالترین برنامه هم که تقریباً تمام کارمان با آن خواهد بود، Borland C++BuilderX Mobile Edition(v1.5) است. این برنامه قبلاً رایگان بود و به راحتی می‌شد از سایت بورلند دانلود کرد ولی الان مدتی است که اجازه دانلود نمی‌دهد؛ با این که هنوز هم رایگان است!

این برنامه را هم آپلود کرده‌ام که میتوانید از لینک زیر دریافت کنید:
http://ce.sharif.edu/~moradi/downloa...mobile-RTM.zip
فایل فعالسازی اش را هم از اینجا بگیرید:
http://ce.sharif.edu/~moradi/download/mobile/reg591.txt

ضمناً به اسم برنامه توجه داشته باشید. این برنامه را با برنامه Borland C++ Builder اشتباه نگیرید. این IDE که ما با آن کار خواهیم کرد، فقط و فقط مختص موبایل می‌باشد.

ضمناًدر صورت علاقمندی میتوانید به جای این برنامه آخری، از IDEهای دیگری هم مثل CodeWarrior، Visual Studio، Eclipse و ... هم استفاده کنید که من چون تا بحال دنبال این برنامه‌ها نبودم، تجربه‌ای هم ندارم و کمک زیادی هم نمی‌توانم در این مورد بکنم.
mousa_mk is offline  
9 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:23   #3
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

امیدوارم که برنامه‌ها را به دست آورده باشید. از حالا درسمان را به صورت عملی شروع می‌کنیم.

ایجاد پروژه جدید
نرم‌افزار C++BuilderX را اجرا کنید. از منوی File مورد New… را بزنید. در پنجره‌اي كه باز مي‌شود، در بخش سمت چپ، "Series 60" را انتخاب كرده و سپس در سمت راست، "New Series 60 GUI Application" را برگزينيد و OK را بزنيد. در پنجره جديد، نام پروژه را snake بگذاريد، مسير ذخيره شدن پروژه را انتخاب كنيد و ضمناً مورد "Create project subdirectory" را تيك بزنيد. SDK موردنظر را هم مشخص كنيد. شكل زير:

Next را بزنيد تا به صفحه بعدي برويد. دوباره همان نام snake را وارد كنيد. در كادر UID هم يك عدد در مبناي 16 (هگزادسيمال) به صورت تصادفي بين 0x10000000 و 0x1FFFFFFF وارد كنيد. در پايان كار اگر خواستيد برنامه‌تان را براي عموم پخش كنيد، بايد اين عدد را به عدد معتبري (كه بالاي 0x20000000 مي‌باشند) تغيير دهيد و اين اعداد معتبر را هم بايد از سايت www.symbiansigned.com تهيه كنيد. (در فرصت مناسب درباره UID توضيح خواهيم داد.)

براي view type مورد full screen را انتخاب كنيد. و بالاخره finish را بزنيد تا پروژه‌مان ايجاد شود.
تصوير محيط كاري را به صورت زير خواهيد ديد:

قبل از اين كه كار ديگري انجام دهيم، بهتر است پروژه را يكبار امتحان كنيم. دكمه Run Project (تصوير زير) را بزنيد تا برنامه اجرا شود. البته كامپايل كردن و ساختن برنامه مدتي طول مي‌كشد. كمي صبر كنيد.

يكي از اشكالزاترين مراحل همين اولين اجرا است. خيلي از افراد در اولين اجراي برنامه با حدود 20 – 30 تا error برخورد مي‌كنند و نمي‌دانند كه چه كنند. معروفترين اين errorها همين به صورت زير هستند:
كد:
'nmake' is not recognized as an internal or external error
'abld' is not recognized as an internal or external error
'link.exe' is not recognized as an internal or external error
cannot locate env32.pm
...
در صورتي كه شما هم با errorهاي بالا (يا خطاهاي ديگري) مواجه شديد، اول پيشنهاد مي‌كنم كه به تاپيك «خطا در اولين اجراي برنامه» در فروم خودم مراجعه كنيد و ببينيد كه آيا راه‌حل‌هايي كه قبلاً پيشنهاد شده‌اند، برايتان جوابگو هستند يا نه.
در صورت حل شدن مشكل، خدا را شكر كنيد و كارتان را ادامه دهيد؛ ولي در غير اين صورت errorتان را در همان تاپيك مذكور و يا در اينجا مطرح كنيد تا من يا دوستان ديگر راهنمايي‌تان كنيم.

اگر همه چيز به درستي پيش برود، بعد از ساخته شدن پروژه، شبيه‌ساز اجرا مي‌شود و منوي اصلي را نشان مي‌دهد. با كليدهاي جهت خود شبيه‌ساز به انتهاي منو برويد. برنامه‌مان را با نام SNAKE در آنجا خواهيد ديد. آن را اجرا كنيد. برنامه‌مان اجرا خواهد شد و يك صفحه سفيد خالي نشان داده خواهد شد. (تصوير زير)

با زدن كليد راست شبيه‌ساز از برنامه خارج شويد و شبيه‌ساز را ببنديد.
هميشه بعد از اجرا كردن برنامه وقتي مي‌خواهيد به كد زدن ادامه دهيد، شبيه‌ساز را ببنديد. اگر شبيه‌ساز باز بماند و دوباره بخواهيد برنامه را اجرا كنيد،errorهاي عجيب و غريبي دريافت خواهيد كرد.
mousa_mk is offline  
10 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:30   #4
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

قبل از اين كه شروع به كد زدن كنيم، ابتدا بايد مي‌خواهيم ببينيم IDE چه چيزهايي برايمان ايجاد كرده است. در حقيقت IDE خيلي از كلاس‌هايي كه حتماً بايد داشته باشيم را به همراه تعدادي فايل ديگر از جمله فايل‌هاي resource، mmp، bld.inf و ... برايمان ايجاد كرده است. اين فايل‌ها را به طور خلاصه توضيح مي‌دهيم. (توجه: شرح مفصل اين فايل‌ها را در مقاله «فايل‌هاي برنامه‌نويسي سيمبين» و همچنين در مقاله «آشنايي با برنامه‌نويسي سيمبين سري 60» نوشته‌ام.)

در پنجره Project كه در سمت چپ پنجره اصلي برنامه C++BuilderX است، مي‌توانيد فايل‌هاي پروژه را ببينيد. تصوير زير:

(ابتدا توجه داشته باشيد كه فايل snake.cbx كه در اين پنجره در بالاترين سطح قرار دارد، فايل استاندارد سيمبين نيست و برنامه C++BuilderX آن را براي خود ايجاد كرده است. محتويات اين فايل به صورت xml مي‌باشند كه البته ما با آن هيچ كاري نداريم و خود IDE از آن استفاده مي‌كند.)

1) فايل bld.inf: اولين و اصلي‌ترين فايل پروژه، فايل bld.inf مي‌باشد. در داخل اين فايل فقط نام فايل‌هاي mmp استفاده شده در پروژه نوشته مي‌شوند. البته اطلاعات محدود ديگري هم در اين فايل در برنامه‌هاي متفاوت‌تر وجود دارند ولي كاري با آنها نداريم. اگر اين فايل را باز كنيد، كد زير را در آن خواهيد ديد:

كد:
// Symbian OS BLD.INF Project file
// Generated by Borland C++Builder Project Wizard

PRJ_MMPFILES
snake.mmp
در اينجا ما فقط يك فايل mmp داريم كه نام آن در اينجا ثبت شده است.
2) فايل mmp: اين فايل، فايل تعريف مشخصات برنامه است. تمامي ويژگي‌هاي برنامه، فايل‌هاي استفاده شده، منابع برنامه، فايل‌هاي خارجي استفاده شده، libraryهاي استفاده شده، كد زبان‌هاي استفاده شده و خيلي چيزهاي ديگر، در اين فايل ثبت مي‌شوند. مي‌توانيد اين فايل را باز كنيد و محتوايتش را نگاه كنيد.

سورس‌فايل‌هايي هم كه ما در پروژه استفاده خواهيم كرد، در اين فايل ثبت شده‌اند و البته فايل‌هايي هم كه ما بعداً اضافه خواهيم كرد، بايد در اينجا نامشان نوشته شود.

3) فايل snake.rss: فايل‌هاي rss مخصوص resourceها يا همان فايل‌هاي منبع مي‌باشند. در فايل‌هاي resource مواردي مثل منوهاي برنامه، dialog boxهاي برنامه و ...، ساختارشان مشخص مي‌باشد. البته در برنامه C++BuilderX ما مي‌توانيم به صورت تصويري و خيلي راحتتر، منوها و dialogها را طراحي كنيم و نيازي به دانستن ساختار خشك و خالي اين فايل‌ها نداريم، به طوري كه اگر اين فايل را باز كنيد، مي‌بينيد كه IDE، كامنتي با اين مضمون نوشته است كه «اين كد توسط IDE مديريت مي‌شود. آن را ويرايش نكنيد!»؛ ولي در سطح بالاتر و همچنين براي كار كردن در مواقعي كه IDE در اختيار نداريم، مجبوريم كه ساختار اين فايل‌ها را بلد باشيم. البته در اينجا در مورد ساختار اين فايل‌ها توضيحي نمي‌دهيم و از ابزارهاي گرافيكي IDE استفاده خواهيم كرد. (براي توضيح بيشتر به دو مقاله معرفي شده در بالا، مراجعه كنيد.)
mousa_mk is offline  
10 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:31   #5
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

در ادامه مطلب قبلي، اكنون كلاس‌‌هاي برنامه را توضيح مي‌دهيم:

قبل از توضيح كدها، بايد كلاس‌هايي كه هر برنامه سيمبين بايد داشته باشد را توضيح مي‌دهيم:
1) كلاس Application: اين كلاس، كلاس اصلي برنامه است و آبجكتي از اين كلاس، معادل خود برنامه است. اين كلاس بايد از كلاس CAknApplication مشتق شود. يكي از وظايف اصلي اين كلاس، ساخت آبجكتي از كلاس document است.

2) كلاس Document: اين كلاس مسئول document برنامه است. در سيمبين اين محدوديت را داريم كه هر برنامه در حال اجرا فقط يك document مي‌تواند داشته باشد. اين كلاس هم بايد از CAknDocument مشتق شود. از وظايف اصلي اين كلاس، ياخت آبجكتي از كلاس AppUi مي‌باشد.

3) كلاس AppUi: اين كلاس براي مديريت رويدادها، بستن فايل‌ها و ... استفاده مي‌شود. هيچ خروجي در صفحه ندارد و رابط صفحه نمايش با Viewهاي خودش است. كلاس پايه‌اش CAknAppUi يا CAknViewAppUi است. (بسته به معماري برنامه)

4) كلاس View: هر View يك نمايش در صفحه است. هر View يك حاوي يك آبجكت از كلاس Container مي‌باشد كه Container خود به صورت مستقيم مسئول صفحه نمايش است. (در برخي معماري‌ها View خودش مسئول صفحه نمايش است و ديگر هيچ Containerي ندارد!) از كلاس CAknView مشتق مي‌شود.

5) كلاس Container: همانطور كه گفته شد، مسئول صفحه نمايش مي‌باشد. از كلاس‌هاي CCoeControl و MCoeControlObserver مشتق مي‌شود. (در سيمبين كلاس‌هايي كه نامشان با M شروع مي‌شود، فقط حاوي متد هستند و هيچ متغير عضو و ... ندارند. در حقيقت دقيقاً معادل با مفهوم Interface در جاوا مي‌باشند. با اين توضيحات مي‌توان ادعا كرد كه كلاس Container فقط از CCoeControl مشتق شده است.)
mousa_mk is offline  
9 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:33   #6
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

حال به خود كدها مي‌پردازيم:

از قسمت source در پنجره project فايل snakemain.cpp را باز كنيد. اين فايل، فايل اصلي بخش برنامه‌نويسي مي‌باشد و اجراي برنامه از اينجا شروع مي‌شود. اين فايل، حاوي دو تابع مي‌شود كه IDE خود، آنها را براي ما پياده‌سازي كرده است. اولي تابع E32Dll() مي‌باشد. اين تابع نقطه ورودي dll مي‌باشد و هميشه بايد مقدار KerrNone را برگرداند. (هر برنامه در سيمبين، حالت خاصي از يك dll است.)

دومين تابع، NewApplication مي‌باشد. اين تابع يك آبجكت از كلاس Application ما مي‌سازد و اشاره‌گر به آن را برمي‌گرداند. FrameWork با صدا كردن اين تابع، آبجكتي از برنامه ما به دست مي‌آورد و بقيه كارها را روي آبجكت انجام مي‌دهد.

فايل snakeapp.h را باز كنيد. (براي باز كردن اين فايل، ابتدا فايل snakeapp.cpp را باز كنيد و از پنجره Structure در سمت چپ، از بخش Includes، اين فايل را باز كنيد.)

كلاس Application در اينجا تعريف شده است. همانطور كه مي‌بينيد در اين هم فقط دو تابع پياده‌سازي شده است كه يكي از آنها يك آبجكت از كلاس Document مي‌سازد و اشاره‌گر به آن را برمي‌گرداند و دومي هم UID برنامه را برمي‌گرداند. (مي‌توانيد پياده‌سازي اين دو تابع را در فايل cppاش ببينيد.)

فايل snakedocument.h را باز كنيد. در اين فايل هم كلاس Document برنامه تعريف شده است. در اين كلاس هم تعدادي تابع Override شده‌اند كه توضيح مي‌دهم:

1) Constructor و Destructor كه البته نيازي به توضيح ندارند.
2) دو تابع استاتيك با نام‌هاي NewL و NewLC: وظيفه اين توابع ساخت آبجكتي از كلاس مي‌باشد.
3) تابع ConstructL: اين تابع هم توسط دو تابع استاتيك اشاره شده صدا زده مي‌شود و بقيه كار آنها را انجام مي‌دهد. (توضيح بيشتر در مورد اين تابع و دو تابع بالا را در پست بعدی خواهم داد.)

4) CreateAppUiL كه وظيفه‌اش ساخت آبجكتي از كلاس AppUi و برگرداندن اشاره‌گر به آن است.

توابع كلاس‌هاي AppUi و View و Container را به علت اين كه زياد هستند، الان شرح نمي‌دهم ولي بعداً در جاهايي كه لازم خواهند شد، توضيح خواهم داد.
mousa_mk is offline  
8 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:35   #7
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

اگر به كلاس Document نگاهي دوباره بيندازيد، خواهيد ديد كه ما constructor اين كلاس را private كرده‌ايم و در عوض براي ساختن آبجكت از اين كلاس از تابع استاتيك NewL استفاده مي‌كنيم. به نظر شما علت اين كار چيست؟

در جواب اين سؤال بايد يكي از تكنيك‌هاي مهم در برنامه‌نويسي سيمبين را كه با نام «سازنده دو فازي» شناخته مي‌شود، توضيح دهم:

در برنامه‌نويسي موبايل برخلاف كامپيوتر كه فكرمان از مقدار حافظه فارغ است، هميشه دغدغه كمبود حافظه داريم و بايد به همين دليل در مديريت حافظه حداكثر توجه‌مان را داشته باشيم.
پردازش استثنا يا همان Exception Handling در سيمبين نسبت به ++C استاندارد كاملاً متفاوت است. در سيمبين اگر هنگام اجراي تابعي، يك Exception رخ دهد، اجراي تابع متوقف مي‌شود و كنترل برنامه به جايي كه تابع صدا زده شده است، برمي‌گردد. و تاجايي پيش مي‌رود كه توسط يك TRAP هندل شود. در اين حالت مي‌گوييم كه «تابع تَرك شده است» (يك leave رخ داده است.) به توابعي كه پتانسيل ترك شدن (leave شدن) دارند، leaving functions مي‌گويند. توابعي كه پتانسيل leave شدن دارند، عبارتند از:

1) توابعي كه براي ايجاد متغير يا آبجكتي، حافظه مي‌گيرند. زيرا ممكن است با كمبود حافظه مواجه شوند.
2) توابعي كه تابع ديگري با اين شرط را صدا مي‌زنند.
3) توابعي كه در آنها خود برنامه‌نويس با نوشتن دستوراتي مانند User::Leave() يا User::LeaveIfError() باعث ايجاد يك Leave مي‌شود.

مي‌دانيم كه هر كلاسي معمولاً داراي تعدادي اشاره‌گر است كه بايد در هنگام ساخته شدن آبجكتي از آن كلاس، بايد متغيرهاي جديد ساخته شوند و آدرسشان در اين اشاره‌گرها ذخيره شود. و نيز مي‌دانيم كه اين وظيفه به عهده Constructor كلاس است. اما در اين صورت، با توجه به مطالبي كه در بالا گفتيم، Constructorكلاس، داراي پتانسيل leave مي‌شود، يعني اين كه مي‌تواند leave شود. ولي اين يك اتفاق بسيار ناگوار است. زيرا leave شدن Constructor معادل با ناتمام ساخته شدن آبجكت است.

يكي از نكات اساسي در سيمبين اين است كه هيچ Constructor و هيچ Destructorي نبايد leave شوند.

حال براي حل اين مشكل چه بايد كرد؟

يك راه‌حل كه در بادي امر به ذهن مي‌رسد، اين است كه وظيفه مقداردهي اوليه كردن اشاره‌گرهاي كلاس را در يك تابع ديگري غير از Constructor بنويسيم و از كاربر بخواهيم كه بعد از ساختن آبجكتي از كلاس، اين تابع را هم صدا بزند. ولي اين راه‌حل استاندارد نيست، زيرا مثلاً ممكن است كاربر فراموش كند كه اين كار را انجام دهد. راه‌حل ديگري كه به ذهن مي‌رسد، اين است كه همين تابع را خودمان در Constructor صدا بزنيم كه در اين صورت دوباره مشكل اول پيش مي‌آيد. زيرا در اين صورت Constructor ما طبق شرط (2) دوباره پتانسيل leave شدن پيدا مي‌كنند.
راه‌حل اين مسئله اين‌گونه است: ابتدا Constructor را private مي‌كنيم تا نتوان با new كردن از كلاس آبجكت گرفت. در خود Constructor فقط كدهاي غيرقابل leave را مي‌نويسيم. سپس يك تابع استاتيك (معمولاً با نام NewL) مي‌نويسيم تا ساخت آبجكت توسط اين تابع انجام شود. در اين تابع، ابتدا يك آبجكت new مي‌كنيم. سپس اين آبجكت را در استك Cleanup قرار مي‌دهيم. (اين مورد را بعداً توضيح مي‌دهم.) سپس تابعي كه براي مقداردهي اشاره‌گرها و رفرنس‌ها نوشته‌ايم را صدا مي‌زنيم. (معمولاً با نام ConstructL) بعد آبجكت را از استك pop مي‌كنيم و با كاربر برمي‌گردانيم.

و اما Cleanup Stack چيست؟ Cleanup Stack، استكي است كه سيمبين مواظب اعضاي آن است. اگر آبجكتي كه داخل اين استك است، هيچ اشاره‌گري به آن وجود نداشته باشد، توسط سيستم عامل، delete خواهد شد.

پس توضيح نحوه كار NewL به اين صورت خواهد بود: ابتدا آبجكتي از كلاس ايجاد مي‌شود. در اين مرحله چون هيچگونه حافظه‌اي براي متغيرها نمي‌گيريم، امكان leave شدن وجود ندارد. سپس همين آبجكت را به Cleanup Stack اضافه مي‌كنيم. (push مي‌كنيم) در اينجا با صدا زدن تابع ConstructL حافظه مورد نياز براي آبجكت را مي‌گيريم. در اين مرحله امكان leave شدن وجود دارد. اگر leaveي اتفاق افتد، آبجكت موجود در استك، چون اشاره‌گر به آن از بين مي‌رود، توسط سيستم عامل حذف مي‌شود و هيچ گونه حافظه‌اي تلف نمي‌شود. در صورتي كه اجراي تابع ConstructL با موفقيت تمام شود، آبجكت از استك، pop مي‌شود و به كاربر برگردانده مي‌شود.
ضمناً براي بهتر كردن ماژولار بودن كد، ايجاد كردن و push كردن آبجكت را در تابع NewLC مي‌نويسند و صدا زدن تابع ConstruclL و pop كردن آبجكت را برعهده تابع NewL مي‌گذارند. دو تابع NewL و NewLC فاز اول ساختن آبجكت و ConstructL هم فاز دوم ساختن آن را انجام مي‌دهد.

استفاده كردن از اين روش تقريباً در تمام كلاس‌هاي سيمبين انجام مي‌شود و تبديل به يك روش كلي شده است. حتي در كلاس‌هايي كه هيچ متغيري نداريم و امكان leave شدن وجود ندارد، باز هم از اين روش استفاده مي‌شود. مثلاً شما در همين كلاس Document و خيلي از كلاس‌هاي ديگر مي‌بينيد كه تابع ConstructL خالي است و كاري انجام نمي‌دهد.

تنها نكته‌اي كه ذكر آن باقي مي‌ماند، اين است كه قبل از ساخته شدن آبجكتي از كلاس Application برنامه، هنوز Cleanup Stack به وجود نيامده است و بنابراين براي كلاس Application نمي‌توان از روش سازنده دوفازي استفاده كرد.

مطلب اين پست، تماماً مفهومي بود و مطمئنم كه خسته‌كننده بوده است، ولي بايد توضيح داده مي‌شود. همين مفاهيم «سازنده دو فازي» و «Cleanup Stack»، دو مفهوم بسيار مهم و بسيار كاربردي در برنامه‌نويسي سيمبين مي‌باشد كه حتماً بايد بلد باشيد.
mousa_mk is offline  
9 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 30-07-2007, 14:39   #8
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

با عرض معذرت از تمامی دوستان، به علت اینکه من این هفته پنجشنبه امتحان میان ترم دارم، شاید تا شنبه نتونم خدمتتون برسم.

سعی کنید تا اون موقع برنامه های لازم را به دست آورید و آموزش را تا اینجا دنبال کرده باشید.
mousa_mk is offline  
5 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 04-08-2007, 12:55   #9
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

اكنون مي‌خواهيم كد زدن براي بازي را شروع كنيم.

هر بازي (موبايل يا كامپيوتر) يك Engine دارد كه تمام كارهاي بازي بر عهده آن مي‌باشد. ما هم براي بازيمان يك Engine طراحي مي‌كنيم. از منوي File مورد New File… را بزنيد. در پنجره‌اي كه باز مي‌شود، براي نام فايل، عبارت SnakeGameEngine و براي نوع فايل هم مورد h را برگزينيد. مسير فايل را به پوشه inc تغيير دهيد و تيك Add saved file to project را برداريد. (تصوير زير)

OK را بزنيد تا فايل ايجاد شود.
كد زير را در فايل كپي كنيد:
كد:
#ifndef __MKSNAKEGAMEENGINE_H_
#define __MKSNAKEGAMEENGINE_H_

#include <e32base.h>                       // Class 'CBase' is here
#include <e32math.h>                       // Math functions. (We use 'rand' here)
#include <s32file.h>                       // For working with file server
#include <aknutils.h>
#include "Snake.h"
#include <w32std.h>
#include <fbs.h>
#include <aknnotewrappers.h>                // Message boxes are here
#include <gdi.h>
#include <e32std.h>
#include <eikenv.h>
#include "MKSnake.rsg"



#define SCREEN_WIDTH    176                 // Screen width  in S60 display
#define SCREEN_HEIGHT   208                 // Screen height in S60 display
#define SCREEN_EDGE     3

#define DELETEANDNULL(p)     {delete p; p = NULL;}

#define GAME_VERSION_NUMBER    1            // Game version
_LIT(KMKSnakeDataFile, "settings.dat");     // File for saving highscore



const TInt KTickInterval = 150000;      // '0.15 Second' Interval for the Timer


class CMKSnakeContainer;                // Forward declaration


class CMKSnakeGameEngine : public CBase
..
public:
  // -------------------------------------------------------------------------
  // 'NewL' function for creating an Instance of this class
  // -------------------------------------------------------------------------
  static CMKSnakeGameEngine* NewL(CMKSnakeContainer* aOwningControl);

  // -------------------------------------------------------------------------
  // This function is called by 'NewL' function
  // -------------------------------------------------------------------------
  static CMKSnakeGameEngine* NewLC(CMKSnakeContainer* aOwningControl);

  // -------------------------------------------------------------------------
  // Destructor of class
  // -------------------------------------------------------------------------
  ~CMKSnakeGameEngine();

  // -------------------------------------------------------------------------
  // This function drows objects in the screen by suitable state
  // -------------------------------------------------------------------------
  void DrawScreen(const TRect& aRect);

  // -------------------------------------------------------------------------
  // This function starts a new game
  // -------------------------------------------------------------------------
  void StartNewGame();

  // -------------------------------------------------------------------------
  // This function creates and starts the Timer
  // -------------------------------------------------------------------------
  void StartTimerL();

  // -------------------------------------------------------------------------
  // This function stops our timer
  // -------------------------------------------------------------------------
  void StopTimer();

  // -------------------------------------------------------------------------
  // This function gets some properties and draws a text
  // -------------------------------------------------------------------------
  void DrawText(TInt aResourceId, TRect aRect, TRgb aColor, const CFont* aFont,
    CGraphicsContext::TTextAlign aHoriz, TInt aLeftMrg=0);

  // -------------------------------------------------------------------------
  // This function notifies the engine that the state has been changed
  // -------------------------------------------------------------------------
  void StateChanged();

  // -------------------------------------------------------------------------
  // This function notifies the engine that the snake has been died
  // -------------------------------------------------------------------------
  void SnakeDied();

  // -------------------------------------------------------------------------
  // This function saves the highscore in a file
  // -------------------------------------------------------------------------
  void SaveGameProgressL();

  // -------------------------------------------------------------------------
  // This function loades the highscore form file
  // -------------------------------------------------------------------------
  void LoadGameProgressL();

  // -------------------------------------------------------------------------
  // This function draws the random rectangle in the screen
  // -------------------------------------------------------------------------
  void DrawRandPoint();

  // -------------------------------------------------------------------------
  // This function creates a random point
  // -------------------------------------------------------------------------
  void CreateRandPoint();

  // -------------------------------------------------------------------------
  // This function notifies the engine that the snake has gotten the random point
  // -------------------------------------------------------------------------
  void GotTheRandPoint();

  // -------------------------------------------------------------------------
  // Draws inofrmation such that score, in the upper rectangle
  // -------------------------------------------------------------------------
  void DrawInformation();

private:
  // -------------------------------------------------------------------------
  // Private Constructor for this class
  // -------------------------------------------------------------------------
  CMKSnakeGameEngine(CMKSnakeContainer* aOwningControl);

  // -------------------------------------------------------------------------
  // This function creates the member variables of class
  // -------------------------------------------------------------------------
  void ConstructL();

  // -------------------------------------------------------------------------
  // This function draws two rectangles in the screen
  // -------------------------------------------------------------------------
  void DrawRects();

  // -------------------------------------------------------------------------
  // This function resets the screen
  // -------------------------------------------------------------------------
  void DrawInits(const TRect& aRect);

  // -------------------------------------------------------------------------
  // This function is called by Time
  // -------------------------------------------------------------------------
  static TInt TimerCallBack(TAny* aObject);

  // -------------------------------------------------------------------------
  // This function has being called by the timer
  // -------------------------------------------------------------------------
  void DoCallBack();

public:
  // -------------------------------------------------------------------------
  // The owner of this class's one object
  // -------------------------------------------------------------------------
  CMKSnakeContainer* iOwningControl;

  // -------------------------------------------------------------------------
  // A pointer to the snake object
  // -------------------------------------------------------------------------
  CSnake* iSnake;


  // -------------------------------------------------------------------------
  // The periodic timer that moves the snake
  // -------------------------------------------------------------------------
  CPeriodic* iPeriodicTimer;

  // -------------------------------------------------------------------------
  // An enumeration for determining the game's state
  // -------------------------------------------------------------------------
  enum TGameState
  ..
    ENotStarted,
    EPaused,
    ENormal,
    EEnded
  };

  // -------------------------------------------------------------------------
  // This object determines the game's state
  // -------------------------------------------------------------------------
  TGameState iGameState;

  // -------------------------------------------------------------------------
  // This is the random point
  // -------------------------------------------------------------------------
  TPoint iCurRandPoint;

  // -------------------------------------------------------------------------
  // A time object for creating a random
  // -------------------------------------------------------------------------
  TTime iTime;

  // -------------------------------------------------------------------------
  // This is the highscore
  // -------------------------------------------------------------------------
  TInt iMaxSnakeSize;


  // -------------------------------------------------------------------------
  // These objects is for drawing the screen:
  // -------------------------------------------------------------------------
  CFbsBitmap* iBackBufferBmp;
  CFbsBitGc*  iGc;
  CFbsBitmapDevice* iBackBufferBmpDrawingDevice;

};

#endif
همانطور كه خودتان هم مي‌دانيد، اين كد، مربوط به تعريف كلاس Engine بود. در كد بالا، تمام متدها و متغيرها را به طور خلاصه توسط كامنت توضيح داده‌ام. حال بايد اين كلاس را پياده‌سازي كنيم. دوباره از منوي File، مورد New File… را بزنيد. نام فايل را دوباره SnakeGameEngine بگذاريد. نوع فايل را cpp تعيين كنيد و مسير ذخيره شدن فايل را به پوشه src تغيير دهيد. مورد add saved file to project نبايد تيك داشته باشد. (شكل زير)

OK را بزنيد. در پنجره project در سمت چپ روي sources راست‌كليك كنيد و add sources… را بزنيد و فايلي كه الان ايجاد كرديد، را انتخاب كرده و OK را بزنيد تا به پروژه اضافه شود.
در اين فايل، ابتدا دستورات زير را بنويسيد:
كد:
#include "SnakeGameEngine.h"
#include "snakecontainer.h"
پياده‌سازي دو تابع NewL و NewLC را به خودتان واگذار مي‌كنم. طبق توضيحاتي كه در بخش «سازنده دو فازي» دادم، بايد به راحتي بتوانيد اين دو تا را بنويسيد.
پياده‌سازي شما بايد شبيه زير باشد:
كد:
CSnakeGameEngine* CSnakeGameEngine::NewL(CsnakeContainer* aOwningControl)
..
  CSnakeGameEngine* self = NewLC(aOwningControl);
  CleanupStack::Pop(self);
  return self;
}

CSnakeGameEngine* CSnakeGameEngine::NewLC(CsnakeContainer* aOwningControl)
..
  CSnakeGameEngine* self = new (ELeave) CSnakeGameEngine(aOwningControl);
  CleanupStack::PushL(self);
  self->ConstructL();
  return self;
}
Constructor و Destructor كلاس را هم مثل كد زير پياده‌سازي كنيد:
كد:
CSnakeGameEngine::CSnakeGameEngine(CsnakeContainer* aOwningControl)
:
  iOwningControl(aOwningControl),
  iGameState(ENotStarted),
  iMaxSnakeSize(3)
..
}

CSnakeGameEngine::~CSnakeGameEngine()
..
  DELETEANDNULL(iSnake);
  StopTimer();

  DELETEANDNULL(iBackBufferBmp);
  DELETEANDNULL(iGc);
  DELETEANDNULL(iBackBufferBmpDrawingDevice);
}
ماكروي DELETEANDNULL هم كه در فايل .h تعريف شده است.
mousa_mk is offline  
9 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
قديمي 04-08-2007, 13:03   #10
mousa_mk
عضو جديد
 
شماره كاربري : 85321
محل سكونت: آذربایجان
نام : موسی
ارسالها: 26
موبايل : Samsung-SGH-I8150-INNOV8
سيم كارت : 091
تشكرها: 32
تشكر از شما 139 بار در 23 پست
پيش فرض

ما بايد در برنامه‌مان يك آبجكت از كلاس Engine داشته باشيم. براي اين منظور در فايل snakecontainer.h تعريف زير را در بخش publicها بنويسيد:
كد:
CSnakeGameEngine* iGameEngine;
يكي از قراردادهاي كدنويسي سيمبين (Coding Convention) اين است كه تمام متغيرهاي عضو بايد داراي يك i در اولشان باشند و همچنين تمام پارامترهاي يك تابع هم بايد داراي a باشند. براي متغيرهاي محلي (local) قانوني وجود ندارد.

حال بايد اين اشاره‌گر را در جايي new كنيم. همانطور كه در بخش «سازنده دو فازي» توضيح دادم، اين كار بايد در تابع ConstructL كلاس انجام شود.
در فايل snakecontainer.cpp به تابع ConstructL برويد و كد زير را در انتهاي آن بنويسيد.
كد:
  // Create Game Engine:
  iGameEngine = CSnakeGameEngine::NewL(this);
  iGameEngine->StartNewGame();
در اينجا آبجكتي از Engineمان ايجاد مي‌كنيم و متد StartNewGame آن را صدا مي‌زنيم تا يك بازي جديد شروع شود. البته مي‌توانستيم كلاسمان را طور ديگري نيز طراحي كنيم تا موقع ايجاد شدن آبجكتي از آن، به طور اتوماتيك اين تابع صدا زده شود، كه البته بهتر نيز مي‌بود، ولي خب من در اينجا اينگونه نوشته‌ام.

الان هر موقع كه بازي ما در موبايل اجرا شود، آبجكتي از Engine نيز ايجاد مي‌شود و كار خود را شروع مي‌كند.
قبل از اين كه به ادامه طراحي Engine بپردازيم، ما به يك مار هم احتياج داريم. يك مار كه بايد در صفحه به دستور كاربر حركت كند و مربع‌ها را بخورد. از آنجايي كه بر اساس برنامه‌نويسي شي‌گرا كد مي‌زنيم، بايد يك كلاس براي آن ايجاد كنيم.

يك فايل جديد با نام Worm و با نوع .h ايجاد كنيد. (طبق روش قبلي) دقت داشته باشيد كه اين فايل بايد در پوشه inc ذخيره شود. (البته به خاطر اينكه از قبل فايلي با نام Snake.h موجود بود، اسم ديگري انتخاب كرديم وگرنه نام Snake مناسب‌تر بود.) كد زير را كه مربوط به تعريف كلاس CSnake مي‌باشد، در آن كپي كنيد:
كد:
#ifndef __WORM_H__
#define __WORM_H__

#include <e32base.h>
#include <w32std.h>
#include <gdi.h>
#include "TQueue.h"



class CMKSnakeGameEngine;


class CSnake: public CBase
..
public:
  //--------------------------------------------------------------------------
  // These two functions, perform the first phase of construction
  //--------------------------------------------------------------------------
  static CSnake* NewL(CFbsBitGc* aGc, CMKSnakeGameEngine* aOwningEngine);
  static CSnake* NewLC(CFbsBitGc* aGc, CMKSnakeGameEngine* aOwningEngine);

  //--------------------------------------------------------------------------
  // Destructor
  //--------------------------------------------------------------------------
  ~CSnake();

  //--------------------------------------------------------------------------
  // This function, initializes the snake
  //--------------------------------------------------------------------------
  void InitSnake();

  //--------------------------------------------------------------------------
  // This function draws the snake in the screen
  //--------------------------------------------------------------------------
  void Draw();

  //--------------------------------------------------------------------------
  // This function moves the snake one cell and if it hits wall or itself,
  // returns EFalse, otherwise ETrue
  //--------------------------------------------------------------------------
  TBool MoveOneCell();

private:

  //--------------------------------------------------------------------------
  // Private constructor for class
  //--------------------------------------------------------------------------
  CSnake(CFbsBitGc* aGc, CMKSnakeGameEngine* aOwningEngine);

  //--------------------------------------------------------------------------
  // This function performs the second phase of construction
  //--------------------------------------------------------------------------
  void ConstructL();

public:
  //--------------------------------------------------------------------------
  // An enumeration for snake's state
  //--------------------------------------------------------------------------
  enum TSnakeState
  ..
    EStarting,
    EMoving,
    EHitWallOrSelf
  };

  //--------------------------------------------------------------------------
  // An enumeration for snake's direction
  //--------------------------------------------------------------------------
  enum TSnakeDirection
  ..
    ELeft,
    ERight,
    EUp,
    EDown
  };

  //--------------------------------------------------------------------------
  // State of the snake
  //--------------------------------------------------------------------------
  TSnakeState iState;

  //--------------------------------------------------------------------------
  // Direction of the snake
  //--------------------------------------------------------------------------
  TSnakeDirection iDirection;

  //--------------------------------------------------------------------------
  // A Queue for keeping snake
  //--------------------------------------------------------------------------
  TQueue* iQueue;

  //--------------------------------------------------------------------------
  // A GC (Graphics Context) for drawing snake. (Initializes in constructor)
  //--------------------------------------------------------------------------
  CFbsBitGc* iGc;

  //--------------------------------------------------------------------------
  // A pointer to the 'Engine' class that owns this snake
  //--------------------------------------------------------------------------
  CSnakeGameEngine* iOwningEngine;

  //--------------------------------------------------------------------------
  // These four functions perform the moving of the snake
  //--------------------------------------------------------------------------
  void MoveUp();
  void MoveDown();
  void MoveLeft();
  void MoveRight();

  //--------------------------------------------------------------------------
  // Color of the snake. (In our game,  this is always fixed, But you can
  // give it from user in a 'settings' form...)
  //--------------------------------------------------------------------------
  TRgb iColor;

};

#endif
توضيحات لازم را داخل كد داده‌ام. حال براي پياده‌سازي Snake فايلي جديد با نام Worm.cpp ايجاد كنيد و سپس طبق روش قبلي آن را به پروژه اضافه كنيد.
mousa_mk is offline  
11 كاربر زير از شما mousa_mk عزيز، تشكر كرده اند
Closed Thread

ابزارهاي موضوع
نحوه نمايش

قوانين ارسال
شما نمی توانید موضوع جدید ایجاد کنید
شما نمی توانید پست ارسال کنید
شما نمی توانید فایل پیوست کنید
شما نمی توانید پستهای خود را ویرایش کنید

BB code is فعال
شکلکها فعال است
كد [IMG] فعال است
كدهاي HTML غير فعال است

مراجعه سریع


ساعت جاري 22:49 با تنظيم GMT +4.5 مي باشد.


Powered by vBulletin Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.