0

JButtonをクリックしてボードの設定を更新したい。ただし、画像がフレームに表示されることがあります。時々そうではありません。私がボタンをクリックすると、毎回かなりの遅延があります。私は、デバッグを試してみましたが、中に無限ループがあるかもしれませんが見つかりました:EventDispatchThread.classボタンをクリックしてメソッド呼び出しを実行すると、何とか私のGUIが固まった

(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は動作しません。

+0

「ボード構成」とは何ですか?あなたのクラスはEventDispatchThread.classですか?このメソッド呼び出しを実行するJButtonのActionListenerを表示できますか? –

+0

これは 'cond'が常にtrueであることを意味します。isInterrupted()は常にfalseで、' pumpOneEventForFilters(id) 'は常にfalseです。ループの中でそれを中断して、それが機能するかどうか確認してください。 –

+2

はい、もちろんイベントディスパッチスレッドには無限ループがあります!そういうものが動作する方法です。イベントが到着すると、無限ループで送出されます。 Swingコードを表示しています**あなたの**コードはどうですか? –

答えて

3

あなたのコードがここで問題になるようです。再度EventDispatchThreadは無限ループを使用してイベントをポンピングするので、実際の問題としては無視できます。問題は、removeAll()を使用し、ボタンをクリックするたびに数千のラベルをインスタンス化することです(13 x 13 x 89-65?4056とは何ですか)。それは不必要に多くの再描画と再レイアウトを引き起こします。効率的ではないので、あなたが見るポーズはコードのパフォーマンスです。これを試してみると信じてはいけません:

コードが10〜100msを超える場所にいる場合は、不便な気分になります。実際、100msは遅い側にあり、人間は100msの遅延を検出することができます。

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

また、新しいImageIcon()コールで数千のイメージを作成しています。おそらく1つのアイコンしか必要とせず、すべてのラベルが同じイメージを指しているだけで、メモリ使用量も劇的に減少します。実際、私のアドバイスに従えば、スピードと記憶の劇的な改善が見られるでしょう。

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

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

+0

私はここで時間をカウントしようとした結果である:タイルが中に配置されている(1,1) UpdateBoardタイミング:0ミリ秒 UpdateBoardタイミング:0 MS コミット正常 UpdateBoardタイミング:16のMS UpdateBoardタイミング:0 MS したがって、問題はremoveAll()ではありません。私はクラスを持っていますが、ボードが[] []配列の場合、nullの場合、パネルに何も配置されません。だから、それは多くのラベルを生成しません。私はまだ問題が何かを知りません... – whileone

+0

actionPerformedコード全体のタイミングコードをラップします。あなたが大きなジャンプを見たら、それを分離することができます。 updateBoardは各プレーヤーに呼び出されるので、複数の13 * 13 *(89-65)* numberOfPlayersが必要です。それはあなたのボードがより多くのアイテムを持つようになるにつれて、ゆっくりとより遅くなる可能性があるためです。実際に私たちが思ったより悪いことです。 – chubbsondubs

+0

+1「CellRendererPane」、[ここに表示](http://stackoverflow.com/a/7776211/230513)、[flyweight](http://en.wikipedia.org/wiki/Flyweight_pattern)として使用できます。レンダラ。 – trashgod

関連する問題