2010-09-18 35 views
8

Đã không làm điều này trước đây, vì vậy rõ ràng là tôi hút nó. Ở đây 64 pixel xung quanh vị trí chuột hiện tại được rút ra ít lớn hơn trên một hình thức. Vấn đề là, đó là 'loại' để làm chậm, và tôi không biết bắt đầu sửa chữa ở đâu.Java, cách vẽ đồ họa thay đổi liên tục

Bên cạnh đó, tôi đã tạo một chuỗi, liên tục gọi đồ họa cập nhật khi nó kết thúc và một fps nhỏ như văn bản, để hiển thị những thứ được vẽ nhanh như thế nào.

hình ảnh ví dụ: (Hình ảnh là từ chữ 'a' trong Eclipse)

alt text

Mã dụ:

@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; 
} 

Thay đổi được thực:
* thêm "gc.dispose() ; "
* được thêm vào "isdone", vì vậy không thể gọi lại được nhanh hơn, sau đó cần.
* thêm this link để thrashgod nguồn viết lại
* thêm this link để thrashgod nguồn viết lại 2

+0

tại sao bạn không chỉ vẽ lại khi sự kiện di chuyển chuột xảy ra? –

+0

Tại sao bạn gọi trình thu gom rác trong 'sơn'? –

+0

Thực sự muốn vẽ những gì gần con chuột và muốn nó hoạt động ở bất cứ nơi nào mà chuột (nhanh nhất có thể, ngay cả khi trên video). Vấn đề tôi giả sử bạn tìm thấy là, sự kiện sơn đó cũng có thể được gọi không phải bởi chủ đề t. Tôi nghĩ rằng, nó không phải là một vấn đề, nhưng cố định nó với thêm "isdone" dù sao đi nữa. – Margus

Trả lời

13

Dưới đây là viết lại chính mình với những thay đổi đáng chú ý sau đây:

  • tôi đã tách nhiệm vụ phát hiện những pixel màu từ nhiệm vụ vẽ
  • tôi đã thay thế robot.getPixelColor (...) với robot.createScreenCapture (...) để tìm nạp tất cả 64 pixel cùng một lúc, thay vì một lần tại một thời điểm
  • Tôi đã cắt thông minh được giới thiệu - chỉ những gì cần được vẽ lại mới được vẽ lại.
  • Tôi đã khắc phục lên luồng vì vậy tất cả cập nhật mô hình và xem xảy ra trên tổ chức sự kiện văn Chủ đề

Các ticker chạy liên tục.Khi phát hiện thay đổi về màu pixel (hoặc do chuột di chuyển đến một vùng khác hoặc các pixel dưới chuột thay đổi), nó phát hiện chính xác những gì đã thay đổi, cập nhật mô hình, sau đó yêu cầu xem lại để vẽ lại. Cách tiếp cận này cập nhật ngay lập tức cho mắt người. 289 cập nhật màn hình mất tích lũy 1 giây.

Đó là một thử thách thú vị cho một buổi tối thứ bảy yên tĩnh.

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); 
           } 
          }); 
         } 
        } 
       } 

      } 
     } 

    } 

} 
+0

Rất tốt đẹp, Cảm ơn bạn. – Margus

+0

+1 Tôi đã tự do sử dụng 'createScreenCapture()' để tăng tốc mã thay thế của tôi. – trashgod

6

Nếu bạn không nhớ sử dụng Swing, example này cho thấy làm thế nào để nhanh chóng phóng to trên một BufferedImage thu được từ một Icon. Trong trường hợp của bạn, bạn muốn có một 8x8 BufferedImage được điền vào mouseMoved() với các pixel được robot nhìn thấy.

Phụ lục: Đây là ảnh chụp nhanh ở góc trên cùng bên trái của ví dụ của bạn.

Phụ Lục:

Zooming chính nó là không quan trọng ...

Phần chậm là nhận được điểm ảnh từ máy tính để bàn; tỷ lệ nhỏ. Nếu bạn chỉ muốn xem một loạt các kỹ thuật hoạt hình, hãy xem điều này example.

Phụ lục: Khi nhận được pixel riêng lẻ chậm và phương pháp createScreenCapture() được đề xuất bởi @Steve McLeod rất nhanh, đây là ý tưởng tôi đang lái xe tại. Bạn có thể thấy nó cũng cập nhật trơn tru hơn nhiều. Lưu ý rằng việc nhả nút chuột cho phép người dùng xem các màu đã chụp.

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(); 
      } 
     }); 
    } 
} 
+0

Tôi chắc chắn không quan tâm. Có vẻ như đây là một ví dụ về việc vẽ một hình ảnh tĩnh với thông tin con trỏ trong đó hình ảnh con chuột, khi được vẽ bên trong một biểu mẫu. Đã thử sử dụng hình ảnh đệm, như trong ví dụ đó, không có sự khác biệt đáng chú ý. Sau đó thấy rằng tôi đã sử dụng hình ảnh đệm và có thể đã bỏ qua việc viết lại này. – Margus

+0

Bạn đang cố gắng phóng to một thành phần hoặc màn hình nền? – trashgod

+0

Phóng to chính nó không quan trọng, chỉ cần đầu vào nhanh để thay đổi đồ họa. – Margus

0

Thêm phương pháp này với phương pháp sơn:

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 

Được rồi vì vậy sử dụng hẹn giờ để chậm trễ, không phải là một luồng, đó là xấu.

+0

paint() được gọi trên chuỗi Gửi sự kiện .... thêm Thread.sleep() vào đó không tốt. – rolfl

+0

Nó chỉ là để làm chậm bản vẽ để không có nhấp nháy. –

+1

Sau đó xem xét một bộ đếm thời gian Swing: http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html ...** không bao giờ ** ngủ trên thread gửi sự kiện ;-) (cho hầu như mọi ý nghĩa của 'không bao giờ') – rolfl

-1

Chỉ cần sử dụng vòng lặp thời gian trễ. Sau đó, bạn có thể tinh chỉnh độ trễ bằng cách điều chỉnh giới hạn của i.It cũng cung cấp cho bạn quyền kiểm soát để điều chỉnh tốc độ chuyển đổi bằng một số lần truy cập và thử nghiệm.

cho (long i = 0; i < = 100000000000; i ++);

canvas.repaint();

Nó hoạt động rất tốt với tôi và cũng không cần phải sử dụng hình ảnh đệm.

+0

Đốt chu kỳ CPU để tạo ra sự chậm trễ. Ugh ... – carlsb3rg

Các vấn đề liên quan