Я пытаюсь создать графический интерфейс, в котором по существу есть несколько прыгающих мячей. Мячи добавляются через JButton. Мне удалось успешно создать класс Ball и анимировать его на экране только с одним мячом, однако мне не удалось добавить несколько мячей с помощью кнопки. Я попытался создать ActionListener, который создает новые потоки и вызывает SwingUtilities.InvokeLater, но это только заморозило графический интерфейс. Я пробовал следовать этому руководству по использованию InvokeLater: http://www.javamex.com/tutorials/threads/invokelater.shtml
Вот мой код до сих пор. Любая помощь приветствуется. (Я понимаю, что вопрос о прыгающем мяче задавался здесь раньше, но я не смог понять методы, описанные в ответах, и подумал, что задам здесь, а не прокомментирую вопрос двухлетней давности)
Класс мяча
package BouncingBall;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Random;
public class Ball extends JComponent
{
private double dx;
private double dy;
private double x;
private double y;
private Color color;
private Random rand = new Random();
private Ellipse2D.Double ball;
private final static int diam = 10;
private final static int xLim = BallFrame.FRAME_WIDTH-diam;
private final static int yLim = BallFrame.FRAME_HEIGHT-diam*7;
boolean xUpperBound = true;
boolean yUpperBound = true;
public Ball()
{
color = new Color(rand.nextFloat(),rand.nextFloat(),rand.nextFloat());
x = rand.nextInt(xLim);
y = rand.nextInt(yLim);
dx = rand.nextInt(9)+1;
dy = rand.nextInt(9)+1;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
public void draw(Graphics2D g2)
{
ball = new Ellipse2D.Double(x,y,diam,diam);
g2.setColor(color);
g2.fill(ball);
}
public void move()
{
if (((x+dx) < xLim) && xUpperBound)
x+=dx;
else if (x > 0)
{
xUpperBound = false;
x-=dx;
}
else
xUpperBound = true;
if (((y+dy) < yLim) && yUpperBound)
y+=dy;
else if (y > 0)
{
yUpperBound = false;
y-=dy;
}
else
yUpperBound = true;
}
public void animate()
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
while (true)
{
repaint();
move();
Thread.sleep(40);
}
}
catch (InterruptedException e)
{
System.out.println("Thread was interrupted!");
}
}
});
}
}
Класс BallFrame
package BouncingBall;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class BallFrame extends JFrame
{
public final static int FRAME_WIDTH = 800;
public final static int FRAME_HEIGHT = 600;
public BallFrame()
{
class ballListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent actionEvent)
{
Thread thread = new Thread()
{
public void run()
{
Ball temp = new Ball();
temp.animate();
add(temp);
}
};
thread.start();
}
}
setLayout(new BorderLayout());
JButton addBall = new JButton("Add Ball");
ActionListener listener = new ballListener();
addBall.addActionListener(listener);
add(addBall, BorderLayout.SOUTH);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
BallFrame frame = new BallFrame();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
});
}
}
Thread.sleep(40);
Это неправильный подход к анимации. Я также не хотел бы, чтобы классBall
расширялJComponent
и не пытался (сам) выполнять цикл рисования. Вместо этого используйте SwingTimer
в классеBallPanel
(новый) и вызовите методBall.move()
передBall.draw(g)
. используяpack()
. - person Andrew Thompson   schedule 22.05.2014