Java applet AWT-EventQueue-1异常

时间:2012-02-20 06:20:36

标签: java exception applet indexoutofboundsexception

我用java applet编写了一个简单的生命游戏实现。 以下是AppletModel.

的源代码

当我单击按钮以获得下一次迭代时,会抛出这些异常。

Z:\GameOfLife>appletviewer driver.html
Exception in thread "AWT-EventQueue-1" java.lang.ArrayIndexOutOfBoundsException:
 65
        at GameOfLifeApplet.mouseClicked(GameOfLifeApplet.java:63)
        at java.awt.Component.processMouseEvent(Component.java:6219)
        at java.awt.Component.processEvent(Component.java:5981)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4583)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4413)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThre    ad.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThre    ad.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

2 个答案:

答案 0 :(得分:3)

尝试使用此代码添加按钮一次,而不是每次调用paint()。请注意,如果您单击网格外部(而不是按钮),此源仍然会抛出AIOOBE,但这似乎是一个基本的逻辑错误,您应该在修复按钮后进行调查。

// <applet code='GameOfLifeApplet' width=580 height=650></applet>
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GameOfLifeApplet extends Applet implements MouseListener,ActionListener
{
  //the x and y coordinates to get the location of the clicked points
  private int xCo, yCo;
  private int diff_x, diff_y;
  private GameOfLife game = new GameOfLife();
  private Button nextButton = null;
  public void init()
  {
    setLayout(null);
    nextButton = new Button("Next Stage");
    diff_x = diff_y = 600 / game.getGridSize();
    nextButton.setLocation(250, 575);
    nextButton.setSize(120, 30);
    // add the button once only!
    add(nextButton);
    addMouseListener(this);
  }

  private void drawEmptyGrid(Graphics g)
  {
    g.setColor(Color.white);
    g.fillRect(0,0,600,600);
    g.setColor(Color.black);
    for(int i=0;i<game.getGridSize();++i)
    {
      g.drawLine(0,i*diff_x,600,i*diff_x);
      g.drawLine(i*diff_x,0,i*diff_x,600);
    }
    g.setColor(Color.white);
  }

  public void paint(Graphics g)
  {
    drawEmptyGrid(g);
    g.setColor(Color.red);
    for(int i=0;i<game.getGridSize();++i)
    {
      for(int j=0;j<game.getGridSize();++j)
      {
        if( game.grid[i][j] )
        {
          g.fillRect(i*diff_x,j*diff_y,diff_x,diff_y);
        }
      }
    }
    g.setColor(Color.white);
  }

 // This method will be called when the mouse has been clicked.
 public void mouseClicked (MouseEvent me) {

  // Save the coordinates of the click lke this.
  xCo = me.getX();
  yCo = me.getY();

  int x_init = xCo / diff_x;
  int y_init = yCo / diff_y;

  System.out.println(x_init + "x" + y_init);
  game.grid[x_init][y_init] = true;
  //show the results of the click
  repaint();

 }

 // This is called when the mous has been pressed
 public void mousePressed (MouseEvent me) {}

 // When it has been released
 // not that a click also calls these Mouse-Pressed and Released.
 // since they are empty nothing hapens here.
 public void mouseReleased (MouseEvent me) {}

 // This is executed when the mouse enters the applet. it will only
 // be executed again when the mouse has left and then re-entered.
 public void mouseEntered (MouseEvent me) {}

 // When the Mouse leaves the applet.
 public void mouseExited (MouseEvent me) {}

 public void actionPerformed(ActionEvent evt)
  {
  // Here we will ask what component called this method
    if (evt.getSource() == nextButton)
    {
      System.out.println("I got clicked!");
      game.nextIteration();
      repaint();
    }
  }

}

class GameOfLife
{
  private final int GRID_SIZE = 64;
  public boolean [][] grid = new boolean[GRID_SIZE][GRID_SIZE];
  //default constructor
  public GameOfLife()
  {
    for(int i=0;i<GRID_SIZE;++i)
    {
      for(int j=0;j<GRID_SIZE;++j)
    {
      grid[i][j] = false;
    }
    }
  }

  public int getGridSize()
  {
    return GRID_SIZE;
  }

  public int getLiveNeighbors(int i,int j)
  {
    int neighbors = 0;
    for( int tmp_i = i-1; tmp_i <= i+1; ++tmp_i )
    {
      for( int tmp_j = j-1; tmp_j <= j+1; ++tmp_j )
      {
        if( tmp_i < 0 || tmp_i >= GRID_SIZE || tmp_j < 0 || tmp_j >= GRID_SIZE )
        {}
        else
        {
          if( grid[tmp_i][tmp_j] )
          {
            neighbors++;
          }
        }
      }
    }
    return neighbors;
  }

  public void nextIteration()
  {
    boolean [][] newGrid = new boolean[GRID_SIZE][GRID_SIZE];

    for(int i=0;i<GRID_SIZE;++i)
    {
      for(int j=0;j<GRID_SIZE;++j)
      {
        newGrid[i][j] = grid[i][j];
      }
    }

    for( int i=0;i<GRID_SIZE;++i)
    {
      for( int j=0;j<GRID_SIZE;++j)
      {
        int my_neighbors = getLiveNeighbors(i,j);
        if( !newGrid[i][j] && my_neighbors == 3)
        {
          grid[i][j] = true;
        }

        else if( newGrid[i][j] && ( my_neighbors == 2 || my_neighbors == 3 ) )
        {
          grid[i][j] = true;
        }

        else
        {
          grid[i][j] = false;
        }
      }
    }
    System.out.println("Change of assignment");
  }
}

进一步提示

  1. 在本千年中不要使用AWT组件,而是使用Swing。
  2. 不要使用null布局。自定义渲染区域不需要它,并且应使用布局管理器(可能使用边框将其填充)来调整按钮的大小和位置。
  3. 更新

    此代码实现了上面“使用布局”的第二个建议,但将其作为练习让读者将组件更新为可能在本千年中使用的东西(即Swing)。

    从某种意义上来说'欺骗'下面的来源显示了GUI的自然尺寸。这在applet中很棘手,因为大小是由HTML设置的。但是将GUI放入基于Swing的JOptionPane中,它可以放在屏幕上,打包到其自然大小,只需几行代码即可。

    以下是“自然尺寸”的样子(我玩了一些数字,使GUI更小)。

    GameOfLifeApplet

    // <applet code='GameOfLifeApplet' width=320 height=350></applet>
    import java.awt.*;
    import java.awt.event.*;
    import java.applet.*;
    
    public class GameOfLifeApplet extends Applet implements ActionListener
    {
        private Button nextButton = null;
        private Ecosystem ecosystem;
    
        public void init()
        {
            add(getGui());
        }
    
        public Component getGui() {
            Panel gui = new Panel(new BorderLayout(3,3));
            ecosystem = new Ecosystem();
            gui.add(ecosystem, BorderLayout.CENTER);
            nextButton = new Button("Next Stage");
    
            Panel p = new Panel(new FlowLayout());
            p.add(nextButton);
            gui.add(p, BorderLayout.SOUTH);
                nextButton.addActionListener(this);
            return gui;
        }
    
        public void actionPerformed(ActionEvent evt)
        {
            // Here we will ask what component called this method
            if (evt.getSource() == nextButton)
            {
                System.out.println("I got clicked!");
                ecosystem.nextIteration();
                ecosystem.repaint();
            }
        }
    
        public static void main(String[] args) {
            GameOfLifeApplet gola = new GameOfLifeApplet();
            // quick cheat to get it on-screen (packed).
            javax.swing.JOptionPane.showMessageDialog(null,gola.getGui());
        }
    }
    
    class Ecosystem extends Panel implements MouseListener {
        private GameOfLife game = new GameOfLife();
        //the x and y coordinates to get the location of the clicked points
        private int xCo, yCo;
        private int diff_x, diff_y;
        private int size = 300;
    
        Ecosystem() {
            diff_x = diff_y = 600 / game.getGridSize();
            setPreferredSize(new Dimension(size,size));
            addMouseListener(this);
        }
    
        public void nextIteration() {
            game.nextIteration();
        }
    
        private void drawEmptyGrid(Graphics g)
        {
            g.setColor(Color.white);
            g.fillRect(0,0,size,size);
            g.setColor(Color.black);
            for(int i=0;i<game.getGridSize();++i)
            {
                g.drawLine(0,i*diff_x,size,i*diff_x);
                g.drawLine(i*diff_x,0,i*diff_x,size);
            }
            g.setColor(Color.white);
        }
    
        public void paint(Graphics g)
        {
            drawEmptyGrid(g);
            g.setColor(Color.red);
            for(int i=0;i<game.getGridSize();++i)
            {
                for(int j=0;j<game.getGridSize();++j)
                {
                    if( game.grid[i][j] )
                    {
                        g.fillRect(i*diff_x,j*diff_y,diff_x,diff_y);
                    }
                }
            }
            g.setColor(Color.white);
        }
    
        // This method will be called when the mouse has been clicked.
        public void mouseClicked (MouseEvent me) {
            Point point = me.getPoint();
    
            // Save the coordinates of the click lke this.
            xCo = (int)point.getX();
            yCo = (int)point.getY();
    
            int x_init = xCo / diff_x;
            int y_init = yCo / diff_y;
    
            System.out.println(x_init + "x" + y_init);
            game.grid[x_init][y_init] = true;
            //show the results of the click
            repaint();
        }
    
        // This is called when the mous has been pressed
        public void mousePressed (MouseEvent me) {}
    
        // When it has been released
        // not that a click also calls these Mouse-Pressed and Released.
        // since they are empty nothing hapens here.
        public void mouseReleased (MouseEvent me) {}
    
        // This is executed when the mouse enters the applet. it will only
        // be executed again when the mouse has left and then re-entered.
        public void mouseEntered (MouseEvent me) {}
    
        // When the Mouse leaves the applet.
        public void mouseExited (MouseEvent me) {}
    }
    
    class GameOfLife
    {
        private final int GRID_SIZE = 60;
        public boolean [][] grid = new boolean[GRID_SIZE][GRID_SIZE];
    
        //default constructor
        public GameOfLife()
        {
            for(int i=0;i<GRID_SIZE;++i)
            {
                for(int j=0;j<GRID_SIZE;++j)
                {
                    grid[i][j] = false;
                }
            }
        }
    
        public int getGridSize()
        {
            return GRID_SIZE;
        }
    
        public int getLiveNeighbors(int i,int j)
        {
            int neighbors = 0;
            for( int tmp_i = i-1; tmp_i <= i+1; ++tmp_i )
            {
                for( int tmp_j = j-1; tmp_j <= j+1; ++tmp_j )
                {
                    if( tmp_i < 0 || tmp_i >= GRID_SIZE || tmp_j < 0 || tmp_j >= GRID_SIZE )
                    {}
                    else
                    {
                        if( grid[tmp_i][tmp_j] )
                        {
                        neighbors++;
                        }
                    }
                }
            }
            return neighbors;
        }
    
        public void nextIteration()
        {
            boolean [][] newGrid = new boolean[GRID_SIZE][GRID_SIZE];
    
            for(int i=0;i<GRID_SIZE;++i)
            {
                for(int j=0;j<GRID_SIZE;++j)
                {
                    newGrid[i][j] = grid[i][j];
                }
            }
    
            for( int i=0;i<GRID_SIZE;++i)
            {
                for( int j=0;j<GRID_SIZE;++j)
                {
                    int my_neighbors = getLiveNeighbors(i,j);
                    if( !newGrid[i][j] && my_neighbors == 3)
                    {
                        grid[i][j] = true;
                    }
                    else if( newGrid[i][j] && ( my_neighbors == 2 || my_neighbors == 3 ) )
                    {
                        grid[i][j] = true;
                    }
                    else
                    {
                        grid[i][j] = false;
                    }
                }
            }
            System.out.println("Change of assignment");
        }
    }
    

    其他事项

    1. 代码将自定义绘画移动到Panel。这解决了直接绘制到顶级容器的常见问题。它还允许在不同的容器中轻松重用相同的GUI。在这种情况下,applet和'application'(通常放在框架中)都是JOptionPane。它现在被称为“混合applet /应用程序”(更容易测试)。
    2. 自定义绘制的组件Ecosystem(耸肩)通知布局它更喜欢的大小。这有助于我们避免设置任何内容的大小或范围。
    3. 按钮将完全按照需要大小。

答案 1 :(得分:2)

首先,我认为您正在阅读异常跟踪错误。例外是ArrayIndexOutOfBoundsException,发生在GameOfLifeApplet.java的第63行。您的应用是applet,或者线程AWT-EventQueue-1上发生的异常完全没有任何相关性。

根本原因是您未正确同步模型并查看网格中有多少单元格的概念。至少,在访问数组元素之前,应该考虑检查用户是否实际点击了网格内部。