簡體   English   中英

當我點擊按鈕執行方法調用時,我的GUI卡住了

[英]Somehow my GUI got stuck when I click on a button to perform a method call

我想通過點擊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拒絕工作。

所以看起來你的代碼可能就是這里的問題。 同樣,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()調用創建數千個圖像。 您可能只需要一個圖標,只需將所有標簽指向同一圖像,這將大大減少您的內存使用量。 事實上,如果你遵循我的建議,我認為你會看到顯着的速度和內存改進。

如果找不到合適的方法來重用JLabel,那么考慮通過繼承JComponent或JPanel(如果您打算使用容器)並覆蓋paintComponent()來編寫自己的組件。 我看到你沒有使用LayoutManager而是選擇使用絕對定位來做所有事情。 如果你要做絕對定位,你可能想要自己畫畫。 繪畫是更低級別的界面,但你有完全的控制。 你必須自己處理定位,自動換行。 但是,它將非常高效,您可以從數據模型重繪。

由於您所做的一切都是以網格模式繪制圖像,我認為使用Java2D api繪制圖像比實例化許多JLabel和ImageIcons更好。 如果你是JPanel的子類,你可以在面板中添加JComponents來獲取得分等等。但是,在paintComponent()方法中繪制網格。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM