代码之家  ›  专栏  ›  技术社区  ›  Margus

Java,如何绘制不断变化的图形

  •  8
  • Margus  · 技术社区  · 16 年前

    图像示例:(图像来自Eclipse中的字母'a')

    alt text

    @SuppressWarnings("serial")
    public static class AwtZoom extends Frame {
        private BufferedImage image;
        private long timeRef = new Date().getTime();
        Robot robot = null;
    
        public AwtZoom() {
            super("Image zoom");
            setLocation(new Point(640, 0));
            setSize(400, 400);
            setVisible(true);
            final Ticker t = new Ticker();
    
            this.image = (BufferedImage) (this.createImage(320, 330));
            addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent we) {
                    t.done();
                    dispose();
                }
            });
            try {
                robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace();
            }
            t.start();
        }
    
        private class Ticker extends Thread {
            public boolean update = true;
            public void done() {
                update = false;
            }
            public void run() {
                try {
    
                    while (update == true) {
                        update(getGraphics());
                        // try {
                        // Thread.sleep(200);
                        // } catch (InterruptedException e) {
                        // e.printStackTrace();
                        // return;
                        // }
                    }
                } catch (Exception e) {
    
                    update=false;
                }
            }
        }
    
        public void update(Graphics g) {
            paint(g);
        }
    
        boolean isdone = true;
        public void paint(Graphics g) {
            if (isdone) {
                isdone=false;
                int step = 40;
                Point p = MouseInfo.getPointerInfo().getLocation();
    
                Graphics2D gc = this.image.createGraphics();
    
                try {
    
                    for (int x = 0; x < 8; x++) {
                        for (int y = 0; y < 8; y++) {
                            gc.setColor(robot.getPixelColor(p.x - 4 + x, p.y
                                    - 4 + y));
                            gc.fillOval(x * step, y * step, step - 3, step - 3);
                            gc.setColor(Color.GRAY);
                            gc.drawOval(x * step, y * step, step - 3, step - 3);
                        }
                    }
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
                gc.dispose();
                isdone = true;
                iter++;
            }
            g.drawImage(image, 40, 45, this);
            g.setColor(Color.black);
            StringBuilder sb = new StringBuilder();
            sb.append(iter)
                    .append(" frames in ")
                    .append((double) (new Date().getTime() - this.timeRef) / 1000)
                    .append("s.");
            g.drawString(sb.toString(), 50, 375);
        }
    
        int iter = 0;
    }
    

    所做的更改:
    *已添加“gc.处理();"
    *添加了“isdone”,所以redraw不能被称为更快,那么它应该。
    this link 重新编写源代码
    this link

    4 回复  |  直到 16 年前
        1
  •  14
  •   Steve McLeod    16 年前

    以下是我的主要重写,其中有以下值得注意的变化:

    • 我已经换了robot.getPixelColor(…)带robot.createScreenscapture创建(…)一次获取所有64个像素,而不是一次获取一个像素
    • 我已经修复了线程,所以模型和视图的所有更新都发生在事件调度线程上

    自动售票机不停地运行。当它检测到像素颜色的变化(由于鼠标移动到不同的区域或鼠标下的像素发生变化)时,它准确地检测到发生了什么变化,更新模型,然后请求视图重新绘制。这种方法会立即更新到人眼。289次屏幕更新累计耗时1秒。

    对于一个安静的周六晚上来说,这是一个令人愉快的挑战。

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.awt.geom.Ellipse2D;
    import java.awt.image.BufferedImage;
    
    public class ZoomPanel extends JPanel {
    
        private static final int STEP = 40;
        private int iter = 0;
        private long cumulativeTimeTaken = 0;
    
    
        public static void main(String[] args) {
            final JFrame frame = new JFrame("Image zoom");
    
            final ZoomPanel zoomPanel = new ZoomPanel();
            frame.getContentPane().add(zoomPanel);
            final Ticker t = new Ticker(zoomPanel);
    
            frame.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent we) {
                    t.done();
                    frame.dispose();
                }
            });
            t.start();
    
            frame.setLocation(new Point(640, 0));
            frame.pack();
            frame.setVisible(true);
        }
    
        private final Color[][] model = new Color[8][8];
    
        public ZoomPanel() {
            setSize(new Dimension(400, 400));
            setMinimumSize(new Dimension(400, 400));
            setPreferredSize(new Dimension(400, 400));
            setOpaque(true);
        }
    
        private void setColorAt(int x, int y, Color pixelColor) {
            model[x][y] = pixelColor;
            repaint(40 + x * STEP, 45 + y * STEP, 40 + (x * STEP) - 3, 45 + (y * STEP) - 3);
        }
    
        private Color getColorAt(int x, int y) {
            return model[x][y];
        }
    
        public void paintComponent(Graphics g) {
            long start = System.currentTimeMillis();
            if (!SwingUtilities.isEventDispatchThread()) {
                throw new RuntimeException("Repaint attempt is not on event dispatch thread");
            }
            final Graphics2D g2 = (Graphics2D) g;
            g2.setColor(getBackground());
            try {
    
                for (int x = 0; x < 8; x++) {
                    for (int y = 0; y < 8; y++) {
                        g2.setColor(model[x][y]);
                        Ellipse2D e = new Ellipse2D.Double(40 + x * STEP, 45 + y * STEP, STEP - 3, STEP - 3);
                        g2.fill(e);
                        g2.setColor(Color.GRAY);
                        g2.draw(e);
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            iter++;
            g2.setColor(Color.black);
            long stop = System.currentTimeMillis();
            cumulativeTimeTaken += stop - start;
            StringBuilder sb = new StringBuilder();
            sb.append(iter)
                    .append(" frames in ")
                    .append((double) (cumulativeTimeTaken) / 1000)
                    .append("s.");
    
            System.out.println(sb);
        }
    
        private static class Ticker extends Thread {
    
            private final Robot robot;
    
            public boolean update = true;
            private final ZoomPanel view;
    
            public Ticker(ZoomPanel zoomPanel) {
                view = zoomPanel;
                try {
                    robot = new Robot();
                } catch (AWTException e) {
                    throw new RuntimeException(e);
                }
            }
    
            public void done() {
                update = false;
            }
    
            public void run() {
                int runCount = 0;
                while (update) {
                    runCount++;
                    if (runCount % 100 == 0) {
                        System.out.println("Ran ticker " + runCount + " times");
                    }
                    final Point p = MouseInfo.getPointerInfo().getLocation();
    
                    Rectangle rect = new Rectangle(p.x - 4, p.y - 4, 8, 8);
                    final BufferedImage capture = robot.createScreenCapture(rect);
    
                    for (int x = 0; x < 8; x++) {
                        for (int y = 0; y < 8; y++) {
                            final Color pixelColor = new Color(capture.getRGB(x, y));
    
                            if (!pixelColor.equals(view.getColorAt(x, y))) {
                                final int finalX = x;
                                final int finalY = y;
                                SwingUtilities.invokeLater(new Runnable() {
                                    public void run() {
                                        view.setColorAt(finalX, finalY, pixelColor);
                                    }
                                });
                            }
                        }
                    }
    
                }
            }
    
        }
    
    }
    
        2
  •  6
  •   Community Mohan Dere    9 年前

    如果你不介意用Swing,这个 example BufferedImage Icon . 在您的情况下,您需要8x8 缓冲图像 被填满了 mouseMoved() 用机器人看到的像素。

    附录:这是你例子左上角的快照。

    缩放本身并不重要。。。

    example .

    createScreenCapture() 史蒂夫·麦克劳德建议的方法很快,这是我的想法。您可以看到它的更新也更加顺利。请注意,松开鼠标按钮可以看到捕获的颜色。

    Zoom.png

    import java.awt.AWTException;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.Robot;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseMotionListener;
    import java.awt.image.BufferedImage;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /** @see https://stackoverflow.com/questions/3742731 */
    public class Zoom extends JPanel implements MouseMotionListener {
    
        private static final int SIZE = 16;
        private static final int S2 = SIZE / 2;
        private static final int SCALE = 48;
        private BufferedImage img;
        private Robot robot;
    
        public Zoom() {
            super(true);
            this.setPreferredSize(new Dimension(SIZE * SCALE, SIZE * SCALE));
            img = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_RGB);
            try {
                robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace(System.err);
            }
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
        }
    
        @Override
        public void mouseMoved(MouseEvent e) {
            Point p = e.getPoint();
            int x = p.x * SIZE / getWidth();
            int y = p.y * SIZE / getHeight();
            int c = img.getRGB(x, y);
            this.setToolTipText(x + "," + y + ": "
                + String.format("%08X", c));
        }
    
        @Override
        public void mouseDragged(MouseEvent e) {
            int x = e.getXOnScreen();
            int y = e.getYOnScreen();
            Rectangle rect = new Rectangle(x - S2, y - S2, SIZE, SIZE);
            img = robot.createScreenCapture(rect);
            repaint();
        }
    
        private static void create() {
            JFrame f = new JFrame("Click & drag to zoom.");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            Zoom zoom = new Zoom();
            f.add(zoom);
            f.pack();
            f.setVisible(true);
            zoom.addMouseMotionListener(zoom);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    create();
                }
            });
        }
    }
    
        3
  •  0
  •   Dylan Turner    12 年前

    public void clear(Graphics g, Color currentColor) {
        g.setColor(backgroundColor);
        g.fillRect(0, 0, width, height);
        g.setColor(currentColor);
        int delay = 5; //milliseconds
    
        ActionListener taskPerformer = new ActionListener() {
        public void actionPerformed(ActionEvent evt) { } };
    
        new Timer(delay, taskPerformer).start();
    } //run this right before you draw something
    

        4
  •  -1
  •   Ritik    10 年前

    只需使用时间延迟循环。你呢然后可以通过调整i的限制来微调延迟。它还可以通过一些点击和试验来控制调整过渡速度。

    对于(长i=0;i<=10000000000;i++);

    画布.重绘();