2012-02-29 7 views
1

私はスイングを使用してJavaで簡単なゲームを作ってるんだし、私のGUIが引き金になっているボタンを押した後(原因おそらくスレッドの問題に)散発的にフリーズとの問題を抱えていますJPanelsで切り替えます。GUIスレッドのJava(およびSwingUtilities)で

私は現在使用している実際のコードの詳細を持っている関連するスレッドhereを投稿しました(ただし、カウントダウンを更新して正常に動作します)。そのスレッドへの回答からは、SwingUtilities.invokeLater()またはinvokeAndWait()を使用して、私は問題を解決するために必要なものかもしれないように思えるが、私は私のコードでは、それはそれを実装する方法を正確に必要であるか、どこか分かりません。

私はスレッドについてその多くを知らないと私が得ることができる(好ましくはやや詳細といくつかのサンプルコード付き)任意のヘルプを使用することができます。さらなる詳細が役に立つかどうか私に教えてください。

+2

イベントスレッド(EDT)で 'Thread.sleep(...) 'を呼び出していますか? –

+0

いいえ、もうしません。私はそれ以前に行っていたコードの部分を書き直しました。 – scaevity

+0

@scaeコンポーネントへの応答を更新するコードを共有できますか? –

答えて

3

参照:Tutorial: Concurrency in Swing

一般的に言って、イベントディスパッチスレッドは、イベントキュー、時の処理1による一気飲み、シングルスレッドです。

SwingUtilities.invokeLater(..) 

は、このキューにRunnableを配置します。したがって、EDTがそれ以前のキューのすべてを終了すると、EDTによって処理されます(これは、キュー上のスリープが再描画のような他のイベントをブロックする理由です)。それは(通常はハックなど)に有用である状況がありますがそれは、EDT自体からinvokeLater(..)を呼び出すためには比較的珍しいです。私は過去6年間にSwingUtilities.invokeAndWait(..)のために正当な使用をしたとは思わない。たぶん一回。

javax.swing.Timerは一回または定期的に起動するように設定することができます。起動すると、EDTキューにイベントが記録されます。処理が集中する処理が必要な場合は、javax.swing.SwingWorkerを使用して別のスレッドで計算し、スレッドセーフな方法で結果を返すこともできます(これは比較的まれです)。

+0

説明をありがとう。私のコードで具体的に何が間違っているのか、それを修正する方法を理解するのを手伝ってください。(私はEDTがどこで始まって、どこで終了するのか、何かを追加するためにinvokeLater() EDTキューに)? – scaevity

+1

問題を示すSSCCE(http://sscce.org/)を作成してみてください。問題を拡大することで、自分で解決することができます。そうでなければ、ここに投稿すると、より具体的なアドバイスを得ることができます。 – kylewm

+0

ありがとう!私はそれをして、それは私がフリーズを引き起こしていた完全に無関係だった(GUI以外のもの)と思っていた何かだったことが判明した。 – scaevity

0

よく見ると、docsです。

がdoRun.run()がAWTイベントディスパッチスレッド 上で非同期に実行されるようにします:あなたのケースでは、これはどのようにSwingUtilities.invokeLater()作品や場所、それを使用することを説明しています。アプリケーション スレッドがGUIを更新する必要がある場合この方法は、使用されるべきです。

したがって、GUIを変更するアクションでは、GUIがフリーズしないようにするには、invokeLaterメソッドを使用する必要があります。

もう1つの優れたリソースは、Javaチュートリアルです。彼らはconcurrency in Swingをカバーしています。

+0

OK、私は、EDTキューにいくつかのビットを追加することでフリーズを止めるためにinvokeLater()を使用する必要があることを理解していますが、私のコードでどこでこれを行う必要がありますか?私はそれをいくつかの異なる場所に追加して実験しましたが、私の考えは固定されていないので、私は明らかに何かが足りなくなっています。 – scaevity

0

あなたはこの

Runnable doWorkRunnable = new Runnable() { 
    @Override 
    public void run() { 
     doWork(); 
    } 
}; 

のようなあなたのGUIのコードで定義されたいくつかの仕事を持っている、あなたはGUIスレッドでの作業を実行している新しいThread

Thread t = new Thread(doWorkRunnable); 
t.start(); 

にそれを取り付けることによって、それを呼び出す場合これはSwingアプリケーションで問題を引き起こします。

代わり

SwingUtilities.invokeLater(doWorkRunnable); 

(私はこれは使用方法の一例であり言及しましょう)これを試してこれはAWTイベントキューへのあなたのRunnable労働者を置き、そして以前のイベントが終了したら、それを実行します。

EDIT:ここでは、3から0までのカウントダウンを実行し、カウントダウン後に何をしたいのかを示す完全な例を示します。

public class TestFrame extends JFrame { 

    private JPanel contentPane; 
    private final Timer timer; 
    private TimerTask[] tasks; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       try { 
        TestFrame frame = new TestFrame(); 
        frame.setVisible(true); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public TestFrame() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setBounds(100, 100, 450, 300); 
     contentPane = new JPanel(); 
     contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); 
     contentPane.setLayout(new BorderLayout(0, 0)); 
     final JLabel lblCountdown = new JLabel(); 
     contentPane.add(lblCountdown, BorderLayout.NORTH); 
     JButton btnStart = new JButton("Start"); 
     contentPane.add(btnStart, BorderLayout.SOUTH); 

     timer = new Timer(); 
     tasks = new TimerTask[4]; 

     setContentPane(contentPane); 

     for (int i = 0; i < 4; i++) { 
      final int count = i; 
      tasks[i] = new TimerTask() { 
       public void run() { 
        EventQueue.invokeLater(new Runnable() { 
         @Override 
         public void run() { 
          lblCountdown.setText(count + ""); 
         } 
        }); 
       } 
      }; 
     } 

     btnStart.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 

       for (int i = 0; i < 4; i++) { 
        timer.schedule(tasks[4 - i - 1], (1000 * i), (1000 * (i + 1))); 
       } 
       // add another timer.schedule(TimerTask) 
       // to execute that "move to game screen" task 
       TimerTask taskGotoGame = new TimerTask() { 
        public void run() { 
         timer.cancel(); 
         JOptionPane.showMessageDialog(null, "Go to game", "Will now", JOptionPane.INFORMATION_MESSAGE); 
         System.exit(0); 
        } 
       }; 
       // and schedule it to happen after ROUGHLY 3 seconds 
       timer.schedule(taskGotoGame, 3000); 
      } 
     }); 

    } 

} 
+0

概要についてはありがたいですが、私はおそらくinvokeLater()を使用する必要があることをすでに知っていました。どこにいても私のコードに固有のヘルプを探しています。 Thread.sleep()を使用して停止したので、問題は発生していません)。自分の質問にリンクした投稿の実際のコード/プログラムの概要を見て、より適切なフィードバックをくれますか? – scaevity

+0

私はいくつかの場所で、プログラムがJPanelsを正常に切り替えるような状況でカウントダウンが正常に機能していると言いました。問題は、最終的にカウントダウンが表示されるようになるパネルを取得していることです(また、その前にボタンを押してもGUIがフリーズしないようにする)。これは実際にはカウントダウンコードにアクセスせずにパネルを追加して表示するようにしても問題ありません(levelPanel.start()コールをコメントアウトすると、それはまだフリーズしています)。 – scaevity

+0

私は実用的な例全体を追加しました。 'JLabel'を特定の番号に更新する' Runnable'を持つ 'TimerTask'と、' Timer'を止めてカウントダウン後にやりたいことをやり遂げるもう一つの終了タスクを定義します。私は「ゲームパネルに切り替える」部分を省いています。主な方法を読んで、何をすべきかを発見してください。 –

0

スレッドとGUIの現在/メインスレッドを処理するWorkerThreadクラスを作成しました。私はGUIアプリケーションをWorkerThreadのconstruct()メソッドに入れました。イベントが発生してXXXServerが起動し、すべてのスレッドがアクティブになり、GUIがスムーズに動かなくなりました。見てみましょう。 /** * アクションイベント * * @see java.awt.event.ActionListener#のactionPerformed(java.awt.event.ActionEvent) */ ます。public void actionPerformedの(のActionEvent AE){ log.info(」 actionPerformed begin ... "+ ae.getActionCommand());

try { 
     if (ae.getActionCommand().equals(btnStart.getText())) { 
      final int portNumber = 9990; 
      try { 

       WorkerThread workerThread = new WorkerThread(){ 
        public Object construct(){ 

         log.info("Initializing the XXXServer ..."); 
         // initializing the Socket Server 
         try { 
          XXXServer xxxServer = new XXXServer(portNumber); 
          xxxServer.start(); 
          btnStart.setEnabled(false);        
         } catch (IOException e) { 
          // TODO Auto-generated catch block 
          log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage()); 
          e.printStackTrace(); 
         } 
         return null; 
        } 
       };workerThread.start(); 
       } catch (Exception e) { 
        log.info("actionPerformed() Start button ERROR..." + e.getMessage()); 
        e.printStackTrace(); 
      } 


     } else if (ae.getActionCommand().equals(btnStop.getText())) { 
      log.info("Exit..." + btnStop.getText()); 
      closeWindow(); 
     } 

    } catch (Exception e) { 
     log 
      .info("Error in ServerGUI actionPerformed===" 
       + e.getMessage()); 
    } 

} 
関連する問題