2009-08-07 8 views
0

私は理解できないことがあります。私のSwing GUIには「再生」と「一時停止」ボタンがあります。私はまた、 'ON'と 'OFF'状態を定義する静的変数を持っています。 (メインプログラムはGUIを生成する)。 'play'でclikingすると、私は静的変数の状態を 'ON'に変更し、GUIを変更するスレッドで時間のかかるプロセスを起動します。静的変数が 'ON'である限り、同じプロセスでループします。 「一時停止」をクリックすると、静的変数がOFFに変わります。 しかし、結果的に「遊び」GUIが凍結され、をクリックして:GUIは、私の「一時停止」ボタンと「一時停止」にすることはできません 私のGUIはフリーズされています

  • プロセスを更新しません

    私はEDTとSwingWorkerについて聞いたことがありますが、私はそれを行う簡単な方法があります。

    は、問題は、あなたがGUIを更新する責任が同じスレッド上で集中的、時間のかかる作業をやっているということです

  • 答えて

    6

    ...あなたの助けをありがとう、私の悪い英語を許します。 SwingWorkerを使用すると、時間のかかるタスクを個別の実行スレッドに移動できるため、UIスレッドはそのことを禁止されたままにしておくことができます。

    しかし、それはさらなる複雑性を追加します:親和性。 UIコンポーネントのメソッドを呼び出すには、通常、UIスレッドからメソッドを呼び出す必要があります。したがって、特別な機能を使用して、ワーカースレッドからUIスレッドに戻す必要があります。 SwingWorkerはこの機能も提供します。

    this documentationを読むことをお勧めします。

    0

    Swingのイベントハンドラでは、GUIがフリーズするため、長期実行プロセスを開始しないでください。 :)新しいスレッドで起動してください。ワーカースレッドからGUIを操作する予定がある場合(Swingはスレッドセーフではないため)、SwingWorkerを使用する必要があります。

    0

    これはかなり単純な理由です.Javaは時間のかかるプロセスに取り組んでいますが、GUIを更新することはできません。解決策:時間のかかるプロセスを別のスレッドで実行します。これをプログラムする方法はたくさんありますが、おそらくあなたのプログラムがどのように書かれているかには多少依存します。

    3

    EDTとSwingWorkersの動作を理解するには、Concurrency in Swingを読む必要があります。

    すべてのGUIアップデートはEDT上で実行されるため、GUIコンポーネントをクリックすると、このコールがEDT上で実行されます。これが時間のかかるプロセスである場合、EDTがGUIの更なる更新を実行するのをブロックします。したがって、あなたのGUIはフリーズしており、一時停止ボタンをクリックすることはできません。

    時間のかかるプロセスを別のスレッドで実行するには、SwingWorkerを使用する必要があります。上記のリンクは、これを行う方法を詳しく説明しています。

    0

    イベントディスパッチスレッド(EDT)は、GUIの読み取りまたは更新が安全な唯一のスレッドです。

    一時停止ボタンは、イベントディスパッチスレッドのオン/オフ変数を設定する必要があります。

    時間がかかる操作とループはではなく、がEDTに属している必要があります。 (ループは何もせずに変数をチェックし続けることも、すべてのCPUを簡単に食べることもできます。それ以外に何もする必要がない場合は、確認してからに電話してください(例えば100ms)。

    オン/オフ変数がOFFに設定されていることが証明できますが、常にONとして読み取られると、変数の値がEDTからワーカー・スレッドにコピーされていない可能性があります。 volatile、またはsynchronizeにアクセスするか、AtomicReferenceを使用するか、SwingUtilities.invokeAndWait()を使用してEDTで読み取ります。

    SwingWorkerおそらくここでは最も簡単な方法です。時間がかかる操作と、doInBackground()メソッドのオン/オフチェックと、done()メソッドのGUI更新を実装します。

    public enum State { 
        RUNNING, STOPPED 
    } 
    
    public class ThreadSafeStateModel { 
        private State state = State.STOPPED; 
    
        public synchronized void stop() { 
         state = State.STOPPED; 
        } 
    
        public synchronized void start() { 
         state = State.RUNNING; 
        } 
    
        public boolean isRunning() { 
         return state == State.RUNNING; 
        } 
    } 
    
    public class ExpensiveProcessWorker extends SwingWorker<Void, Void> { 
    
        private final ThreadSafeStateModel model; 
    
        public ExpensiveProcessWorker(ThreadSafeStateModel model) { 
         this.model = model; 
        } 
    
        @Override // Runs in background 
        protected Void doInBackground() throws Exception { 
         while (model.isRunning()) { 
          // do one iteration of something expensive 
         } 
         return null; 
        } 
    
        @Override // Runs in event dispatch thread 
        protected void done() { 
         // Update the GUI 
        } 
    } 
    
    public class StopButton extends JButton { 
        public StopButton(final ThreadSafeStateModel model) { 
         super(new AbstractAction("Stop") { 
          @Override 
          public void actionPerformed(ActionEvent e) { 
           model.stop(); 
          } 
         }); 
        } 
    } 
    
    public class StartButton extends JButton { 
        public StartButton(final ThreadSafeStateModel model) { 
         super(new AbstractAction("Start") { 
          @Override 
          public void actionPerformed(ActionEvent e) { 
           model.start(); 
           new ExpensiveProcessWorker(model).execute(); 
          } 
         }); 
        } 
    } 
    

    (多くは、実際のアプリケーションに応じて、これをクリーンアップするために行うことができるが、あなたのアイデアを得る。)

    +0

    すべてがOKで、完璧に動作しますあなたのデビッドありがとうございます。 しかし、ちょっとしたこと:私は、GUIをリフレッシュするためにdone()メソッドを使う必要はありませんでした。私はdoInBackground()メソッドで成功する。 あなたはそれについて考えていますか? –

    +0

    Jeremyさん、一般的には 'doInBackground()'のUIを更新することはよくありますが、あなたはそれに依存することはできません。 UIは常にイベントディスパッチスレッドに描画され、UIモデルは常にイベントディスパッチスレッドで読み込まれるため、イベントディスパッチスレッドのUIモデルに書き込む方が安全です。たとえば、 'TableModel'の行数がイベントディスパッチスレッドの外側で変更された場合、テーブルの描画時に' IndexOutOfBoundsException'が発生する可能性が高くなります。 –

    +0

    私は理解しています...もう少し多くのGUIアップデートを追加しようとしましたが、フリーズしました。この問題を解決するために、done()メソッドを使用してGUIを更新し、同じ初期データを持つ他のswingWorkerを作成しました。今は大丈夫です!どうもありがとうございました! –

    関連する問題