4

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

在本例中,我将模拟 10 辆汽车。JPanels我将在稍后详细说明这些汽车。

因此,考虑事件 process_car_arrival。每次计划执行此事件时,我都会在我的类中添加一个Car对象。该类具有以下相关属性:ArrayListcarsModelCar

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()为每辆要移动的汽车调用该方法。

返回到 process_car_arrival 事件。添加 Car 对象后,它会调用类addCarToEast()中的方法View。这在从东到西的道路起点处添加了一个 JPanel。

现在去View上课,我有一个**单独的**线程,它执行以下操作(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 辆汽车移动时,它最终移动得很少。

澄清一下,目前Model类中有一个ArrayList对象Car,并且View类中还有一个表示汽车ArrayList的对象。JPanel我正在尝试将Car对象与匹配JPanels,但我显然在做一项疯狂的工作。

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

任何指向我可以更改以使其顺利运行的指针?

4

2 回答 2

11

基于这个先前的答案,下面的例子模拟了一个由三辆出租车组成的车队在一个矩形网格上随机移动。Ajavax.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();
            }
        });
    }
}
于 2013-02-15T02:22:13.147 回答
5

我无法抗拒...

在此处输入图像描述

我在屏幕上运行了 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

于 2013-02-15T19:45:11.530 回答