المساعدة - البحث - قائمة الأعضاء - التقويم
نسخة كاملة: الدرس الثالث (وهو الموضوع الرابع)
برمجة - شبكات - كمبيوتر - منتديات الفريق العربي للبرمجة > منتديات لغات البرمجة العام > منتدى مبرمجي C و ++C و C++.NET > أرشيف منتدى قسم السي ++
إسماعيل ابراهيم
4- إضافة معالجة الرسائل للبرنامج
في الدرس السابق, قمنا ببناء نافذة, بواسطة مكتبة MFC , لكن تلك النافذة كانت غير مفيدة, مجرّد نافذة تستعرض نفسها امامنا! ولا تستجيب لاي مؤثرات... وبلغة برمجية نقول ان هذه النافذة لا تستجيب للرسائل التي تتلقاها من النظام. ولكي نجعلها تستجيب لهذه الرسائل سوف نضيف لها بعض السطور البرمجية, لترى كيف نحولها من نافذة كسولة الى نافذة فعالة, وحيوية!!
سوف نضيف للبرنامج كود وظيفته: جعل البرنامج يرسم دائرة نتيجة لضغط زر الماوس الايسر...
الخطوات هي: نضيف للبرنامج خاصية معالجة رسائل الماوس..- وعند تلقي رسالة ضغطة على زر الماوس الايسر سنرسم دائرة في موقع الضغطة وسوف نحتفظ بقيم النقاط, لكي نعيد رسم الدوائر عند الحاجة..( لا تقلق نفسك بكيفية رصد موقع الضغطة, لأن نظام التشغيل سيرسله لك مع الرسالة).

لكي يكون الكود واضحا,(ولكي نشعر باننا محترفينregular_smile.gif wink_smile.gif ) سنقوم بتقسيم كودنا الى ملفات .h و .cpp
الملفات :
MainFrm.cpp/.h سيضم هذان الملفان تعريفات فئة الاطار.. CMainFrame
MFCApp2.cpp/.h سيضم هذان الملفان تعريفات فئة البرنامج CMFCApp2

1- فئة البرنامج
نفس الكود الذي استخدمناه في فئة البرنامج في تطبيقنا السابق, لكننا قسمناه الى ملفين.

الملف الاول:
كود
MFCApp2.h:



// file: mfcapp2.h



class CMFCApp2 : public CWinApp

{

public:

    // Virtual function overrides.

   BOOL InitInstance();

};
الملف الثاني:


كود
MFCApp2.cpp:

// file: mfcapp2.cpp

#include <afxwin.h>

#include "mfcapp2.h"

#include "mainfrm.h"



CMFCApp2 MFCApp2;



BOOL CMFCApp2::InitInstance()

{

    m_pMainWnd = new CMainFrame();

    m_pMainWnd->ShowWindow(m_nCmdShow);



    return TRUE;

}
2- فئة الاطار : الاختلاف عن البرنامج السابق هو فقط في هذه الفئة:
الملف الاول
:
MainFrm.h

كود
  // file: mainfrm.h

#include <afxwin.h>



class CMainFrame : public CFrameWnd

{

    CPoint m_points[50];

    UINT   m_index;

public:

    CMainFrame();

    // Message map functions.

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

    afx_msg void OnPaint();

    

    DECLARE_MESSAGE_MAP()

};


الملف الثاني: mainfrm.cpp


كود
// file: mainfrm.cpp

#include <afxwin.h>

#include "mainfrm.h"



BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

    ON_WM_LBUTTONDOWN()

    ON_WM_PAINT()

END_MESSAGE_MAP()



CMainFrame::CMainFrame()

{

    m_index = 0;

    Create(NULL, "MFC App2");

}



// Message map functions.

void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)

{

    CClientDC dc(this);

    if(m_index<50)

 m_points[m_index++] = point;

    dc.Ellipse(point.x-30, point.y-30, point.x+30, point.y+30);



}



void CMainFrame::OnPaint()

{

    CPaintDC dc(this);

    for (UINT i=0; i<m_index; ++i)

 dc.Ellipse(m_points[i].x-30, m_points[i].y-30,

       m_points[i].x+30, m_points[i].y+30);

}
بعد ان تصنع هذه الملفات الاربع... جمعها في مشروع واحد وشغّل, وبعد ان يعمل المشروع .. اضغط بزر الماوس الايسر على النافذة لترى ردّة الفعل!
" كيفية التشغيل: بعد ان تصنع الملفات الاربع, اذهب الى فيجيوال سي++ 6 , وهناك قم بانشاء مشروع Win32 application فارغ, ثم اذهب الى project Setting واختر use MFC in static Library ...
ثم استعرض المشروع حسب الملفات , ستجد ثلاث مجلدات فارغة: 1) source files 2) header files 3) resource files..
اضغط بزر الماوس الايمن على المجلّد source files وبعده اختر add files to folder .. واختر الملفين الذين انشأناهما والذين ينتهيان بـ .cpp
كرر العملية مع المجلد header files لكن هذه المرة اختر الملفين الذين ينتهيان بـ .h "
قبل شرح هذا الكود (هذا البرنامج), سنتحدث عن كيفية اضافة معالجة االرسائل للبرنامج, يدويا. هناك طريقة الية وهي باستخدام نعالج الفئات ClassWizard فيقوم هو اليّا باضافة هذه الاشياء, لكن نحن لأن هدفنا التعليم, وليس الانتاج, فسنقوم بهذا يدويّا...
لكي تخبر البرنامج انه هنك معالجة رسائل فيه تستخدم ماكرو بإسم [ALIGN=LEFT]DECLARE_MESSAGE_MAP()[/ALIGN]هذا الماكرو وظيفته كما اسلفت, الاعلان عن وجود تصنيف للرسائل في برنامجنا, لا يهمنا كيف يعمل هذا الماكرو, المهم هو اننا نضيفه في نهاية تعريف الكلاس الذي يوجد فيه معالجة رسائل...
هذه اول خطوة, هناك خطوتين أخريتين لكي تتم معالجة الرسائل في برنامجك! الخطوة الثانية هي :
[ALIGN=LEFT]
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_LBUTTONDOWN()
ON_WM_PAINT()
END_MESSAGE_MAP()[/ALIGN]

وهذا ايضا ماكرو آخر نستخدمه في ملف الـ.cpp , وهو يحتوي التالي :
1- بداية الماكرو , وبين الاقواس CmainFrame: الفئة التي لها نعالج الرسائل, CframeWnd:الفئة الاساية التي منها اشتققنا فئتنا الحالية.
2- اسماء الرسائل(الاحداث) التي سنعالجها , ON_WM_LBUTTONDOWN() هو ماكرو يخبرنا اننا سنعالج رسالة ضغطة زر الماوس الايسر(WM_LBUTTONDOEN) والذي يناسب الدالة التي تعريفها بالشكل التالي:

[ALIGN=LEFT] afx_msg void OnLButtonDown(UINT nFlags, CPoint point[/ALIGN]);

afx_msg- مقدمة غير اجباريّة, لكنها من اجل اخبارنا ان هذه الدالة هي دالة ردّ على رسالة نظام..

, ON_WM_PAINT()هو ماكرو يخبرنا اننا سنعالج رسالة الدهن WM_PAINT .والتي تناسبه الدالة OnPaint.

3- نهاية الماكرو...
-------------------------------

إحفظ شكل الماكرو هكذا كما هو, وبين ال BEGIN_MESSAGE_MAPوال END_MESSAGE_MAP()تضع اسماء الرسائل التي تريد معالجتها في برنامجك... اسماء الرسائل ستحصل عليها من مصادر عدّة لا تخف..
--------------------

الخطوة الاخيرة لمعالجة الرسائل ... ما هي؟؟ طبعا تعريف الدوال التي سترد على الرسائل.. regular_smile.gif
هذا بشكل عام حول كيفية اضافة معالجة الرسائل الى برنامجنا.

شرح البرنامج: الان وقد علمت كيفية اضافة معالجة الرسائل للبرنامج سيسهل فهم البرنامج اعلاه.

فئة البرنامج CMFCApp2 مماثلة لتلك في برنامجنا الاول...(النافذة الفارغة).
فئة الاطار CmainFrame هنا كل الاضافات..

قمنا في ملف mainfrm.h بتعريف الفئةCmainFrame وفيها:

[ALIGN=LEFT]Cpoint m_points[50] [/ALIGN]

قمنا بتعريف مصفوفة من نوع Cpoint وهو النوع في MFC الذي نحفظ فيه قيَم النقاط , ولو تحرينا الدقّة العلمية فـ Cpoint ليس نوع من انواع البيانات بل هو كلاس(فئة) خاص بحفظ النقاط.. وسنرى الكثير من الفئات المشابهة مثل Crect ,Csize ....
UINT m_index - قمنا بتعريف متغير Unsigned int أي عدد صحيح موجب.. عرفناه ليكون عدّاد, للنقاط..
هذه التعريفات لم نضع امامها اي محددات للمجال (public ,private ,friend ) وبهذا تكون كأننا وضعنا أمامها المحدِّد private .. اي اعضاء خاصة...(لمعرفة المعنى راجع موضوع الفئات في سي++)
بعد ذلك قمنا بتعريف الاعضاء العامّة : وهي في هذه الحالة الباني
(constructor )
[ALIGN=LEFT]CMainFrame();[/ALIGN]
وبعدها عرفنا دوال الردّ على الرسائل:

[ALIGN=LEFT]afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnPaint();[/ALIGN]تعرفها!


وضعنا بعد ذلك وفي نهاية تعريف الفئة , وضعنا الماكرو DECLARE_MESSAGE_MAP

هذا شرح الملف الاول ارجو ان يكون واضحا...
الان شرح الملف الاخير:
[ALIGN=LEFT]
BEGIN_MESSAGE_MAP(CMainFrame, CframeWnd)
ON_WM_LBUTTONDOWN()
ON_WM_PAINT()
END_MESSAGE_MAP()[/ALIGN]
هذه القطعة قمنا بشرحها.


[ALIGN=LEFT]
CMainFrame::CMainFrame()
{
m_index = 0;
Create(NULL, "MFC App2");
}[/ALIGN]

هذا الباني.. ودائما نضع القيم الاوّلية للمتغيرات بواسطة الباني... لذا قمنا بوضع القيمة 0 في المتغير m_index وبعد ذلك انشانا النافذة (كما في الدرس السابق).
إقتباس
void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)
{
1:CClientDC dc(this(;
:2if(m_index<50(;
:3  m_points[m_index++] = point;
:4 dc.Ellipse(point.x-30, point.y-30,point.x+30,point.y+30);  

}

هذه الدالة سيقوم البرنامج بتنفيذها (استدعائها) عندما يضغط المستخدم زر الماوس الايسر, والاوامر هي حسب الترقيم اعلاه:
1- احفظ هذا الامر ووظيفته الحصول على الـDevice Context للفئة الحالية.. ووضعه في المتغير dc ووظيفة ال Device Context هو لنتمكن من عمل كل عمليات الاخراج على النافذة (كتابة رسم...الخ)
2- اذا كان m_index اقل من 50, اي اذا لم تكن المصفوفة قد امتلأت..(لأن مصفوفة النقاط تحتوي 50 عضو.. 0-49...
3- اذا تحقق الشرط في بند 2 فقم بوضع قيمة النقطة الحالية (احداثيات موقع الضغطة) ضع هذه القيم في المصفوفة...
4- الدالة ُEllipse والتي هي عضو في dc وظيفتها رسم قطع ناقص (قطع ناقص= دائرة ممطوطة regular_smile.gif تعريف عاميّ .. أما تعريفها فإن الدائرة هي قطع ناقص قطريه الافقي والعامودي متساويين)
أما البارمترات اربع التي مررناها للدالة Ellipse فهي: إحداثيات زوايا المربع الذي يحصر هذه الدائرة (القطع الناقص)...
كود
void CMainFrame::OnPaint()

{

    :1CPaintDC dc(this);

2:    for (UINT i=0; i<m_index; ++i(

 dc.Ellipse(m_points[i].x-30, m_points[i].y-30,

       m_points[i].x+30, m_points[i].y+30);

}.


كما تعلم فان النافذة اذا قام المستخدم بإخفائها, تصغيرها, ثم أعاد إظهارها, فان نظام التشغيل سيعيد رسم النافذة, ويدهن فحواها .. مما يجعلنا نخسر كل ما رسمناه عليها من دوائر.. ولحل هذه المشكلة نقول للبرنامج في حالة اعادة الدهن قم باعادة الرسم , لكي يظن المستخدم المسكين ان دوائره الاصلية لم تمحَ regular_smile.gif ..

وهذا الكلام نقوله لبرنامجنا بلغة برمجية كالتالي: بما ان الدالة هي OnPoint فهي ستنفّذ عند اعادة الدهن..
السطر 1 : كيفية الحصول على Device Context ..
السطر 2: حلقة for تمرّ على كلّ النقاط التي حفظناها في المصفوفة, وتعيد رسم دوائر بناءً على هذه النقاط....

وهااااااااااي هي... خلص الدرس. regular_smile.gif .. بتقدروا تروحوا
* الشبح *
اشكرك أخي العزيز على الدرس الجميل بس مافهمت عدل ( اعتقد يبغال انام واقد من النوم حق يكون مخي اكثر استقبال الى المعلومات الفيده ) أنا راجع الك بكره وعطيك 10000 سؤال teeth_smile.gif (بنفجر مخك قبل لاترد teeth_smile.gif )

اتمى الك التوفيق ونجاح في المستقبل القريب !؟(f)regular_smile.gif
اا الفاروق اا
السلام عليكم

مشكور أخ/ اسماعيل نفعك الله وإيانا بالعلم النافع..

ولكن الرجا دائما وضع روابط لدروسك السابقة فى كل موضوع.

وشكرا
mhammad
الله يعطيك العافية أخ اسماعيل والى الأمام (f)(f)
إسماعيل ابراهيم
السلام عليكم.,..
أعتذر عن التأخر في الرد...

ولا شكر على واجب...

أخ شبح.. في انتظار اسئلتك..

أخ اا الفاروق اا ... أعتذر لأنني لم أضع وصلات للدروس السابقة.. لكن بإذن الله سأفعل في المرات القادمة...

أخ محمد ... الله يعافيك... وشكرا,.(f)(f)
مبرمج المستقبل
و الله يعطيك العافية (gift)

تحياتي (f)
هذه "نسخة - خفيفة" من محتويات الرئيسية للإستعراض الكامل مع المزيد من الصور والخيارات الرجاء إضغط هنا.
Invision Power Board © 2001-2009 Invision Power Services, Inc.