Java applet awt-eventqueue-1 исключение
-
28-10-2019 - |
Вопрос
Я написал простую реализацию игры жизни с Java Applets. Вот исходный код для Апплет и Модель.
Когда я нажимаю кнопку, чтобы получить следующую итерацию, эти исключения брошены.
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)
Решение
Попробуйте этот код, который добавляет кнопку один раз, а не каждый вызов в 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");
}
}
Дополнительные советы
- Не используйте компоненты AWT в этом тысячелетии, вместо этого используйте качели.
- Не используйте
null
макеты. Пользовательская зона не нужна, и кнопка должна быть размещена и расположена с использованием менеджера макета (возможно, с границей, чтобы забить его).
Обновлять
Этот код реализует 2 -е предложение сверху «макет», но оставляет его в качестве упражнения для читателя, чтобы обновить компоненты до чего -то, что можно использовать в этом тысячелетии (т.е. качание).
Источник ниже «читы» в некотором смысле, чтобы показать графический интерфейс в его естественном размере. Это сложно сделать в апплете, так как размер установлен HTML. Но поместите графический интерфейс в свинг JOptionPane
И его можно поместить на экране, упакованный до его естественного размера, всего лишь в паре строк кода.
Вот как это выглядит в «естественном размере» (я играл с некоторыми числами, чтобы сделать графический интерфейс меньше).
// <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");
}
}
Другие вопросы
- Код перемещает пользовательскую живопись в
Panel
. Анкет Это обогащает общие проблемы рисования непосредственно в контейнер на верхнем уровне. Это также позволяет легко использовать один и тот же графический интерфейс в разных контейнерах. В этом случае как апплет, так и для «приложения» (которое обычно ставит в кадр),JOptionPane
. Анкет Теперь это то, что известно как «гибридный апплет/приложение» (проще для тестирования). - Нарисованный на заказ компонент
Ecosystem
(пожимает плечами) информирует макет, какого размера он предпочитает. Это помогает нам избежать необходимости устанавливать размер или границы всего. - Кнопка будет точно такой большой, как и должна.
Другие советы
Во -первых, я думаю, что вы неправильно читаете исключение. Исключением является ArrayIndexOutOfBoundsException
и встречается на линии 63 GameOfLifeApplet.java
. Анкет Что ваше приложение является апплетом или что исключение происходит в потоке AWT-EventQueue-1
не имеет никакого отношения вообще.
Основная причина заключается в том, что вы не синхронизировали модель и представление о том, сколько ячеек в вашей сетке. По крайней мере, вы должны рассмотреть возможность проверки того, что пользователь фактически щелкнул внутри сети, прежде чем получить доступ к элементу массива.