الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

كيف تبني نظام أحداث خاص بحزمتك

بدأه علاء الصالحي في 3 ديسمبر 2009 · 4 رد · 525 مشاهدة · في JavaSE
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

انقل لكم هذه التدوينة من مدونتي

وأتمنى أن تحوز على رضاكم

كيف حالكم يا شباب

كالعادة لست أتوقع أن يقرأ المقال الكثير

لكني كنت وعدت الأخ عصام في منتديات الفريق العربي

حين سألني عن نظام الأحداث events في حزمة المحرك AAnimation

بأني سأكتب شرحاً لآلية العمل

طبعاً أطلت جداً في الإيفاء بوعدي

وهذه ميزة لدي لا أحدد موعد انتهاء العمل

فيصبح وعدي بالإنتهاء منه مجرد سراب

لذا أتوقع حين أتم هذا المقال أن يكون عصام فهم الموضوع من تلقاء نفسه

وأن أكون أنا ضيعت وقتي في كتابة مقال لن يقرؤه حتى عصام :)

على كل هناك احتمال بسيط أن يكون عصام نسي الموضوع

-وأنا فعلاً صادق حين أقول احتمال بسيط لأن عصام لا يستهان به على الإطلاق-

ما الفائدة من الأحداث events؟

معروف أن الحزم packges وجدت لكي تسهل على المبرمجين العمليات المعقدة

أما لماذا وجدت الأحداث events فالأحداث وجدت لكي تعطي المجال لمستخدمي الحزم

عند حصول تغيير في حالة الكائنات داخل الحزمة من معالجة هذا التغيير بأسلوب يختلف من مبرمج إلى آخر

لنأخذ مثالاً على هذا عندما يضغط (بضم الياء) على زر في برنامج أ

فإن البرنامج يقوم بطباعة رسالة يوم جميل لا تنسى أن تسبح الله

أما في برنامج ب فعندما تضغط الزر فإنه سيشغل لك مقطعاً صوتياً

أي نظام أحداث يحتوي على جزئين أساسيين

1- المصدر للحدث Event Source

وهو الكائن أو الإنسان المسبب للحدث

2- المستمع للحدث Listner

وهو الكائن المسؤول عن معالجة الحدث

نلاحظ أن المستع دائماً كائن

لكن المصدر قد يكون كائن وقد يكون إنسان يتفاعل مع البرنامج

أعرف أن الكلام غير واضح لكن تعالوا نضرب مثالاً على الموضوع

عندما تضغط على زر رسالة ترحيبية في نافذة

فتحصل على رسالة "مرحباً بك في برنامج الأحداث"

تفاصيل الحدث في المثال السابق

الحدث:الضغط على الزر

مصدر الحدث:إنسان

المثال السابق كان مصدر الحدث فيه إنسان

نأخذ مثال آخر يكون فيه مصدر الحدث كائن

برنامج مؤقت Timer

بعد كل ساعة يصدر صوت يذكر المستخدم بأن ساعة انتهت

الحدث:مرور ساعة

مصدر الحدث:كائن من النوع مؤقت

أظن الأمور تحسنت بالنسبة للحدث ومصدر الحدث

لكني أظنها غامضة بعض الشيء بالنسبة للمستمع الحدث

هنا يبدأ الجد ويبدأ العمل

المستمع هو عبارة عن واجهة أو فئة مجردة

(يفضل أن تكون واجهة في جافا لأن جافا لا تدعم الوراثة المتعددة)

يتم تصميمها من قبل مبرمج الحزمة

لكن يتم بناؤها أو وراثتها من قبل المستخدم

ثم تسجيله ضمن قائمة الأحداث الخاصة بالحزمة

وستقوم الحزمة بتولي إخبار المستمع بالأحداث التي تحدث بها

أقصد بتصميمها كتابة قواعدها وتحديد آلية وكيفية الاستخدام

(من ناحية عملية كتابة رؤوس header الدوال التي يجب أن يقوم المستخدم للواجهة بإعادة كتابتها)

وأقصد ببناؤها أي لو كانت واجهة ووراثتها أي لو كانت فئة

يبدو أن الموضوع لازال يحتوي على الكثير من اللبس

وبما أن المقال يتضح بالمثال فنأخذ مثال

(تظن نفسك شاعر يا دب)

الموضوع يحتاج إلى تركيز يا أخ عبده

فاتركني وشأني لو سمحت

المثال هو ActionListner في حزمة swing في جافا

التصميم قام به فريق تطوير swing وهو كالتالي

package java.awt.event;

import java.util.EventListener;

public interface ActionListener extends EventListener {
	public void actionPerformed(ActionEvent e);

}

تلاحظون أن التصميم واجهة interface وأنا أدعم أن تكون هكذا دائماً

لأن الواجهات أكثر مرونة في التعامل من ناحية الوراثة

ولأني فعلياً لم أجد حالة تستدعي كون التصميم فئة مجردة AbstractClass

لكني أذكرها هنا لاحتمالية وجود ما يستدعي ذلك

بالنسبة لآلية بناء المستمع

هذا الجزء ليس مهماً لنا مطوري الحزمة

وإنما مهم للمبرمجين

على كل هذا مثال على بناء الواجهة ActionListener

package com.modonat-alaa;

import java.util.EventListener;

public Class Implementor implements ActionListenertListener {
	public void actionPerformed(ActionEvent e){
		//doing something
	}

}

مازال الموضوع غير واضحاً

كيف يتم التعامل بين مصدر الحدث والمستمع للحدث

يأتي هنا دور تسجيل الحدث

بعد أن قمنا ببناء الواجهة الخاصة بالحدث

كل كائن نقوم ببناؤه من هذه الفئة يسمى مستمع

لكنه مستمع لا يستمع

(ما هذا الكلام الغريب تقول لنا مستمع ثم تقول لنا لا يستمع)

يا أخ عبده الفكرة كالتالي صحيح أنك قمت ببناء مستمع جديد

لكنك لم تحدد لمن يستمع هذا المستمع

لكي نجعل المستمع يستمع يجب أن نوفر في الحزمة دالة يتم تسجيل المستمع من خلالها

دوال تسجيل المستمع تنقسم إلى قسمين

1- دالة set

2- دالة add

إذا كنا نرى أن الحدث لا يصح أن يكون له أكثر من مستمع

نستخدم الدالة set

مثال:لا أجد مثالاً فعلياً لكني أتوقع وجود هكذا شيء

إذا كنا نرى أن الحدث يصح أن يكون له أكثر من مستمع

نستخدم الدالة add

مثال:الأمثلة لا تعد ولا تحصى أنا نفسي قمت بعمل نظامين بهذه الطريقة

(لا والله استفدنا منك ومن أمثلتك واحد لا تجد عليه مثال والآخر أمثلة لا تعد ولا تحصى)

خبرتي في الموضوع جيدة يا عبده لكنها لم تصل إلى الكمال

لذا أنا أحاول أن أعطيكم خلاصة تفكري في الموضوع

لكني لا أضمن لكم أن يكون تفكيري سليماً مئة في المئة

لكي يتضح الموضوع بشكل أكبر سنقوم بعمل حزمة بسيطة

الحزمة تمثل عدد صحيح

لكن عند حصول أي تعديل على العدد نريد أن تنتج بعض الأحداث

1- العدد الجديد أكبر من العدد القديم

2- العدد الجديد أقل من العدد القديم

دعونا في البداية نقوم بتصميم الواجهة الخاصة بالحدث

package integer.event;

public interface IntegerEvent {

	void newVlueGreaterThanOldValue();

	void newVlueLesserThanOldValue();

}

بعد ذلك نقوم بكتابة الفئة عدد صحيح بأحداث IntegerEvent

package integer.event;
import java.util.ArrayList;
import java.util.List;
	/**
 	* هذه الفئة تمثل عدد صحيح
 	* لكنه يقوم بتوليد أحداث عند التغييرات التالية
 	* تغيير العدد الحالي إلى عدد أكبر
 	* تغيير العدد الحالي إلى عدد أصغر
 	* @author علاء الصالحي
 	*
 	*/

public class IntegerClass {
	/**
 	* هذا المتغير يمثل القيمة للعدد الصحيح
 	*/
	private int value;
	/**
 	* هذا المتغير يحتوي على قائمة المستمعين
 	* الذين يجب تنبيههم عند حصول تعديلات على العدد
 	*/
	private List<IntegerEvent> integerEvent;
	public IntegerClass(int value){
		this.value=value;
		integerEvent=new ArrayList<IntegerEvent>();
	}
	public int getValue (){
		return value;
	}
	/**
 	* هذه الدالة التي يتم من خلالها تغيير العدد الصحيح
 	* وهي الدالة التي تنتج منها الأحداث
 	* طبعاً نحن كمصممين للحزمة
 	* يجب علينا تنبيه كل المستمعين إلى حصول حدث جديد
 	* @param value القيمة التي سيتغير لها العدد
 	*/
	public void setValue(int value) {
		if(value>this.value){//هنا نقوم بعملية الفحص للتأكد من كون القيمة أكبر من القيمة القديمة
			doGreaterEvent();//وهنا يتم تنبيه المستمعين للحدث
		}
		else if(value<this.value){//هنا نقوم بعملية الفحص للتأكد من كون القيمة أصغر من القيمة القديمة
			doLesserEvent();//وهنا يتم تنبيه المستمعين للحدث
		}
		this.value = value;
	}
	private void doLesserEvent() {
		for (int i = 0; i < integerEvent.size(); i++) {//نقوم بالمرور على كل المستمعين وتنفيذ الدالة المسؤولة عن الحدث
			integerEvent.get(i).newVlueLesserThanOldValue();
		}	

	}
	private void doGreaterEvent() {
		for (int i = 0; i < integerEvent.size(); i++) {
			integerEvent.get(i).newVlueGreaterThanOldValue();
		}		
	}
	/**
 	* هنا يتم إضافة مستمع جديد لهذا الكائن
 	* @param event
 */	
	public void addIntegerEvent(IntegerEvent event) {
		if(event!=null)
			integerEvent.add(event);
	}

}

وبهكذا نكون أنهينا تصميم الحزمة الخاصة بنا مع وجود نظام أحداث فيها

(ما الذي أنهيناه يا أخ علاء لا أرى شيئاً يعمل)

بصراحة يا أخ عبده تصميم الحزم ليس له علاقة بأن ترى شيئاً يعمل

بل المفروض أن لا ترى شيئاً يعمل

الفكرة في الموضوع ككل أنك تساعد الآخرين في كتابة برامجهم

بأن تقوم بتسهيل الأمور عليهم

على كل لن أخيبك يا أخ عبده

سنرى معاً كيف يمكنني أن أستخدم الحزمة التي قمنا بتصميمها قبل قليل

في البداية علينا أن نقوم ببناء الواجهة IntegerEvent

وهذا تمثيل بسيط فقط سنقوم بطباعة كلمتي greater و lesser

package test;

import integer.event.IntegerEvent;

public class IntegerEventImpl implements IntegerEvent {

	@Override
	public void newVlueGreaterThanOldValue() {
		System.out.println("greater");
	}

	@Override
	public void newVlueLesserThanOldValue() {
		System.out.println("lesser");
	}

}

الآن سنكتب مثال بسيط على كيفية استخدام الفئة IntegerClass

package test;

import integer.event.IntegerClass;

public class Test {
	public static void main(String[] args) {
		IntegerClass integerClass=new IntegerClass(10);
		integerClass.addIntegerEvent(new IntegerEventImpl());
		integerClass.setValue(12);
		integerClass.setValue(10);
	}

}

لاحظوا الآن الجملة المطبوعة في console مع أني لم أقم بطباعة أي شيء هنا

وعلى رأي الأخ أيمن أبو سمرة سحر :)

فعلياً الأمر لا يتعدى كون نظام الأحداث الذي قمنا به يعمل بشكل جيد

في الخاتمة:

لكي أكون صادق معكم الأحداث التي فيها تفاعل من الإنسان ليش من السهولة بمكان أن يتم التعامل معها في جافا

بل الأمر يحتاج إلى بعض التعقيدات التي قد تلجأك لـ jni

في رأيي يمكنك الاكتفاء بالأحداث التي توفرها جافا مبدئياً

أمر أخير قبل أن أنهي هذا المقال

لابد أن الأخوة أصحاب الخبرة في تصميم الأنماط Design pattern

لاحظوا أن الأحداث قريبة من نمط المراقب observer

ربما أتكلم عن نمط المراقب بتفصيل في مقال آخر

على كل المهم أن الفكرة وصلت

لا تنسوا أن تدفعوا الإشتراك الشهري الخاص بمدونتي

(احم احم عن أي اشتراك تتكلم أيها الوغد ثم على ماذا سندفع لك اشتراكاً على مقالتك الغبية أم على ثقل دمك)

احم احم كنت أمزح يا أخ عبده

(اها إذن لا تعيدها يا ...)

ماشي ماشي يا أخ عبده على الأقل كف عن السباب القبيح

أختم قبل أن يقرر الأخ عبده أني أحتاج إلى علقة سخنة

تحياتي

المراجع:

لا شيء يمكن اعتباره كمرجع إلا لو اعتبرنا عملي في حزمة المحرك كمرجع

على العموم هذه وصلة لآخر إصدارة من الحزمة

1
حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#2

يا أخ عبده تأدب قليلا واعرف مع من تتكلم :mad:

في الحقيقة نسيت الأمر كليا :D

بالنسبة لحزمتك ففي الحقيقة ما يلزمها هو documentation يشرحها بشكل مفصل. فلا يكفي أن تصنع أعظم برنامج أو أعظم مكتبة إذا لم يعرف أحد كيف يستعملها.

لو كنت مكانك لكتبت كل أسبوع موضوعا عن الحزمة حتى تقوم الساعة.... أو يستعملها شخص ما :D

#3

لكي أكون صادق معك يا عصام

كل الحزم التي قمت بصناعتها حتى اليوم كلها لم يكن لي أي هدف منها سوى التعلم

(ما عدا واحدة أعمل عليها حالياً ضمن مهامي الوظيفية)

وبأمانة أنا استفدت الكثير

أقصد أنا حصلت على مبتغاي من حزمة مكوناتي حزمة بياني حزمة المحرك وغيرهم

لكن نفس الفكرة أعجبتني

مقال عن حزمة المحرك أسبوعياً

فكرة ليست بالسيئة أبداً

متى أبدأ في تنفيذ الفكرة

الله أعلم

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

#4

السلام عليكم ،،

عذرا استاذ علاء .. لم يتاح لي الفرصه بعد كي استخدم حزمة المحرك

ولكن بماذا قد استفيد منها ؟؟

هل من مقاله توضح مميزاتها وفي ماذا استخدمها ؟؟ ان شاء الله سوف استخدمها ولو للتجربه

وشكراً جزيلاً .. بالتوفيق :)

صــفــر

#5

الحزمة تساعدك على تحريك المكونات الخاصة بك في حزمة swing

بحيث تعطي مصمم الواجهات إمكانيات لا حصر لها لا يمكن أن تعطيك اياها المكونات الثابتة

من ناحية أخرى الحزمة تساعد مصممي الألعاب على البسيطة من الاستفادة من المكونات الموجودة فعلياً في ألعابهم

كنت كتبت مجموعة من المواضيع هنا عن الحزمة

هنا الإصدارات القديمة

/index.php?showtopic=188557

هنا الإصدارات الأحدث

/index.php?showtopic=175752

(لا أعلم إن كنت وضعت كل الإصدارات هنا لكن يمكنك التأكد من المدونة)

عارض الصور -مثال على حزمة المحرك-

/index.php?showtopic=204838

وسأحاول في أقرب وقت أن أقوم بعمل مقالات تكون مفصلة عن الحزمة

تحياتي

حزمة المحرك الإصدارة 0.8

أي أحد يجد أني ظلمته فليراسلني

وبإذن الله لو كان له حق سيأخذه

728x90.png

مواضيع مشابهة