摇摆动画运行速度极慢 [英] Swing animation running extremely slow
问题描述
我的当前动画有问题,我正在使用Java Swing运行。这是一个离散事件模拟,基于文本的模拟工作正常,我只是在连接模拟到GUI输出时遇到问题。
I have a problem with my current animation that I'm running using Java Swing. It is a discrete event simulation and the text based simulation is working fine, I'm just having problems connecting the simulating to GUI output.
对于这个例子,我将有10个要模拟的汽车。汽车用 JPanels
表示,我稍后会详细说明。
For this example I will have 10 cars to be simulated. The cars are represented by JPanels
which I will elaborate on in a few moments.
所以考虑一下,事件process_car_arrival 。每次计划执行此事件时,我都会将 Car
对象添加到名为<$ c $的 ArrayList
中c> cars 在我的 Model
类中。 Car
类具有以下相关属性:
So consider, the event process_car_arrival. Every time this event is scheduled for execution, I'm adding a Car
object to an ArrayList
called cars
in my Model
class. The Car
class has the following relevant attributes:
Point currentPos; // The current position, initialized in another method when knowing route.
double speed; // giving the speed any value still causes the same problem but I have 5 atm.
RouteType route; // for this example I only consider one simple route
此外它还有以下方法 move()
:
switch (this.route) {
case EAST:
this.currentPos.x -= speed;
return this.currentPos;
.
.
.
//only above is relevant in this example
这一切都很好。所以从理论上讲,汽车沿着一条直线道路从东向西穿过,因为我只是为每辆想要移动的汽车调用 move()
方法。
This is all well. so in theory the car traverses along a straight road from east to west as I just invoke the move()
method for each car I want to move.
返回process_car_arrival事件。添加Car对象后,它会在 View
类中调用方法 addCarToEast()
。这会在从东到西的道路开始时添加一个JPanel。
Returning to the process_car_arrival event. After adding a Car object it invokes a method addCarToEast()
in the View
class. This adds a JPanel at the start of the road going from east to west.
现在转到查看
类我有一个**单独的**线程,它执行以下操作(run()方法):
Going to the View
class now I have a ** separate** thread which does the following ( the run() method) :
@Override
public void run() {
while (true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!cars.isEmpty()) {
cars.get(i).setLocation(
new Point(getModel.getCars().get(i).move()));
if (i == cars.size() - 1) {
i = 0;
} else {
i++;
}
}
}
}
上面确实首先将汽车顺利地从东向西移动。但是在有3-4辆车移动之后,它最终变得非常缓慢,当我有10辆车移动时,它最终移动得很少。
The above does move the car from east to west smoothly at first. But after there is 3-4 cars moving it just ends up being EXTREMELY slow and when I have 10 cars moving it just ends up moving very little.
只是为了清理,目前在 Model
类中,有一个 ArrayList
Car
对象,并且在 View
类中还有一个 ArrayList
JPanel
代表汽车的对象。我正在尝试将 Car
对象与 JPanels
进行匹配,但我显然正在做一些事情。工作。
Just to clear up, at the moment in the Model
class there's an ArrayList
of Car
objects, and in the View
class there is also an ArrayList
of JPanel
objects representing the cars. I'm trying to match the Car
objects to the JPanels
, but I'm obviously doing a cra**y job.
我怀疑我做的事情非常低效,但我不知道是什么。我想最初也许它正在访问 ArrayList
,我想这会让它变得非常慢。
I suspect that I'm doing something insanely inefficient but I don't know what. I thought initially maybe it's accessing the ArrayList
so much which I guess would make it really slow.
任何指向我能改变什么才能让它顺利运行?
Any pointers to what I can change to make it run smoothly?
推荐答案
基于此前的答案,下面的例子模拟了一个在矩形网格上随机移动的三个驾驶室的车队。 javax.swing.Timer
以5 Hz的频率驱动动画。模型和视图紧密耦合在 CabPanel
中,但动画可能会提供一些有用的见解。特别是,您可能会增加驾驶室数量或降低计时器延迟。
Based on this previous answer, the example below simulates a fleet of three cabs moving randomly on a rectangular grid. A javax.swing.Timer
drives the animation at 5 Hz. The model and view are tightly coupled in CabPanel
, but the animation may provide some useful insights. In particular, you might increase the number of cabs or lower the timer delay.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* @see https://stackoverflow.com/a/14887457/230513
* @see https://stackoverflow.com/questions/5617027
*/
public class FleetPanel extends JPanel {
private static final Random random = new Random();
private final MapPanel map = new MapPanel();
private final JPanel control = new JPanel();
private final List<CabPanel> fleet = new ArrayList<CabPanel>();
private final Timer timer = new Timer(200, null);
public FleetPanel() {
super(new BorderLayout());
fleet.add(new CabPanel("Cab #1", Hue.Cyan));
fleet.add(new CabPanel("Cab #2", Hue.Magenta));
fleet.add(new CabPanel("Cab #3", Hue.Yellow));
control.setLayout(new GridLayout(0, 1));
for (CabPanel cp : fleet) {
control.add(cp);
timer.addActionListener(cp.listener);
}
this.add(map, BorderLayout.CENTER);
this.add(control, BorderLayout.SOUTH);
}
public void start() {
timer.start();
}
private class CabPanel extends JPanel {
private static final String format = "000000";
private final DecimalFormat df = new DecimalFormat(format);
private JLabel name = new JLabel("", JLabel.CENTER);
private Point point = new Point();
private JLabel position = new JLabel(toString(point), JLabel.CENTER);
private int blocks;
private JLabel odometer = new JLabel(df.format(0), JLabel.CENTER);
private final JComboBox colorBox = new JComboBox();
private final JButton reset = new JButton("Reset");
private final ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int ds = random.nextInt(3) - 1;
if (random.nextBoolean()) {
point.x += ds;
} else {
point.y += ds;
}
blocks += Math.abs(ds);
update();
}
};
public CabPanel(String s, Hue hue) {
super(new GridLayout(1, 0));
name.setText(s);
this.setBackground(hue.getColor());
this.add(map, BorderLayout.CENTER);
for (Hue h : Hue.values()) {
colorBox.addItem(h);
}
colorBox.setSelectedIndex(hue.ordinal());
colorBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Hue h = (Hue) colorBox.getSelectedItem();
CabPanel.this.setBackground(h.getColor());
update();
}
});
reset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
point.setLocation(0, 0);
blocks = 0;
update();
}
});
this.add(name);
this.add(odometer);
this.add(position);
this.add(colorBox);
this.add(reset);
}
private void update() {
position.setText(CabPanel.this.toString(point));
odometer.setText(df.format(blocks));
map.repaint();
}
private String toString(Point p) {
StringBuilder sb = new StringBuilder();
sb.append(Math.abs(p.x));
sb.append(p.x < 0 ? " W" : " E");
sb.append(", ");
sb.append(Math.abs(p.y));
sb.append(p.y < 0 ? " N" : " S");
return sb.toString();
}
}
private class MapPanel extends JPanel {
private static final int SIZE = 16;
public MapPanel() {
this.setPreferredSize(new Dimension(32 * SIZE, 32 * SIZE));
this.setBackground(Color.lightGray);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
g2d.setColor(Color.gray);
for (int col = SIZE; col <= w; col += SIZE) {
g2d.drawLine(col, 0, col, h);
}
for (int row = SIZE; row <= h; row += SIZE) {
g2d.drawLine(0, row, w, row);
}
for (CabPanel cp : fleet) {
Point p = cp.point;
int x = SIZE * (p.x + w / 2 / SIZE) - SIZE / 2;
int y = SIZE * (p.y + h / 2 / SIZE) - SIZE / 2;
g2d.setColor(cp.getBackground());
g2d.fillOval(x, y, SIZE, SIZE);
}
}
}
public enum Hue {
Cyan(Color.cyan), Magenta(Color.magenta), Yellow(Color.yellow),
Red(Color.red), Green(Color.green), Blue(Color.blue),
Orange(Color.orange), Pink(Color.pink);
private final Color color;
private Hue(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
private static void display() {
JFrame f = new JFrame("Dispatch");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FleetPanel fp = new FleetPanel();
f.add(fp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
fp.start();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
display();
}
});
}
}
这篇关于摇摆动画运行速度极慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!