لماذا لا يزال واجهة المستخدم الرسومية معلقة حتى بعد استخدام swingutilities.invokelater؟

StackOverflow https://stackoverflow.com/questions/4227745

سؤال

لدي هذا 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);
       }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top