السلام عليكم و رحمة الله تعالى و بركاته,,
في هذا الموضوع, ستنتحدث, إن شاء الله, عن تنفيد الأحداث في لغة سي++. سنعرف الأحداث على أنها وسيلة تمكن عناصر سي++ من إعلام عناصر أخرى وقت حدوث حدث ما. الحدث يمكن أن يكون تغيير في محتوى متغير, إنشاء عنصر, تدميره, إلخ.
هذه لائحة متمنياتي :
- أريد من الحدث أن يكون قادرا على إشعار أي عنصر من العناصر.
- العنصر المرسل ليس مرغما على المعرفة المسبقة للعنصر المستقبل.
- العنصر المرسل يحدد شكل الدالة التي ستتم المناداة عليها لإشعار العنصر المستقبل بوقوع الحدث.
- العنصر المرسل يحدد نوع العنصر الذي سيتم تمريره للدالة المستقبلة و هذا العنصر سيحتوي كل المعلومات المتعلقة بالحدث.
- سنكتفي في هذه المحاولة الأولى بإمكانية إشتراك واحد في الحدث.
ليتمكن المرسل من إشعار المستقبل أي مستقبل بالحدث, المرسل لا يجب أن يكون مرغما بمعرفة المستقبل و لهذا سنعتمد على كلاس افتراضي يمكن من تسجيل اشتراك في الحدث و الإشعار به دون معرفة مسبقة بالمستقبل :
// كلاس إفتراضية تستعمل كمؤشر لكلاس event
class IEvent
{
public :
// تقوم هذه الدالة بالمناداة على الدالة التي تم تسجيلها على أنها المستقبل للإشعار بحدوث الحدث
virtual void Invoke(ISender *pSender, IEventArgs *pEventArgs) = 0;
};الكلاس event في شكلها الحالي صغيرة و بسيطة جدا و سيتم تطويرها في الردود التالية :
// كلاس لتسجيل و تسيير حدث
// نوع الكلاس التي ستستقبل الإشعار بحدوث الحدث R
// نوع الدالة التي سيتم المناداة عليها وقت حدوث الحدث و الإشعار به F
template<class R, class F>
class event : public IEvent
{
private :
// العنصر الذي سيستقبل الإشعار بالحدث
R *m_pReceiver;
// مؤشر نحو الدالة الموجودة بالعنصر المستقبل و التي سيتم المناداة عليها لإشعار العنصر بحدوث الحدث
F m_pEventFunc;
public :
// تهيئة الحدث
// مؤشر العنصر المستقبل للحدث : pReceiver
// مؤشر الدالة التي سيتم المناداة عليها وقت حدوث الحدث : pEvFunc
event(R *pReceiver, F pEvFunc) : m_pReceiver(pReceiver), m_pEventFunc(pEvFunc)
{}
// IEvent تفعيل للدالة الموروثة عن الكلاس
// تقوم هذه الدالة بالمناداة على الدالة التي تم تسجيلها على أنها المستقبل للإشعار بحدوث الحدث
void Invoke(ISender *pSender, IEventArgs *pEventArgs)
{
(m_pReceiver->*m_pEventFunc)(pSender, pEventArgs);
}
};في نسختها الحالية الكلاس event تقوم :
event(R *pReceiver, F pEvFunc);
الباني الإفتراضي للكلاس event والذي يقوك بتسجيل المعلومات الازمة لإشعار عنصر عند وقوع حدث ما. pReceiver : مؤشر العنصر المستقبل للإشعار بوقوع الحدث. pEvFunc : مؤشر الدالة التي سيتم المناداة عنها للإشعار بوقوع الحدث.
void Invoke(ISender *pSender, IEventArgs *pEventArgs);
الدالة التي سيستعملها العنصر المرسل للمناداة على الدالة التي ستستقبل الإشعار بوقوع الحدث. pSender : مؤشر العنصر الذي أرسل الإشعار بوقوع الحدث. pEventArgs : العنصر الوريث للكلاس الإفتراضية IEventArgs و الذي سيحتوي على معلومات -يحددها العنصر المرسل- عن الحدث.
الكلاس IEventArgs ستكون, إن شاء الله, الكلاس الأم لكل كلاس مشخصة لحمل معلومات متعلقة بحدث ما.
الكلاس المرسل هو الذي يحدد نوع الدالة التي يجب على المستقبل تفعيلها لاستقبال الإشعار
بالحدث. و النوع العادي لهذه الدالة هو على الشكل التالي :
void event_function_name(ISender *pSender, IEventArgs *pEventArgs)
أنظر للدالة IEvent::Invoke للمزيد من المعلومات.
وفي الأخير سنتحدث عن طريقة تعريف و تهيئة الحدث :
أولا سنعرف مؤشر للكلاس IEvent على الكلاس المرسل :
IEvent *pEvent_Name;
ثانيا سنعرف و نفعل الدالة المستقبلة للإشعار بوقوع الحدث داخل الكلاس المستقبلة للحدث :
void event_function_name(ISender *pSender, IEventArgs *pEventArgs)
{
// الكود الذي سيتم تنفيده عند الإشعار بوقوع الحدث
}ثالثا حجز اشتراك في الحدث :
pEvent_Name = (IEvent *)new event<Receiver_Class, P_STD_EVENT_FUNC>(&Receiver_Object, &Receiver_Class::event_function_name);
و أخيرا يمكننا المناداة على الدالة المستقبلة للإشعار بوقوع الحدث بالشكل التالي :
pEvent_Name->Invoke(pSende_Object, pEvent_Args_Object);
في الأيام القادمة سأنشر نسخة مطورة لهذه الكلاس والتي سيتم زيادة إمكانية تعدد الإشتراكات في الحدث الواحد من طرف العديد من العناصر إضافة إلى زيادة في حماية تسيير الأحداث.
المرجو التبليغ عن أي خطإ لأنه لم تتم تجربة هذه الكلاس...
في الملف المرفق ستجدون مشروعا عليه كل الكود إضافة لبرنامج صغير لتجربة الكلاس event
تحياتي...