لماذا لا يزال واجهة المستخدم الرسومية معلقة حتى بعد استخدام swingutilities.invokelater؟
-
26-09-2019 - |
سؤال
لدي هذا ActionListener
التي يتم استدعاؤها في EDT. وظيفتي المؤامرة () ثقيلة من الناحية الحسابية ، يمكن أن تستغرق بسهولة خمس ثوان. جعل واجهة المستخدم الرسومية معلقة كما هو متوقع. أضفت SwingUtilities.invokeLater
رمز ولا يزال معلق. ألا ينبغي أن يكون واجهة المستخدم الرسومية مستجيبة الآن بعد أن قمت بتفريغ موضوع منفصل لحساب heave الخاص بي؟
final ActionListener applyListener = new ActionListener()
{
@CommitingFunction
public void actionPerformed(ActionEvent arg0)
{
/*Don't do plotting in the EDT :)*/
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
plot();
}
});
}
};
المحلول
مُطْلَقاً. Invokelater لا ينتج موضوعًا جديدًا. يوجد Invokelater لتوضيح Swing بشكل صريح "استخدم مؤشر ترابط إرسال الحدث لهذا الغرض ، ولكن ليس الآن". يوجد في Invoke و Invokelater للسماح لك بالقيام بعمليات آمنة فقط للاطلاع على الحدث من مؤشرات الترابط من مؤشرات الترابط الأخرى- ليس عن طريق القيام بها على هذه الخيوط ، ولكن عن طريق إخبار EDT بالقيام بها.
سيتم تشغيل ActionListener بسرعة كبيرة ، مع إلقاء قائمة Runnable على قائمة انتظار حدث Swing. ثم عندما يصل إلى هذا الحد ، سوف يستغرق الأمر خمس ثوان لتشغيل المؤامرة ().
الحل الوحيد هو إعادة صياغة مؤامرة (). إستخدم Swingworker (أو استراتيجية مماثلة لتربية القصير ، ولكن من المحتمل أن يكون Swingworker هو الأفضل لهذا) لتحريك منطق Plot () فعليًا إلى مؤشر ترابط مختلف. لا يمكن أن يرسم هذا الموضوع بأمان لأنه ليس مؤشر ترابط الأحداث المتأرجحة ، لذلك يجب إجراء جميع عمليات السحب الخاصة به عبر Invokelater (). لأسباب الكفاءة ، يجب أن تحاول القيام بجميع عمليات الرسم في وقت واحد ، على واحد من Invokelater () ، باستخدام النتائج المخزنة من حسابك.
نصائح أخرى
أنت تفعل عكس ما تعتقد أنك. بدلاً من تشغيل موضوع الحساب الخاص بك خارج EDT ، فإنك تسميه بشكل صريح داخل هو - هي!
swingutability.invokelater () قوائم الانتظار في الجري للاحتجاج في وقت لاحق ، في EDT! تريد استخدامها Swingworker في حين أن.
Invokelater إضافة مهمة إلى قائمة انتظار عمل واجهة المستخدم الرسومية. سيتم استدعاؤه بعد إجراء جميع المهام الأخرى ، ومع ذلك لا يزال يستخدم مؤشر ترابط واجهة المستخدم الرسومية.
أقترح عليك أن تنظر في استخدام خدمة ExecutorService.
كما يقترح adam ، يجب القيام بأي رسم فعلي له عبر Invokelater.
لا تظهر ما هو داخل وظيفة Plot () ، لكن يجب عليك ليس ضع أي لوحة هناك. احسب ما تريده في الخيط الجديد ، وقم بالرسوم في EDT. للقيام بذلك ، من الأفضل الاستخدام Swingworker
إليكم ما فعلته لتطبيق شركتي ، وهذا هو بعض رمز الزائفة لأسباب قانونية ، لكن Jist منه هو أنه إذا كانت الشاشة غير مستجيبة ، فستقوم بإعادة تشغيل واجهة المستخدم الرسومية. كلما استخدمت Swingutabilities لبدء EDT ، في نفس كتلة init ، قم بإنشاء خيوط مراقبة. سيقوم مؤشر ترابط واحد ببساطة بتنفيذ إجراء على مؤشر ترابط EDT باستخدام أدوات التأرجح. سيقوم مؤشر ترابط آخر بمراقبة الخيط الأول لمعرفة ما إذا كان يشعر أن الخيط الأول يستجيب. سوف يعترف الخيط الأول فقط بالاستجابة إذا كان بإمكانه إجراء أمر بسيط للغاية.
SET ISEDTCHECK إلى true عند التشغيل بطريقة طبيعية ، خطأ في وضع التصحيح (وإلا فسوف يتم إعادة تشغيله باستمرار.
if (isEDTCheck) {
new Thread("EDTHeartbeat") {
@Override
public void run() {
Runnable thisThingYouDo = new Runnable() {
public void run() {
int x = 0;
}
};
while (true) {
// first thread says we are waiting, aka bad state
edtwait=true;
try {
javax.swing.SwingUtilities.invokeAndWait(thisThingYouDo);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// first thread says we are not waiting, good state
edtwait=false;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread("EDTValidator") {
@Override
public void run() {
while (true) {
// is first thread in bad state?
if (edtwait) {
try {
Thread.sleep(3000);
// after 3 seconds are we still in bad state? if so, get rid of initial frame, pop up a dialog box in AWT that does no commands
if (edtwait) {
mainFrame.setVisible(false);
new Dialog();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
public class Dialog extends Frame {
private static final int WIDTH = 400;
private static final int HEIGHT = 300;
Frame f = null;
public Dialog() {
f = this;
hasSomethingBeenEntered=false;
this.setTitle("APP PROBLEM DETECTED");
this.setSize(WIDTH, HEIGHT);
this.setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - myapp.width, 0);
Panel p1 = new Panel() {
@Override
public void paint(final Graphics g) {
int left = Dialog.WIDTH/2 - 45; // don't use WIDTH shadowed by Panel class
int top = Dialog.HEIGHT/2 - 20; // same as above
g.drawString("APP HAS DETECTED A PROBLEM", left, top);
}
};
this.add("Center", p1);
this.setAlwaysOnTop(true);
TextArea tb = new TextArea("APP HAS DETECTED A MAJOR PROBLEM\nIT WILL NOW RESTART IN 5 SECONDS");
this.add(tb);
this.setVisible(true);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
restartApp();
}
private void restartApp() {
Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"cd C:\\Progra~1\\Common~1 && C:\\Progra~1\\Common~1\\MyAppDir\\myjavaapp.jar\"");
System.exit(0);
}