gpt4 book ai didi

java - 使用计时器对 Java 线条图进行动画处理

转载 作者:行者123 更新时间:2023-12-02 04:28:25 25 4
gpt4 key购买 nike

我试图在按下按钮后在面板上绘制两个圆圈并用一条线连接它们。到目前为止(除了调整线路的位置)这是可以的。但是,我想使用计时器为其设置动画。第一个圆圈应该出现,然后线条逐渐显露出来,最后是第二个圆圈。

我看过很多计时器的例子,但我似乎无法让它为我工作。我一定是误会了什么。

这是球类(每个圆圈):

package twoBalls;

import java.awt.Color;
import java.awt.Point;

public class Ball {

private int x;
private int y;
private int r;
private Color color;
private Point location;
private Ball parent;

public Ball(int x, int y, int r) {
this.x = x;
this.y = y;
this.r = r;
Point p = new Point(x, y);
setLocation(p);
}

public void setParent(Ball b) {
parent = b;
}

public Ball getParent() {
return parent;
}

public void setx(int x) {
this.x = x;
}

public void sety(int y) {
this.y = y;
}

public int getx() {
return x;
}

public int gety() {
return y;
}

public int getr() {
return r;
}

public void setPreferedSize() {

}

public void setLocation(Point p) {
setx(p.x);
sety(p.y);
location = p;
}

public Point getLocation() {
return location;
}

public void setColor(Color color) {
this.color = color;
}

public Color getColor() {
return color;
}

}

然后是将球存储在 arrayList 中的类。我认为这就是实际绘图和计时器应该发生的地方。我试图使用计时器将线的起点和终点设置为相同,并增加终点直到它位于应有的位置。我可能是在跟踪,但这就是意图!

我已经更改了这个类,现在可以输入 while 循环中的 if 语句,因为我现在正在比较不同的点。但这条线仍然没有被划定。

package twoBalls;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.Timer;

public class BallsArray extends JPanel implements ActionListener {

private ArrayList<Ball> balls;
private Timer timer;
private final int DELAY = 25;
private int xDest;
private int yDest;
private Point dest;
private Point starts;
private int xStart;
private int yStart;

public BallsArray() {
balls = new ArrayList<Ball>();
timer = new Timer(DELAY, this);
yDest = 0;
xDest = 0;
dest = new Point(xDest, yDest);
starts = new Point(xStart, yStart);

}

public void setDestXY(int x, int y) {
xDest = x;
yDest = y;
dest = new Point(xDest, yDest);
setDest(dest);
}

public void setDest(Point p) {
dest = p;

}

public Point getDest() {
return dest;
}

public void setStartsXY(int x, int y) {
xStart = x;
yStart = y;
starts = new Point(xStart, yStart);
setStarts(starts);
}

public void setStarts(Point p) {
starts = p;
}

public Point getStarts() {
return starts;
}

public void addBall(Ball b) {
balls.add(b);
}

public void addBall(int x, int y, int r) {
balls.add(new Ball(x, y, r));

}

public void paintComponent(Graphics g) {

Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < balls.size(); i++) {
if (i == 0) {
paintBall(balls.get(0), g2);
}
if (i != 0) {
int j = i - 1;
Ball bp = balls.get(j);
Ball bc = balls.get(i);
bc.setParent(bp);
paintLine(bc, g2);
paintBall(bc, g2);
}

}
}

public void paintBall(Ball b, Graphics2D g2d) {
Ellipse2D circ = new Ellipse2D.Float(b.getx(), b.gety(), b.getr(),
b.getr());
g2d.draw(circ);
}

public void paintLine(Ball b, Graphics2D g2d) {
timer.start();
if (b != null && b.getLocation() != null) {
Ball parent = b.getParent();
if (parent != null) {
g2d.setColor(Color.GRAY);
if (parent.getLocation() != null && b.getLocation() != null) {
setDest(parent.getLocation());
setStarts(parent.getLocation());
g2d.draw(new Line2D.Float(starts, dest));
}
}
}

}

@Override
public void actionPerformed(ActionEvent e) {
// Not sure what I need to do here
// increment second location somehow
// Point s = getStarts();
Point p = getDest();
Point t = this.getLocation();
while (p != t) {

if (p.x != t.x && p.y != t.y) {
System.out.println("hello");
int x = dest.x;
int y = dest.y;
x++;
y++;
setDestXY(x, y);
p = getDest();
repaint();
} else if (p.x == t.x && p.y != t.y) {
System.out.println("part 2");
int y = dest.y;
y++;
setDestXY(dest.x, y);
p = getDest();
repaint();
} else if (p.x != t.x && p.y == t.y) {
System.out.println("part 3");
int x = dest.x;
x++;
setDestXY(x, dest.y);
p = getDest();
repaint();
}
repaint();
}
}
}

我在网上得到了很多帮助才走到这一步,我担心我现在超出了我的深度!我不确定下面的 EventQueue/run 部分。这是进行所有设置的类:

package twoBalls;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class Display implements ActionListener {

private JFrame frame;
private JButton button;
private BallsArray b;

public static void main(String[] args) {

EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Display ex = new Display();

}
});

}

public Display() {
b = new BallsArray();
frame = new JFrame();
frame.setSize(800, 500);
frame.setTitle("Show balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
button = new JButton("New Ball");
frame.add(button, BorderLayout.SOUTH);
frame.setVisible(true);
button.addActionListener(this);

}

@Override
public void actionPerformed(ActionEvent e) {

Ball ball1 = new Ball(100, 100, 50);
b.addBall(ball1);
b.addBall(200, 200, 50);
frame.add(b, BorderLayout.CENTER);
frame.revalidate();
frame.repaint();

}
}

目前它绘制了两个圆圈,但根本没有绘制线条。

最佳答案

当您制作动画时,使用model / view / controller pattern会有所帮助。 .

这是我根据您的代码创建的 GUI。

Show Balls Animation

我简化了你的 Ball 类。这就是定义球所需的全部内容。

package twoBalls;

import java.awt.Color;
import java.awt.Point;

public class Ball {

private final int radius;

private final Color color;

private final Point center;

public Ball(int x, int y, int radius, Color color) {
this(new Point(x, y), radius, color);
}

public Ball(Point center, int radius, Color color) {
this.center = center;
this.radius = radius;
this.color = color;
}

public int getRadius() {
return radius;
}

public Color getColor() {
return color;
}

public Point getCenter() {
return center;
}

}

我创建了 GUIModel 类来保存 GUI 所需的所有信息。这将模型与 View 分开。

package twoBalls;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class GUIModel {

private double direction;
private double distance;

private List<Ball> balls;

private Point lineStartPoint;
private Point lineEndPoint;

public GUIModel() {
this.balls = new ArrayList<>();
}

public void addBall(Ball ball) {
this.balls.add(ball);
}

public List<Ball> getBalls() {
return balls;
}

public void calculatePoints() {
this.lineStartPoint = balls.get(0).getCenter();
this.lineEndPoint = balls.get(1).getCenter();

this.distance = Point.distance(lineStartPoint.x, lineStartPoint.y,
lineEndPoint.x, lineEndPoint.y);
this.direction = Math.atan2(lineEndPoint.y - lineStartPoint.y,
lineEndPoint.x - lineStartPoint.x);
}

public Point getCurrentPoint(int pos, int total) {
double increment = distance / total;
double length = increment * pos;

double x = lineStartPoint.x + Math.cos(direction) * length;
double y = lineStartPoint.y - Math.sin(direction) * length;

x = Math.round(x);
y = Math.round(y);

return new Point((int) x, (int) y);
}

public Point getLineStartPoint() {
return lineStartPoint;
}

}

该类保存两个 Ball 实例,并计算线的长度和方向,分为总增量。

现在我们已经定义了模型类,让我们看看 View 类。第一个是您的 Display 类。

package twoBalls;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Display implements Runnable {

private GUIModel guiModel;

private JFrame frame;

public static void main(String[] args) {
EventQueue.invokeLater(new Display());
}

public Display() {
this.guiModel = new GUIModel();
Ball ball1 = new Ball(150, 200, 50, Color.BLUE);
Ball ball2 = new Ball(450, 200, 50, Color.GREEN);
guiModel.addBall(ball1);
guiModel.addBall(ball2);
guiModel.calculatePoints();
}

@Override
public void run() {
frame = new JFrame();
frame.setTitle("Show Balls Animation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());

DrawingPanel drawingPanel = new DrawingPanel(guiModel);
panel.add(drawingPanel, BorderLayout.CENTER);

panel.add(createButtonPanel(drawingPanel), BorderLayout.SOUTH);

frame.add(panel);

frame.pack();
frame.setVisible(true);
}

private JPanel createButtonPanel(DrawingPanel drawingPanel) {
JPanel panel = new JPanel();

JButton startButton = new JButton("Start Animation");
startButton.addActionListener(new StartAnimation(drawingPanel));
panel.add(startButton);

return panel;
}

public class StartAnimation implements ActionListener {

private DrawingPanel drawingPanel;

public StartAnimation(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
}

@Override
public void actionPerformed(ActionEvent event) {
LineRunnable runnable = new LineRunnable(drawingPanel);
new Thread(runnable).start();
}

}

}

Display 类的构造函数设置 GUI 模型。

Display 类的 run 方法构造 GUI,并启动动画。

看看我如何分离模型和 View 。

StartAnimation 类是您的 Controller 。当您左键单击 JButton 时,它会启动动画。稍后我将讨论 LineRunnable 类。

接下来,让我们看一下DrawingPanel类。

package twoBalls;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;

import javax.swing.JPanel;

public class DrawingPanel extends JPanel {

private static final long serialVersionUID = -3709678584255542338L;

private boolean drawLine;

private int pos;
private int total;

private GUIModel guiModel;

public DrawingPanel(GUIModel guiModel) {
this.guiModel = guiModel;
this.drawLine = false;
this.setPreferredSize(new Dimension(600, 400));
}

public boolean isDrawLine() {
return drawLine;
}

public void setDrawLine(boolean drawLine) {
this.drawLine = drawLine;
}

public void setPos(int pos) {
this.pos = pos;
repaint();
}

public void setTotal(int total) {
this.total = total;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

Graphics2D g2d = (Graphics2D) g;

for (Ball ball : guiModel.getBalls()) {
g2d.setColor(ball.getColor());
Point center = ball.getCenter();
int radius = ball.getRadius();
g2d.fillOval(center.x - radius, center.y - radius, radius + radius,
radius + radius);
}

if (isDrawLine()) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(5.0F));
Point a = guiModel.getLineStartPoint();
Point b = guiModel.getCurrentPoint(pos, total);
g2d.drawLine(a.x, a.y, b.x, b.y);
}
}

}

这个 View 类唯一做的事情就是绘制球和线。计算线长度的责任属于模型。

我在这里设置了首选大小,并使用 Display 类中的 pack 方法来获取 JFrame 的大小。您通常想知道绘图区域的尺寸,而不是整个窗口的尺寸。

最后,让我们看一下 LineRunnable 类。这是控制动画的类。

package twoBalls;

import java.awt.EventQueue;

public class LineRunnable implements Runnable {

private int total;

private DrawingPanel drawingPanel;

public LineRunnable(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
this.total = 240;
}

@Override
public void run() {
setDrawLine();
for (int pos = 0; pos <= total; pos++) {
setPos(pos);
sleep(50L);
}
}

private void setDrawLine() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
drawingPanel.setDrawLine(true);
drawingPanel.setTotal(total);
}
});
}

private void setPos(final int pos) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
drawingPanel.setPos(pos);
}
});
}

private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {

}
}

}

在run方法中,我们将线分为240段,每50毫秒绘制一段。 GUI 需要 12 秒来绘制这条线。如果您愿意,您可以使用这些数字。

for循环是一个经典的动画循环。首先,更新模型,这是我通过绘图面板进行的。然后你就 sleep 了。

此动画循环在与 GUI 线程不同的线程上运行。这可以保持 GUI 的响应能力。由于循环在不同的线程上运行,因此我们必须使用 invokeLater 方法在事件调度线程上进行绘制。

希望这对您有帮助。分而治之。不要让一个类做不止一件事。

关于java - 使用计时器对 Java 线条图进行动画处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31837162/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com