خيط إرسال الأحداث

خيط معالجة الأحداث (EDT) هو خيط يعمل في الخلفية ، ويُستخدم في لغة جافا لمعالجة الأحداث الواردة من قائمة انتظار أحداث واجهة المستخدم الرسومية الخاصة بمجموعة أدوات النوافذ المجردة (AWT) . وهو مثال على المفهوم العام للبرمجة الموجهة بالأحداث ، والذي يحظى بشعبية واسعة في العديد من السياقات الأخرى غير جافا، مثل متصفحات الويب وخوادم الويب .

تتمثل الأحداث بشكل أساسي في أحداث التحديث التي تُجبر مكونات واجهة المستخدم على إعادة رسم نفسها، أو أحداث الإدخال من أجهزة الإدخال مثل الفأرة أو لوحة المفاتيح. يستخدم AWT نموذج رسم أحادي الخيوط ، حيث يجب تنفيذ جميع تحديثات الشاشة من خيط واحد. خيط إرسال الأحداث هو الخيط الوحيد الصالح لتحديث الحالة المرئية لمكونات واجهة المستخدم الظاهرة. يُعد تحديث المكونات الظاهرة من خيوط أخرى مصدرًا للعديد من الأخطاء الشائعة في برامج Java التي تستخدم Swing . [ 1 ] يُطلق على خيط إرسال الأحداث اسم العامل الأساسي في Adobe Flash، وخيط واجهة المستخدم في SWT و . NET Framework و Android .

حلقة رسائل لتسلسل عمليات الوصول إلى واجهة المستخدم الرسومية

يتكون تطبيق البرمجيات عادةً من عدة خيوط وبنية بيانات GIT واحدة. هذا يعني أن GIT بنية بيانات مشتركة، ويلزم وجود آلية تزامن لضمان وصول خيط واحد فقط إليها في كل مرة. على الرغم من أن AWT و Swing توفران طرقًا ( غير آمنة للخيوط ) لإنشاء مكونات واجهة المستخدم الرسومية والوصول إليها، وهذه الطرق مرئية لجميع خيوط التطبيق، إلا أنه في أطر عمل واجهة المستخدم الرسومية الأخرى، لا يحق إلا لخيط واحد، وهو خيط إرسال الأحداث، تنفيذ هذه الطرق. [ 2 ] [ 3 ] [ 4 ] ولأن المبرمجين غالبًا ما يغفلون هذا الشرط، فإن أدوات تصميم واجهة المستخدم الرسومية الخارجية ، مثل Substance ، تصل إلى حد رفض إنشاء أي مكون من مكونات Swing عند عدم تشغيله ضمن خيط إرسال الأحداث، [ 5 ] لمنع مثل هذا الخطأ البرمجي. يتم تسلسل الوصول إلى واجهة المستخدم الرسومية، ويمكن للخيوط الأخرى إرسال بعض التعليمات البرمجية لتنفيذها في خيط إرسال الأحداث من خلال قائمة انتظار رسائل خيط إرسال الأحداث .

بمعنى آخر، كما هو الحال في أطر عمل واجهة المستخدم الرسومية الأخرى، يقضي خيط معالجة الأحداث (EDT) وقته في إرسال الرسائل: فهو يحتفظ بقائمة انتظار للرسائل تتضمن الإجراءات المطلوب تنفيذها على واجهة المستخدم الرسومية. تُرسل هذه الطلبات إلى قائمة الانتظار من قِبل النظام وأي خيط تطبيق. يستهلك خيط معالجة الأحداث هذه الرسائل واحدة تلو الأخرى ويستجيب بتحديث مكونات واجهة المستخدم الرسومية. قد تكون الرسائل عبارة عن إجراءات معروفة أو تتضمن ردود استدعاء، وهي إشارات إلى أساليب المستخدم التي يجب تنفيذها بواسطة خيط معالجة الأحداث.

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

إرسال رمز المستخدم إلى EDT

توجد حلول متنوعة لإرسال التعليمات البرمجية إلى EDT وتنفيذ المهام الطويلة دون حظر الحلقة.

معالجات أحداث المكونات (المستمعون)

تدعم مكونات واجهة المستخدم الرسومية قوائم الاستدعاءات، المسماة بالمستمعين، والتي يتم ملؤها عادةً عند إنشاء المكونات. يقوم EDT بتنفيذ المستمعين عندما يقوم المستخدم بتنشيط المكونات بطريقة ما (النقر على زر، تحريك الماوس، تحديد عنصر، فقدان التركيز، تغيير حجم المكون، وما إلى ذلك).

مؤقت

يُستخدم هذا المكون للمهام القصيرة التي تتطلب الوصول إلى واجهة المستخدم الرسومية أو تعديلها بشكل دوري أو في أوقات محددة javax.swing.Timer. ويمكن اعتباره مكونًا غير مرئي لواجهة المستخدم الرسومية، حيث يتم تسجيل مستمعيه ليتم تشغيلهم في أوقات محددة.

المكافئات

طلبات من مواضيع أخرى

يمكن لخيوط التطبيق الأخرى تمرير بعض التعليمات البرمجية لتنفيذها في خيط معالجة الأحداث باستخدام SwingUtilitiesفئات مساعدة (أو EventQueueإذا كنت تستخدم AWT ). يجب تغليف التعليمات البرمجية المُرسلة بكائن Runnable. تسمح طريقتان من هذه الفئات بما يلي:

من سلسلة إرسال الأحداث.

invokeAndWait()لا ينبغي استدعاء هذه الطريقة من سلسلة عمليات إرسال الأحداث ، لأنها ستُطلق استثناءًSwingUtilities.isEventDispatchThread() . يمكن استدعاء هذه الطريقة EventQueue.isDispatchThread()لتحديد ما إذا كانت سلسلة العمليات الحالية هي سلسلة عمليات إرسال الأحداث.

يجب أن يكون الكود المُقدَّم عبر ` invokeLaterand` invokeAndWaitإلى `EDT` سريعًا قدر الإمكان لتجنب التجميد. وعادةً ما يكون الغرض منه هو عرض نتيجة عملية حسابية مطولة على واجهة المستخدم الرسومية (المستخدم).

نمط تصميم العامل

يمكن الجمع بين تنفيذ مهمة في سلسلة عمليات منفصلة وعرض نتائجها في جدول تفاصيل التنفيذ (EDT) باستخدام نمط تصميم العامل . يُعدّ javax.swing.SwingWorkerالصنف SwingWorker، الذي طورته شركة Sun Microsystems ، تطبيقًا لنمط تصميم العامل، وهو جزء من توزيعة Swing القياسية بدءًا من Java 6. عادةً ما يتم استدعاء SwingWorker من مستمع الأحداث المُنفَّذ في جدول تفاصيل التنفيذ (EDT) لتنفيذ مهمة طويلة الأمد، وذلك لتجنب حظر جدول تفاصيل التنفيذ (EDT).

عينات

SwingWorker < Document , Void > worker = new SwingWorker < Document , Void > () { public Document doInBackground () throws IOException { return loadXML ( ); // مهمة ثقيلة } public void done () { try { Document doc = get (); display ( doc ); } catch ( Exception ex ) { ex.printStackTrace ( ) ; } } }; worker.execute ();

إذا كنت تستخدم Groovy و groovy.swing.SwingBuilder، فيمكنك استخدام doLater()، doOutside()و edt(). ثم يمكنك كتابتها بشكل أبسط على النحو التالي:

doOutside { def doc = loadXML () // مهمة ثقيلة edt { display ( doc ) } }

المكافئات

عادةً ما يتم إنشاء SwingWorker للمهام الطويلة بواسطة EDT أثناء معالجة أحداث الاستدعاء (المستمع). عند إنشاء سلسلة عمليات عاملة، يتابع EDT معالجة الرسالة الحالية دون انتظار اكتمال العملية. غالبًا ما يكون هذا غير مرغوب فيه.

في كثير من الأحيان، يتولى EDT معالجة إجراء مكون واجهة المستخدم الرسومية، والذي يتطلب من المستخدم اختيار ملف عبر مربع حوار آخر، مثل JFileChooser، الذي يظهر ويظل متجاوبًا أثناء اختيار المستخدم للملف، ولا يتابع الإجراء مع الملف المحدد إلا بعد الضغط على زر "موافق". هذا يستغرق وقتًا (يستجيب المستخدم في غضون ثوانٍ)، وتحتاج إلى واجهة مستخدم رسومية سريعة الاستجابة (حيث تستمر الرسائل في EDT) طوال هذه الفترة التي يكون فيها EDT متوقفًا (لا يعالج الرسائل الأحدث، مثل JFileChooser، في قائمة الانتظار قبل إغلاق مربع الحوار وانتهاء إجراء المكون الحالي). يتم كسر هذه الحلقة المفرغة من خلال دخول EDT في حلقة رسائل جديدة، والتي ترسل الرسائل كالمعتاد حتى ظهور رسالة "انتهى مربع الحوار"، ثم تستأنف معالجة الرسائل العادية من الموضع المتوقف في إجراء المكون.

يحاكي مشروع Foxtrot مفتوح المصدر آلية ضخ الرسائل في Swing لتوفير آلية التنفيذ "المتزامنة" لمهام المستخدم العشوائية، والتي لا تستمر إلا بعد أن يكمل العامل المهمة.

button.addActionListener ( new ActionListener () { public void actionPerformed ( ActionEvent e ) { button.setText ( "Sleeping..." ); } } } } } } } } } } } } } } } } } } } } } } }String text = null ; try { text = ( String ) Worker.post ( new Task ( ) { public Object run () throws Exception { Thread.sleep ( 10000 ); return "Slept!" ; } } ) ; } catch ( Exception x ) ...button.setText ( text ) ;somethingElse (); } });

منذ إصدار Java 1.7، توفر Java حلاً قياسياً لحلقات الرسائل الثانوية المخصصة من خلال عرض createSecondaryLoop () في EventQueue () الخاص بالنظام.

انظر أيضاً

مراجع

  1. هذه المشكلة ليست خاصة بـ Java Swing . توجد نفس المشكلة في معظم مجموعات أدوات Widget ، مثل Windows Forms ، حيث تؤدي فئة BackgroundWorker نفس وظيفة SwingWorker في Java.
  2. "خيط إرسال الأحداث" . صن مايكروسيستمز . تم الاسترجاع في 2011-10-02 .
  3. "تصحيح أخطاء Swing - هل هو صعب حقاً؟" . ألكسندر بوتوشكين. مؤرشف من الأصل بتاريخ 2011-08-05 . تم الاطلاع عليه بتاريخ 2011-10-02 .
  4. "الخيوط الأولية" . صن مايكروسيستمز . تم الاسترجاع في 2011-10-02 .
  5. "إجراءات تدقيق أكثر صرامة بشأن انتهاكات EDT في Substance · Pushing Pixels" .