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

물론 Event Dispatch Thread에는 무한 루프가 있습니다! 그것이 작동하는 방식입니다. 이벤트가 도착하자마자 무한 루프로 전달합니다. Swing 코드를 표시하고 있습니다 ** ** 코드는 무엇입니까? –

답변

3

코드가 여기에 문제가 될 수 있습니다. 다시 EventDispatchThread는 무한 루프를 사용하여 이벤트를 펌프 처리하여 실제 문제로는 무시할 수 있도록합니다. 문제는 removeAll()을 사용하고 단추를 누를 때마다 수천 개의 레이블을 인스턴스화하는 것입니다 (13 x 13 x 89-65? 4056은 무엇입니까!). 그건 불필요하게 많은 재 작업과 재 레이아웃을 야기 할 것입니다. 그래서 효율적이지 않기 때문에 보게되는 일시 중지는 코드의 성능입니다. 시도해보십시오.

코드가 10-100ms를 초과하면 이상이 발생합니다. 실제로 100ms는 느린쪽에 있고 인간은 100ms의 지연을 감지 할 수 있습니다.

디자인을 다시 평가하고 기존 레이블을 다시 사용하고 setImage()를 호출하여 변경해야 할 수도 있습니다. 결국 그것은 원시 페인트 호출을 사용하는 것보다 영구 UI 구성 요소 모델을 사용하는 요지입니다. 한 번 인스턴스화하고 다시 사용하십시오.

또한 새 ImageIcon() 호출로 수천 개의 이미지를 만들 수 있습니다. 아마 하나의 아이콘 만 있으면되고 모든 레이블이 동일한 이미지를 가리 키도록하여 메모리 사용량을 크게 줄일 수 있습니다. 실제로 당신이 나의 충고를 따르는 경우에 나는 당신이 극적인 속도 및 기억 향상을 볼 것이라는 점을 생각한다.

JLabel을 재사용 할 수있는 적절한 방법을 찾지 못하면 JComponent 또는 JPanel (컨테이너를 사용하려는 경우)을 서브 클래 싱하여 paintComponent()를 재정 의하여 고유 한 구성 요소를 작성하는 것을 고려하십시오. LayoutManager를 사용하지 않고 대신 절대 위치 지정을 사용하여 모든 작업을 수행하는 것을 확인합니다. 절대 위치 지정을 수행하려는 경우 직접 페인트를 칠할 수도 있습니다. 회화는 더 낮은 수준의 인터페이스이지만, 당신은 모든 권한을가집니다. 당신은 포지셔닝, 단어 감싸기, 모든 것을 처리해야합니다. 그러나 매우 효율적이며 데이터 모델에서 다시 그릴 수 있습니다.

당신이하고있는 모든 작업은 그리드 패턴으로 이미지를 그리는 것이므로 Java2D API로 그 이미지를 그리는 것이 많은 JLabel과 ImageIcon을 인스턴스화하는 것보다 더 좋은 아이디어라고 생각합니다.JPanel을 서브 클래스 화한다면, JComponents를 스코어 등의 패널에 추가 할 수 있습니다. 그러나 paintComponent() 메소드로 그리드를 그립니다.

+0

내가 여기에 시간을 계산하는 노력은 결과입니다 타일이 배치됩니다 (1,1) UpdateBoard 타이밍 : 0 MS 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