1

私の質問について多くの回答が見つかりましたが、アプリケーションが例外をスローしない理由をまだ理解できません。NetBeans 8 で新しい Java フォーム アプリケーションを作成しました。フォームが作成され、main メソッドで次のように表示されます。

public static void main(String args[])
    {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try
        {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
            {
                if ("Nimbus".equals(info.getName()))
                {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (ClassNotFoundException ex)
        {
            java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (InstantiationException ex)
        {
            java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (IllegalAccessException ex)
        {
            java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (javax.swing.UnsupportedLookAndFeelException ex)
        {
            java.util.logging.Logger.getLogger(MainForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                new MainForm().setVisible(true);     
            }
        });
    }

したがって、この新しい Runnable は新しい MainForm を作成し、それを可視に設定します。

次に、私のコードでは、いくつかの jButton と jTextField を更新する新しいスレッドを開始します。以下のコード:

private void updateUI() {
        updateUIThread = new Thread(() ->
        { 
            while (true) {
                try {
                    jtfIP.setEnabled(!Start && !autoRec);
                    jtfPort.setEnabled(!Start && !autoRec);
                    jtfSlaveID.setEnabled(!Start && !autoRec);
                    jtfTimeout.setEnabled(!Start && !autoRec);
                    jtfReqInterval.setEnabled(!Start && !autoRec);
                    jCheckBox1.setEnabled(!Start && !autoRec);
                    jCBReconnect.setEnabled(!Start && !autoRec);

                    if (db != null) {
                        if (!db.getIsOpen()) {
                            jPBD.setBackground(Color.RED);
                            jPBD.setForeground(Color.WHITE);
                            jPBD.setText("ER");
                        } else {
                            jPBD.setBackground(Color.GREEN);
                            jPBD.setForeground(Color.BLACK);
                            jPBD.setText("OK ");
                        }
                    } else {
                        jPBD.setBackground(Color.RED);
                        jPBD.setForeground(Color.WHITE);
                        jPBD.setText(" ER ");
                    }


                    if (autoRec){
                        jbtnConnect.setText("Auto");
                        if (Start && Connected) {
                            jbtnConnect.setForeground(Color.BLACK);
                            jbtnConnect.setBackground(Color.GREEN);
                        } else {       
                            jbtnConnect.setForeground(Color.WHITE);
                            jbtnConnect.setBackground(Color.RED);
                        }
                    } else {
                        if (Start) {
                            jbtnConnect.setText("Disconnect");
                            jbtnConnect.setForeground(Color.BLACK);
                            jbtnConnect.setBackground(Color.GREEN);

                        } else {
                            jbtnConnect.setText("Connect");
                            jbtnConnect.setForeground(Color.WHITE);
                            jbtnConnect.setBackground(Color.RED);
                        }
                    }

                    jtfErroriCitire.setText(String.valueOf(totalErrors));

                    try
                    {
                        Thread.sleep(300);
                        jPanel4.repaint(1);
                    }
                    catch (InterruptedException ex)
                    {
                        Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                catch (Exception ex) {
                    Logger.getLogger(MainForm.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        updateUIThread.start();
    }

そして、上記のように開始された他のスレッドがあり、上記のスレッドで更新されるさまざまな値を取得します。

私の質問は、私のコードが別のスレッドから更新された UI 要素に関して例外をスローしないのはなぜですか? 私は使用しませんでしたSwingUtilities.invokeLater(new Runnable() { //code here }); そして私のコードは完全に実行されます...

ありがとうございました!

4

3 に答える 3

4

Swing はスレッドセーフではなく、シングルスレッドです。イベント ディスパッチ スレッドの外部から UI コンポーネントを更新しないでください。同様に、EDT 内で実行時間の長いプロセスやブロック コードを実行しないでください。これにより、イベント キュー内で新しいイベントが処理されなくなり、アプリが更新されたように見えます。ハング...持っているので...

詳細については、Swing での同時実行をご覧ください。

しばらく頭を悩ませた後、簡単な解決策は単に使用することであることに気付きましたjavax.swing.Timer

定期的な間隔 (300 ミリ秒) で更新を繰り返し、UI を更新したいのですが、完璧です。SwingTimerは定期的な間隔で更新をスケジュールし、EDT のコンテキスト内でコールバックを実行できます。

また、繰り返しの通話を統合する機能もあります。つまり、イベント キューに「タイマー」アクションが既に存在する場合、タイマーは新しいアクションを生成せず、EDT のフラッディングを防ぎ、パフォーマンスの問題を引き起こす可能性があります...

javax.swing.Timer timer = new Timer(300, new ActionListener() {
    public void actionPerformed(ActionEvent evt) {    
        jtfIP.setEnabled(!Start && !autoRec);
        jtfPort.setEnabled(!Start && !autoRec);
        jtfSlaveID.setEnabled(!Start && !autoRec);
        jtfTimeout.setEnabled(!Start && !autoRec);
        jtfReqInterval.setEnabled(!Start && !autoRec);
        jCheckBox1.setEnabled(!Start && !autoRec);
        jCBReconnect.setEnabled(!Start && !autoRec);

        if (db != null) {
            if (!db.getIsOpen()) {
                jPBD.setBackground(Color.RED);
                jPBD.setForeground(Color.WHITE);
                jPBD.setText("ER");
            } else {
                jPBD.setBackground(Color.GREEN);
                jPBD.setForeground(Color.BLACK);
                jPBD.setText("OK ");
            }
        } else {
            jPBD.setBackground(Color.RED);
            jPBD.setForeground(Color.WHITE);
            jPBD.setText(" ER ");
        }


        if (autoRec){
            jbtnConnect.setText("Auto");
            if (Start && Connected) {
                jbtnConnect.setForeground(Color.BLACK);
                jbtnConnect.setBackground(Color.GREEN);
            } else {       
                jbtnConnect.setForeground(Color.WHITE);
                jbtnConnect.setBackground(Color.RED);
            }
        } else {
            if (Start) {
                jbtnConnect.setText("Disconnect");
                jbtnConnect.setForeground(Color.BLACK);
                jbtnConnect.setBackground(Color.GREEN);

            } else {
                jbtnConnect.setText("Connect");
                jbtnConnect.setForeground(Color.WHITE);
                jbtnConnect.setBackground(Color.RED);
            }
        }

        jtfErroriCitire.setText(String.valueOf(totalErrors));
    }
});
timer.start();

詳細については、スイング タイマーの使用方法を参照してください。

于 2014-10-21T21:33:59.127 に答える
1

Swing は、Swing Event Dispatch Thread の外部からコンポーネントを更新すべきではないと述べていますが、それを強制するものではありません。すべての呼び出しがどのスレッドから来ているかを確認することは、まったく実用的ではありません。

また、スレッド化の問題が原因で発生する傾向がある問題の性質上 (一般的に)、マルチスレッド コードにバグがある場合に常に例外がスローされるとは考えないでください。これは、スレッド化の問題が原因でデッドロックまたはメモリ整合性エラーが頻繁に発生し、ほとんどの場合回復できないためです (通常は JVM 全体がクラッシュするだけです)。

于 2014-10-21T19:02:39.130 に答える