1

JButton をクリックしてボード構成を更新したいと考えています。ただし、フレームに画像が表示される場合があります。そうでない場合もあります。ボタンをクリックした後、毎回かなりの遅延があります。デバッグを試みたところ、:EventDispatchThread.class に無限ループがある可能性があることがわかりました。

(this is the class from java library)
void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
    addEventFilter(filter);
    doDispatch = true;
while (doDispatch && cond.evaluate()) {
        if (isInterrupted() || !pumpOneEventForFilters(id)) {
            doDispatch = false;
        }
    }
    removeEventFilter(filter);
}

無限ループは上記の while ループです。

以下は私のリスナークラスです:

public class PlaceListener implements ActionListener{

private JTextField _text1;
private Board board;
private JTextField _text2;
private ArrayList<NewGUI> _guiList;
private int _numOfPlayer;
public PlaceListener(JTextField text1, JTextField text2, Board b,ArrayList<NewGUI> guiList, int numOfPlayer,NewGUI gui)
{
    _text1 = text1;
    _text2 = text2;
    board = b;
    _guiList = guiList;
    _numOfPlayer = numOfPlayer;
}
@Override
public void actionPerformed(ActionEvent e) {

    int x = Integer.parseInt(_text1.getText());
    int y = Integer.parseInt(_text2.getText());

    board.Place(y, x);

    for(int j = 0;j<_numOfPlayer;j++)
    {
          NewGUI gui = _guiList.get(j);
          gui.updateBoard();
          gui.updateCurrTile();
          gui.updateScore();
          gui.updateTurn();
    }
}

}

基本的な考え方は次のとおりです。GUI の配列があります。クリックするたびに、リスナーは配列内のすべての GUI を呼び出して構成を更新します。

また、GUI クラス内でボード構成を直接更新しようとしましたが、うまく機能することがわかりました。私は非常に混乱しています!誰でも私を助けることができますか?ありがとう!!

これはメインの GUI クラスです。

public class NewGUI {
private JFrame _frame;
    private Board _board;
private JLabel _turnLabel;
private JTextArea _textArea;
private JLabel _currTileLabel;
private JPanel _boardPanel;
public NewGUI(Board board,int whos,ArrayList<NewGUI> guiList,int numOfPlayer)
{
    _board = board;



   _frame = new JFrame("Metro");    


   //turnLabel
   _turnLabel = new JLabel();
   _turnLabel.setText("Current player is: "+_board.getCurrPlayer());
   _turnLabel.setSize(110, 40);
   _turnLabel.setLocation(0, 0);
   _frame.add(_turnLabel);


   //mainPlayerLabel
   JLabel mainPlayerLabel = new JLabel("Player"+whos+" 's window");
   mainPlayerLabel.setSize(120, 20);
   mainPlayerLabel.setLocation(400,0);
   _frame.add(mainPlayerLabel);

   //JTextArea to hold scores
   _textArea = new JTextArea();
   _textArea.setText(_board.displayScore());
   _textArea.setSize(160,140);
   _textArea.setLocation(730, 170);
   _frame.add(_textArea);

   _boardPanel = new JPanel();
   _boardPanel.setSize(560, 560);
   _boardPanel.setLocation(170, 80);
   _boardPanel.setLayout(null);
 //  _boardPanel.setBackground(java.awt.Color.BLACK);
   _frame.add(_boardPanel);


   //Button Panel
   JPanel buttonPanel = new JPanel();
   buttonPanel.setSize(300, 150);
   buttonPanel.setLocation(280, 650);
   buttonPanel.setBackground(java.awt.Color.blue);
   _frame.add(buttonPanel);

   //Current Tile Label
   _currTileLabel = new JLabel("Current Tile is: ");
   _currTileLabel.setIcon(new ImageIcon(NewGUI.class.getResource(_board.getCurrTile().tileType()+".png")));
   _currTileLabel.setSize(170, 60);
   _currTileLabel.setLocation(20, 620);
   _frame.add(_currTileLabel);


   //2 input JTextField
   JTextField text1 = new JTextField(3);
   JTextField text2 = new JTextField(3);
   text1.setSize(20, 20);
   text2.setSize(20, 20);
   text1.setLocation(620, 680);
   text2.setLocation(640, 680);
   _frame.add(text1);
   _frame.add(text2);


   //Buttons
   JButton buttonPlace = new JButton("Place");
   JButton buttonCommit = new JButton("Commit");
   JButton buttonRemove = new JButton("Remove");
   JButton buttonResign = new JButton("Resign");

   buttonPlace.addActionListener(new PlaceListener(text1,text2,_board,guiList,numOfPlayer,this));
   buttonCommit.addActionListener(new CommitListener(_board,guiList,numOfPlayer));
   buttonRemove.addActionListener(new RemoveListener(_board,guiList,numOfPlayer,this));
   buttonResign.addActionListener(new ResignListener(_board));

   //Add buttons onto buttonPanel
   buttonPanel.add(buttonCommit);
   buttonPanel.add(buttonResign);
   buttonPanel.add(buttonRemove);
   buttonPanel.add(buttonPlace);
   buttonPanel.setLayout(new FlowLayout());

   _frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   _frame.setSize(900, 900);
   _frame.setLayout(null);
   _frame.setVisible(true);

}


public void updateBoard()
{
    _boardPanel.removeAll();
    //scan and refresh the board configuration.
    for(int i = 1; i<13;i++)
    {
        for(int j = 1; j<13;j++)
        {
            if(_board.getBoard()[i][j]!=null)
            {

              for(int e = 65; e<89;e++){
                  char temp = (char)e;
                  if(_board.getBoard()[i][j].tileType()==temp)
                  {

                JLabel label = new JLabel(new ImageIcon(NewGUI.class.getResource(temp+".png")));
                label.setSize(40,40);
                label.setLocation(40+(i-1)*40, 40+(j-1)*40);
                _boardPanel.add(label);
                break;
                  }
            }
        }
        }
    }
}

public void updateTurn()
{
    _turnLabel.setText("Current player is: "+_board.getCurrPlayer());
}
public void updateScore()
{
    _textArea.setText(_board.displayScore());
}
public void updateCurrTile()
{
    _currTileLabel.setIcon(new ImageIcon(NewGUI.class.getResource(_board.getCurrTile().tileType()+".png")));
}


public static void main(String[] args)
{
    Board b = new Board(3,true);
    NewGUI gui = new NewGUI(b,1);
    b.Place(4, 4);
    b.Commit();
    b.Place(12, 12);
    b.Commit();
    b.Place(3, 3);
    gui.updateBoard();
}

}

最後の静的メイン クラスを参照してください。テストすると、すべての更新方法がうまく機能します。しかし、リスナーを使用してメソッドをすべて実行すると。updateBoard は機能しません。

4

1 に答える 1

3

したがって、ここではコードが問題になっている可能性があります。この場合も、EventDispatchThreadは無限ループを使用してイベントをポンピングするように機能するため、これは明らかであり、実際の問題として無視できます。問題は、removeAll()を使用し、ボタンをクリックするたびに数千のラベルをインスタンス化することです(13 x 13 x 89-65とは何ですか?4056!)。これにより、多くの再描画とリレーアウトが不必要に発生します。したがって、表示される一時停止は、効率的ではないため、コードのパフォーマンスです。これを試してみてはいけません:

public void updateBoard() {
    long start = System.currentTimeInMillis();

    // existing code goes here

    long duration = System.currentTimeMillis() - start;
    System.out.printf("UpdateBoard timing: %,d ms%n", duration );
}

コードが10〜100ミリ秒を超えると、グリッチが発生します。実際、100msは遅い側にあり、人間は100msの遅延を検出できます。

おそらく、デザインを再評価し、既存のラベルを再利用し、単にsetImage()を呼び出してそれらを変更する必要があります。結局のところ、生のペイント呼び出しを使用するよりも、永続的なUIコンポーネントモデルを使用することが重要です。それらを一度インスタンス化して再利用します。

また、新しいImageIcon()呼び出しを使用して何千もの画像を作成しています。おそらく必要なアイコンは1つだけで、すべてのラベルが同じ画像を指すようにするだけで、メモリ使用量も大幅に削減されます。実際、私のアドバイスに従えば、劇的な速度とメモリの改善が見られると思います。

JLabelを再利用する適切な方法が見つからない場合は、JComponentまたはJPanel(コンテナーの使用を計画している場合)をサブクラス化して独自のコンポーネントを作成し、paintComponent()をオーバーライドすることを検討してください。LayoutManagerを使用しておらず、代わりに絶対位置を使用してすべてを実行することを選択しているようです。絶対測位を行う場合は、自分でペイントすることをお勧めします。ペイントはより低レベルのインターフェイスですが、完全に制御できます。ポジショニング、ワードラップ、すべてを自分で処理する必要があります。ただし、これは非常に効率的であり、データモデルから再描画できます。

グリッドパターンで画像を描画するだけなので、Java2D APIを使用して画像を描画する方が、多くのJLabelやImageIconをインスタンス化するよりも良いアイデアだと思います。JPanelをサブクラス化すると、スコアなどのJComponentsをパネルに追加できます。ただし、paintComponent()メソッドでグリッドを描画します。

于 2012-04-29T21:17:01.023 に答える