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クラスにはArrayListofCarオブジェクトがあり、Viewクラスには車を表すArrayListofオブジェクトもあります。オブジェクトをJPanelに一致させようとしていますが、明らかにクレイジーな仕事をしています。CarJPanels

私はめちゃくちゃ非効率なことをしているのではないかと疑っていますが、何が原因かわかりません。最初は、アクセスがArrayList多すぎて本当に遅くなると思いました。

スムーズに実行するために変更できるものへのポインタはありますか?

4

2 に答える 2

11

この前の回答に基づいて、以下の例では、長方形のグリッド上をランダムに移動する 3 台のタクシーのフリートをシミュレートしています。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 に答える