2

私はプロジェクトのためにチェスプログラムを作っています。ボードの側面に移動履歴ボックスを追加しようとしています。移動履歴は正常に機能し、データはテキスト領域に適切に送信されますが、AIが移動について考えている間、JTextArea内のテキストは消えます。

public void aiMove(){
  if (!playing){ return; }
  paintImmediately(0,0,totalX,totalY);
  ai = eve.getMove(chess,wtm,aiOut);   //text disappears here
  chess.makeMove(ai);
  wtm = !wtm;
  humanMove = true;
  writeMove(ai);                   //updates move history, text reappears here
  playing = stillPlaying();
  repaint();
}

private void writeMove(Move move){
  char c = "abcdefgh".charAt(7-move.fromY);
  char h ="abcdefgh".charAt(7-move.toY);
  String s = Character.toString(c)+(move.fromX+1)+" - "+Character.toString(h)+(move.toX+1)+"  ";
  if (!wtm){
    String q = chess.getFullMove()+".  "+s+"  ";
    moves.setText(moves.getText()+q);
  }
  else {
    moves.setText(moves.getText()+s+"\n");
  }
}

これが何が起こっているかの印刷画面です。 http://s13.postimage.org/mh7hltfk7/JText_Area_disappear.png


解決済みすべての返信 に感謝します。aiMove()を変更して、スレッドを作成しました。これが私がしたことです。

試み#3...スイングはまだ私にはとても異質です。writeMoveをgetMoveに変更したくなかった、または人間のターンを少し書き直さなければならなかった。プロジェクトは基本的に完了しているので、できるだけ多くの作業を避けようとしています:) GUIはとにかく完全にオプションであり、楽しみのために、そして少しスイングを学ぶためにやっていただけです。

public void aiMove(){
  if (!playing){ return; }
  if (!aiThread.isAlive()){
    aiThread = new Thread(){
      public void run(){
        ai = eve.getMove(chess,wtm,aiOut);
        chess.makeMove(ai);
        wtm = !wtm;
        humanMove = true;
        SwingUtilities.invokeLater(new Runnable(){
          public void run(){
            writeMove(ai);
          }
        });
        repaint();
        playing = stillPlaying();
      }
    };
    aiThread.start();
  }
}

また、以前の問題も修正されました。「a」キーを押したままにすると(強制ai移動)、多くの強制ai移動がキューに入れられます。今ではそれは起こりません。

4

1 に答える 1

6

問題は、AIの考え方がCPUに集中し、時間がかかることです。したがって、これは長時間実行されるタスクと見なされます。GUIイベントディスパッチスレッドで長時間実行するタスクを実行しないでください。UIがフリーズしているように見え、タスクの終了後にのみ更新が表示されます。

幸い、使用できるアプローチは2つあります。

  • チュートリアルで述べられているように、SwingWorkerを使用してください。

SwingWorkerサブクラスは、バックグラウンドタスクが終了したときにイベントディスパッチスレッドで自動的に呼び出されるメソッドdoneを定義できます。

SwingWorkerはjava.util.concurrent.Futureを実装します。このインターフェースにより、バックグラウンドタスクは他のスレッドに戻り値を提供できます。このインターフェイスの他のメソッドを使用すると、バックグラウンドタスクをキャンセルし、バックグラウンドタスクが終了したかキャンセルされたかを検出できます。

バックグラウンドタスクは、SwingWorker.publishを呼び出して、イベントディスパッチスレッドからSwingWorker.processを呼び出すことにより、中間結果を提供できます。

バックグラウンドタスクは、バインドされたプロパティを定義できます。これらのプロパティを変更するとイベントがトリガーされ、イベント処理メソッドがイベントディスパッチスレッドで呼び出されます。

  • Threadまたは、AI思考用に個別に作成し、setTextコールをラップインしますSwingUtilities.invokeLater(...);

    Thread t=new Thread(new Runnable() {
         @Override
         public void run() {
        }
    });
    t.start();
    

アップデート

MadProgrammersのコメント(+1)を読んだ後、SwingUtilities.invokeLater(..)ブロックを介してEDTでGUI/Swingコンポーネントを作成/操作することを忘れないでください。詳細については、こちらをご覧ください。

更新2:

その編集は要点を打ち負かしています。SwingUtilititesブロック内のEDTでの唯一の呼び出しはsetText、Swingコンポーネントを操作するコードまたは少なくとも唯一のコードである必要があります。

public void aiMove(){
  if (!playing){ return; } 
  if (!aiThread.isAlive()){  //originally initialized by constructor
    aiThread = new Thread(){
      public void run(){
            ai = eve.getMove(chess,wtm,aiOut);
            chess.makeMove(ai);
            wtm = !wtm;
            humanMove = true;
        SwingUtilities.invokeLater(new Runnable(){
          public void run(){
            writeMove(ai);
          }
        });
        repaint();
        playing = stillPlaying();
      }
    };
    aiThread.start();
  }
}
于 2012-12-22T19:59:55.483 に答える