我正在尝试制作一个 GUI,它本质上有多个弹跳球。这些球是通过 JButton 添加的。我能够成功地创建 Ball 类,并仅用一个球在屏幕上制作动画,但是我无法通过使用按钮添加多个球。我尝试制作一个 ActionListener 来创建新线程并调用 SwingUtilities.InvokeLater,但它只会使 GUI 卡住。我尝试按照本指南了解如何使用 InvokeLater:http://www.javamex.com/tutorials/threads/invokelater.shtml
这是到目前为止我的代码。任何帮助表示赞赏。 (我意识到之前已经在这里问过弹跳球问题,但我无法理解回复中解释的方法,并且认为我应该在这里问而不是评论一个2年前的问题)
球类
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 );
}
});
}
}
最佳答案
我在设计中已经遇到的一个问题是,你正在制作 Ball
延伸JComponent
这已经在很多方面限制了你。你应该只做 Ball
一个简单的状态持有者/状态操纵类,具有动画和绘制球状态的方法。
然后只需一个 JComponent/JPanel 类来绘制球。在该类(class)中,您可以有 List<Ball>
您将在 paintComponent
中绘制方法。每当你想添加一个球时,只需添加 Ball
到列表中。
此外,您应该使用 javax.swing.Timer
,而不是使用单独的线程,这不应该通过绘画来完成(因为所有绘画都应该在 EDT 上完成)。用于计时动画。您可以在How to Use Swing Timers查看更多信息
您还可以看到上述方法的一堆示例 here和 here和 here和 here和 here和 here .
<小时/>更新
"Can you explain extending JComponent limits it? As for not using threads. How would I have multiple Ball objects animate independently? Doesn't that require multiple threads?"
- 您必须将多个组件添加到一个可见的“绘画表面”。因此基本上您必须将这些组件分层到表面,必须处理组件不透明度等问题。
- 您使用 javax.swing.Timer,在其中循环遍历 List 并调用每个球的 animate() 方法。
- 不。
请参阅我发布的链接中的示例。他们有使用计时器和对象列表的示例
这是一些代码片段的基本思想
球类
public class Ball {
public void draw(Graphics g) {}
public void animate() {}
}
BallPanel 类
public class BallPanel extends JPanel {
List<Ball> balls;
public BallPanel() {
Timer timer = new Timer(40, new ActionListener(){
public void actionPerformed(ActionEvent e) {
for (Ball ball : balls) {
ball.animate();
}
repaint();
}
});
timer.start();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Ball ball : ball ) {
ball.draw(g);
}
}
public void addBall(...) {
balls.add(new Ball(..));
}
}
关于java - 通过 InvokeLater 的多个动画 - Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23798441/