当前位置: 首页 > 知识库问答 >
问题:

Swing动画运行极慢

徐昊焜
2023-03-14

我当前使用Java Swing运行的动画有一个问题。这是一个离散事件模拟,基于文本的模拟运行良好,我只是在将模拟连接到GUI输出时遇到问题。

对于这个例子,我将有10辆汽车进行模拟。这些汽车由JPanels表示,我将在稍后详细介绍。

因此,请考虑事件进程\u car\u到达。每次计划执行此事件时,我都会将一个Car对象添加到我的Model类中名为carsArrayList中。Car类具有以下相关属性:

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()方法。

返回过程车到达事件。添加一个Car对象后,它调用视图类中的方法addCarToEast()。这在从东到西的道路开始处增加了一个JPanel。

现在转到视图类,我有一个**单独的**线程,它执行以下操作(run()方法):

@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辆车移动时,它就会变得非常慢。

只是想澄清一下,目前在模型类中有一个ArrayListCar对象,在视图类中还有一个ArrayListJPanel对象代表汽车。我试图将汽车对象与JPanels匹配,但我显然是在做一项艰难的工作。

我怀疑我在做一些非常低效的事情,但我不知道是什么。我最初认为它可能访问ArrayList太多了,我想这会让它变得非常慢。

有什么我可以改变的地方让它顺利运行吗?

共有2个答案

郝峰
2023-03-14

我忍不住。。。

我有500辆车在屏幕上运行,几乎没有减速(这不是最快的...大约200-300辆已经很不错了...

这使用面板来表示每辆车。如果你想获得更好的性能,你可能需要考虑使用某种背景缓冲区。

public class TestAnimation10 {

    public static void main(String[] args) {
        new TestAnimation10();
    }

    public TestAnimation10() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                final TrackPane trackPane = new TrackPane();
                JSlider slider = new JSlider(1, 500);
                slider.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        trackPane.setCongestion(((JSlider)e.getSource()).getValue());
                    }
                });
                slider.setValue(5);

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(trackPane);
                frame.add(slider, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

            }
        });
    }

    public class TrackPane extends JPanel {

        private List<Car> cars;
        private int maxCars = 1;

        private List<Point2D[]> points;

        private Ellipse2D areaOfEffect;

        public TrackPane() {

            points = new ArrayList<>(25);

            cars = new ArrayList<>(25);
            setLayout(null);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    Rectangle bounds = areaOfEffect.getBounds();
                    List<Car> tmp = new ArrayList<>(cars);
                    for (Car car : tmp) {
                        car.move();
                        if (!bounds.intersects(car.getBounds())) {
                            remove(car);
                            cars.remove(car);
                        }
                    }
                    updatePool();
                    repaint();
                }
            });

            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();

            updateAreaOfEffect();
        }

        protected void updateAreaOfEffect() {
            double radius = Math.max(getWidth(), getHeight()) * 1.5d;
            double x = (getWidth() - radius) / 2d;
            double y = (getHeight() - radius) / 2d;
            areaOfEffect = new Ellipse2D.Double(x, y, radius, radius);
        }

        @Override
        public void invalidate() {
            super.invalidate();
            updateAreaOfEffect();
        }

        protected void updatePool() {
            while (cars.size() < maxCars) {
//            if (cars.size() < maxCars) {
                Car car = new Car();
                double direction = car.getDirection();
                double startAngle = direction - 180;

                double radius = areaOfEffect.getWidth();
                Point2D startPoint = getPointAt(radius, startAngle);

                int cx = getWidth() / 2;
                int cy = getHeight() / 2;

                double x = cx + (startPoint.getX() - car.getWidth() / 2);
                double y = cy + (startPoint.getY() - car.getHeight() / 2);
                car.setLocation((int)x, (int)y);

                Point2D targetPoint = getPointAt(radius, direction);

                points.add(new Point2D[]{startPoint, targetPoint});

                add(car);

                cars.add(car);
            }
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            Font font = g.getFont();
            font = font.deriveFont(Font.BOLD, 48f);
            FontMetrics fm = g.getFontMetrics(font);
            g.setFont(font);
            g.setColor(Color.RED);
            String text = Integer.toString(maxCars);
            int x = getWidth() - fm.stringWidth(text);
            int y = getHeight() - fm.getHeight() + fm.getAscent();
            g.drawString(text, x, y);
            text = Integer.toString(getComponentCount());
            x = getWidth() - fm.stringWidth(text);
            y -= fm.getHeight();
            g.drawString(text, x, y);
            text = Integer.toString(cars.size());
            x = getWidth() - fm.stringWidth(text);
            y -= fm.getHeight();
            g.drawString(text, x, y);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public void setCongestion(int value) {
            maxCars = value;
        }
    }

    protected static Point2D getPointAt(double radius, double angle) {

        double x = Math.round(radius / 2d);
        double y = Math.round(radius / 2d);

        double rads = Math.toRadians(-angle);

        double fullLength = Math.round((radius / 2d));

        double xPosy = (Math.cos(rads) * fullLength);
        double yPosy = (Math.sin(rads) * fullLength);

        return new Point2D.Double(xPosy, yPosy);

    }

    public class Car extends JPanel {

        private double direction;
        private double speed;
        private BufferedImage background;

        public Car() {
            setOpaque(false);
            direction = Math.random() * 360;
            speed = 5 + (Math.random() * 10);
            int image = 1 + (int) Math.round(Math.random() * 5);
            try {
                String name = "/Car0" + image + ".png";
                background = ImageIO.read(getClass().getResource(name));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            setSize(getPreferredSize());
//            setBorder(new LineBorder(Color.RED));
        }

        public void setDirection(double direction) {
            this.direction = direction;
            revalidate();
            repaint();
        }

        public double getDirection() {
            return direction;
        }

        public void move() {
            Point at = getLocation();
            at.x += (int)(speed * Math.cos(Math.toRadians(-direction)));
            at.y += (int)(speed * Math.sin(Math.toRadians(-direction)));
            setLocation(at);
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = super.getPreferredSize();
            if (background != null) {
                double radian = Math.toRadians(direction);
                double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian));
                int w = background.getWidth(), h = background.getHeight();
                int neww = (int) Math.floor(w * cos + h * sin);
                int newh = (int) Math.floor(h * cos + w * sin);
                size = new Dimension(neww, newh);
            }
            return size;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - background.getWidth()) / 2;
            int y = (getHeight() - background.getHeight()) / 2;
            g2d.rotate(Math.toRadians(-(direction + 180)), getWidth() / 2, getHeight() / 2);
            g2d.drawImage(background, x, y, this);
            g2d.dispose();

//            Debug graphics...
//            int cx = getWidth() / 2;
//            int cy = getHeight() / 2;
//
//            g2d = (Graphics2D) g.create();
//            g2d.setColor(Color.BLUE);
//            double radius = Math.min(getWidth(), getHeight());
//            Point2D pointAt = getPointAt(radius, direction);
//            g2d.draw(new Ellipse2D.Double(cx - (radius / 2d), cy - (radius / 2d), radius, radius));
//            
//            double xo = cx;
//            double yo = cy;
//            double xPos = cx + pointAt.getX();
//            double yPos = cy + pointAt.getY();
//            
//            g2d.draw(new Line2D.Double(xo, yo, xPos, yPos));
//            g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4));
//            g2d.dispose();
        }
    }
}

更新为优化版本

我对汽车对象的创建做了一些代码优化(还有改进的余地),并对图形输出进行了扩展(使其看起来更漂亮)。

基本上,现在,当一辆车离开屏幕时,它被放置在一个池中。当需要另一辆车时,如果可能的话,它会从池中拉出来,否则就会制造一辆新车。这减少了创建和销毁如此多(相对)短暂的对象的开销,这使得内存使用更加稳定。

在我的2560x1600分辨率屏幕上(最大化运行),我能够让4500辆汽车同时运行。一旦对象创建减少,它就会相对平稳地运行(它永远不会运行得像10辆一样好,但它没有受到速度显着降低的影响)。

public class TestAnimation10 {

    public static void main(String[] args) {
        new TestAnimation10();
    }

    public TestAnimation10() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                final TrackPane trackPane = new TrackPane();
                JSlider slider = new JSlider(1, 5000);
                slider.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        trackPane.setCongestion(((JSlider) e.getSource()).getValue());
                    }
                });
                slider.setValue(5);

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(trackPane);
                frame.add(slider, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

            }
        });
    }

    public class TrackPane extends JPanel {

        private List<Car> activeCarList;
        private List<Car> carPool;
        private int maxCars = 1;
        private List<Point2D[]> points;
        private Ellipse2D areaOfEffect;

        public TrackPane() {

            points = new ArrayList<>(25);

            activeCarList = new ArrayList<>(25);
            carPool = new ArrayList<>(25);
            setLayout(null);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    Rectangle bounds = areaOfEffect.getBounds();
                    List<Car> tmp = new ArrayList<>(activeCarList);
                    for (Car car : tmp) {
                        car.move();
                        if (!bounds.intersects(car.getBounds())) {
                            remove(car);
                            activeCarList.remove(car);
                            carPool.add(car);
                        }
                    }
                    updatePool();
                    repaint();
                }
            });

            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();

            updateAreaOfEffect();
        }

        protected void updateAreaOfEffect() {
            double radius = Math.max(getWidth(), getHeight()) * 1.5d;
            double x = (getWidth() - radius) / 2d;
            double y = (getHeight() - radius) / 2d;
            areaOfEffect = new Ellipse2D.Double(x, y, radius, radius);
        }

        @Override
        public void invalidate() {
//            super.invalidate();
            updateAreaOfEffect();
        }

        protected void updatePool() {
            if (activeCarList.size() < maxCars) {
                int count = Math.min(maxCars - activeCarList.size(), 10);
                for (int index = 0; index < count; index++) {
                    Car car = null;

                    if (carPool.isEmpty()) {
                        car = new Car();
                    } else {
                        car = carPool.remove(0);
                    }

                    double direction = car.getDirection();
                    double startAngle = direction - 180;

                    double radius = areaOfEffect.getWidth();
                    Point2D startPoint = getPointAt(radius, startAngle);

                    int cx = getWidth() / 2;
                    int cy = getHeight() / 2;

                    double x = cx + (startPoint.getX() - car.getWidth() / 2);
                    double y = cy + (startPoint.getY() - car.getHeight() / 2);
                    car.setLocation((int) x, (int) y);

                    Point2D targetPoint = getPointAt(radius, direction);

                    points.add(new Point2D[]{startPoint, targetPoint});

                    add(car);

                    activeCarList.add(car);
                }
            }
        }

        @Override
        public void paint(Graphics g) {
            super.paint(g);
            Font font = g.getFont();
            font = font.deriveFont(Font.BOLD, 48f);
            FontMetrics fm = g.getFontMetrics(font);
            g.setFont(font);
            g.setColor(Color.RED);
            String text = Integer.toString(maxCars);
            int x = getWidth() - fm.stringWidth(text);
            int y = getHeight() - fm.getHeight() + fm.getAscent();
            g.drawString(text, x, y);
            text = Integer.toString(getComponentCount());
            x = getWidth() - fm.stringWidth(text);
            y -= fm.getHeight();
            g.drawString(text, x, y);
            text = Integer.toString(activeCarList.size());
            x = getWidth() - fm.stringWidth(text);
            y -= fm.getHeight();
            g.drawString(text, x, y);
            text = Integer.toString(carPool.size());
            x = getWidth() - fm.stringWidth(text);
            y -= fm.getHeight();
            g.drawString(text, x, y);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public void setCongestion(int value) {
            maxCars = value;
        }

        @Override
        public void validate() {
        }

        @Override
        public void revalidate() {
        }

//        @Override
//        public void repaint(long tm, int x, int y, int width, int height) {
//        }
//
//        @Override
//        public void repaint(Rectangle r) {
//        }
//        public void repaint() {
//        }
        @Override
        protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
            System.out.println(propertyName);
//            // Strings get interned...
//            if (propertyName == "text"
//                            || propertyName == "labelFor"
//                            || propertyName == "displayedMnemonic"
//                            || ((propertyName == "font" || propertyName == "foreground")
//                            && oldValue != newValue
//                            && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
//
//                super.firePropertyChange(propertyName, oldValue, newValue);
//            }
        }

        @Override
        public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
        }
    }

    protected static Point2D getPointAt(double radius, double angle) {

        double x = Math.round(radius / 2d);
        double y = Math.round(radius / 2d);

        double rads = Math.toRadians(-angle);

        double fullLength = Math.round((radius / 2d));

        double xPosy = (Math.cos(rads) * fullLength);
        double yPosy = (Math.sin(rads) * fullLength);

        return new Point2D.Double(xPosy, yPosy);

    }

    public class Car extends JPanel {

        private double direction;
        private double speed;
        private BufferedImage background;

        public Car() {
            setOpaque(false);
            direction = Math.random() * 360;
            speed = 5 + (Math.random() * 10);
            int image = 1 + (int) Math.round(Math.random() * 5);
            try {
                String name = "/Car0" + image + ".png";
                background = ImageIO.read(getClass().getResource(name));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            setSize(getPreferredSize());
//            setBorder(new LineBorder(Color.RED));
        }

        public void setDirection(double direction) {
            this.direction = direction;
            revalidate();
            repaint();
        }

        public double getDirection() {
            return direction;
        }

        public void move() {
            Point at = getLocation();
            at.x += (int) (speed * Math.cos(Math.toRadians(-direction)));
            at.y += (int) (speed * Math.sin(Math.toRadians(-direction)));
            setLocation(at);
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = super.getPreferredSize();
            if (background != null) {
                double radian = Math.toRadians(direction);
                double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian));
                int w = background.getWidth(), h = background.getHeight();
                int neww = (int) Math.floor(w * cos + h * sin);
                int newh = (int) Math.floor(h * cos + w * sin);
                size = new Dimension(neww, newh);
            }
            return size;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            int x = (getWidth() - background.getWidth()) / 2;
            int y = (getHeight() - background.getHeight()) / 2;
            g2d.rotate(Math.toRadians(-(direction + 180)), getWidth() / 2, getHeight() / 2);
            g2d.drawImage(background, x, y, this);
            g2d.dispose();

//            Debug graphics...
//            int cx = getWidth() / 2;
//            int cy = getHeight() / 2;
//
//            g2d = (Graphics2D) g.create();
//            g2d.setColor(Color.BLUE);
//            double radius = Math.min(getWidth(), getHeight());
//            Point2D pointAt = getPointAt(radius, direction);
//            g2d.draw(new Ellipse2D.Double(cx - (radius / 2d), cy - (radius / 2d), radius, radius));
//            
//            double xo = cx;
//            double yo = cy;
//            double xPos = cx + pointAt.getX();
//            double yPos = cy + pointAt.getY();
//            
//            g2d.draw(new Line2D.Double(xo, yo, xPos, yPos));
//            g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4));
//            g2d.dispose();
        }

        @Override
        public void invalidate() {
        }

        @Override
        public void validate() {
        }

        @Override
        public void revalidate() {
        }

        @Override
        public void repaint(long tm, int x, int y, int width, int height) {
        }

        @Override
        public void repaint(Rectangle r) {
        }

        @Override
        public void repaint() {
        }

        @Override
        protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
//            System.out.println(propertyName);
//            // Strings get interned...
//            if (propertyName == "text"
//                            || propertyName == "labelFor"
//                            || propertyName == "displayedMnemonic"
//                            || ((propertyName == "font" || propertyName == "foreground")
//                            && oldValue != newValue
//                            && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
//
//                super.firePropertyChange(propertyName, oldValue, newValue);
//            }
        }

        @Override
        public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
        }
    }
}

ps-我应该加上1-我10个月大的孩子喜欢它2-它让我想起了奔波的工作:P

龙承德
2023-03-14

基于这个前面的答案,下面的示例模拟了一个由三辆驾驶室组成的车队在矩形网格上随机移动。一个javax.swing.Timer以5 Hz驱动动画。模型和视图在CabPanel中紧密耦合,但动画可能会提供一些有用的见解。特别是,您可能会增加驾驶室的数量或降低计时器延迟。

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();
            }
        });
    }
}
 类似资料:
  • 问题内容: 我在制作JApplet并遇到动画问题。 这是我的代码: 有了它,就没有动画:在循环过程中什么也没发生,repaint()方法似乎只在精灵停止移动后才起作用。 我只想将Swing用于此目的,关于如何进行的任何想法? 谢谢阅读。 问题答案: 您应该使用a 来执行动画,而不要使用“线程睡眠”。这是一个很好的链接,可以助您一臂之力:http : //java.sun.com/docs/book

  • 问题内容: 我是新手,并且使用Java swing设计接口。我希望抽屉在单击按钮时以滑动动画拉出。首先,是否可以这样做,如果可以,我该怎么做。谢谢。对于某些特定的方法信息,我将不胜感激。 问题答案: 根据要实现的目标,您可以采用多种可能的方法。 基本方法是简单地绘制图形和摆动 这样您就可以简单地更新一个变量,该变量将作为绘制大小的基础,例如… 这真的很基础,并且没有考虑到概念变慢/变慢等问题。对于

  • 我正在尝试通过像往常一样将图像添加到来显示动画png(称为)。这适用于普通的-动画,但是,我更希望能够支持。 我一直在网上搜索现有的框架或解决方案,一无所获。有人找到在Swing中显示动画pngs的方法了吗? 要了解我为什么要实现,请查看以下示例,其中演示了GIF的局限性:http://jsfiddle.net/RUX8w/(您的浏览器必须支持apng!

  • 本章将介绍如何使用Canvas和javax.swing包的JFrame类绘制JOGL基本框架。 在这里,我们将实例化一个JFrame,并使用add()方法将canvas对象添加到JFrame的实例中。 使用Canvas和AWT为您提供具有重量级功能的图形框架。 要拥有轻量级图形框架,您需要将GLCanvas与Swing一起使用。 将GLCanvas与Swing一起使用时,可以直接将GLCanvas

  • 我必须为android创建一个窗口过渡动画(就像关闭一个应用程序时的动画。它消失了,另一个从一个角落进来)在Java上。我听说用swing做动画比用JavaFX做要复杂一点。那么,在只用swing制作程序时,我会遇到什么问题吗?或者有什么我不能用swing做但可以用JavaFX做的事情吗?我更喜欢使用swing因为我熟悉它。谢了。

  • 问题内容: 我正在尝试为JPanel的右上角到左下角的2个框设置动画。对于动画,我使用了Swing Timer和。问题是当我单击开始按钮时。它仅设置动画并移动蓝色框,而不移动红色框。 这是代码: 问题答案: 因此,所有在类级别声明的变量都是共享的。您的第一个调用将设置它们,然后第二个调用将完全覆盖以前的值。您需要将它们从类变量更改为动画的参数。 创建一个新类,该类实现并保存该类中的变量。 例如,