1

I want to update the board configuration by clicking on a JButton. However, sometimes the image is displayed on the frame. sometimes is not. Everytime there is a significant delay after I click on the button. I tried debugging and found there might be a endless loop in :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);
}

The endless loop is the while loop above.

Below is my listener class:

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();
    }
}

}

The basic idea is: I have an array of GUI. after each click, the listener will call all the GUIs within the array to update their configuration.

I also tried to update the board configuration within the GUI class directly, and it turns out to work well. I'm extremely confused! Can anyone help me out? Thanks!!

This is the main GUI class:

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();
}

}

See the last static main class? when I test it , all the update methods work well! But when I use listener to perform the method all. The updateBoard refuses to work.

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 毫秒,它会感觉有问题。事实上,100 毫秒是慢的,人类可以检测到 100 毫秒的延迟。

您可能需要重新评估您的设计,或者重用现有标签并简单地调用 setImage() 来更改它们。毕竟,这就是使用持久 UI 组件模型而不是使用原始绘制调用的全部意义所在。将它们实例化一次并重用。

您还使用新的 ImageIcon() 调用创建了数千张图像。您可能只需要一个图标,并且所有标签都指向同一个图像,这也将大大减少您的内存使用量。事实上,如果你听从我的建议,我想你会看到显着的速度和内存改进。

如果您找不到合适的方法来重用 JLabel,请考虑通过继承 JComponent 或 JPanel(如果您打算使用容器)来编写您自己的组件并覆盖 paintComponent()。我看到你没有使用 LayoutManager 而是选择使用绝对定位来做所有事情。如果您要进行绝对定位,您可能只想自己绘制。绘画是更底层的界面,但你有完全的控制权。您必须自己处理定位、自动换行。但是,它将非常有效,您可以从数据模型中重绘。

由于您所做的只是以网格模式绘制图像,因此我认为使用 Java2D api 绘制图像比实例化那么多 JLabel 和 ImageIcon 更好。如果您将 JPanel 子类化,您可以将 JComponents 添加到面板中以获取分数等内容。但是,请在 paintComponent() 方法中绘制网格。

于 2012-04-29T21:17:01.023 回答