Swing动画运行速度极慢 [英] Swing animation running extremely slow

查看:31
本文介绍了Swing动画运行速度极慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前使用 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 对象添加到 ArrayList 在我的 Modelcars代码>类.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() :

In addition it has the following method 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.

现在转到 View 类,我有一个 ** 单独的 ** 线程,它执行以下操作(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 类中有一个 ArrayListCar 对象,在 View 类还有一个表示汽车的 JPanel 对象的 ArrayList.我正在尝试将 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?

推荐答案

基于这个之前的answer,下面的例子模拟在矩形网格上随机移动的三辆出租车组成的车队.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();
            }
        });
    }
}

这篇关于Swing动画运行速度极慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆