2010-09-18 17 views
8

इससे पहले ऐसा नहीं किया है, इसलिए जाहिर है कि मैं इसे चूसता हूं। वर्तमान माउस स्थिति के आस-पास 64 पिक्सेल एक फॉर्म पर थोड़ा बड़ा खींचा जाता है। समस्या यह है कि धीमा करने के लिए यह 'तरह का' है, और मुझे नहीं पता कि फिक्सिंग शुरू करना कहां है।जावा, निरंतर बदलते ग्राफिक्स को कैसे आकर्षित करें

इसके अलावा, मैंने एक थ्रेड बनाया है, जो इसे समाप्त होने पर अपडेट ग्राफिक्स को लगातार कॉल करता है और टेक्स्ट की तरह थोड़ा एफपीएस कहता है, वास्तव में यह दिखाने के लिए कि कितनी तेजी से चीजें खींची जाती हैं।

छवि उदाहरण: (छवि पत्र से है 'एक' ग्रहण में)

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.dispose जोड़ा() , "
* जोड़ा गया "आइसडोन", इसलिए रेड्रा को तेज़ नहीं कहा जा सकता है, तो इसे चाहिए।
* this link जोड़ा thrashgod के स्रोत को फिर से लिखने
* जोड़ा this link स्रोत पुनर्लेखन thrashgod करने के लिए 2

+0

माउस मूव इवेंट होने पर आप केवल तब क्यों पेंट नहीं करते हैं? –

+0

आप 'पेंट' के दौरान कचरा कलेक्टर का आह्वान क्यों कर रहे हैं? –

+0

वास्तव में माउस के पास क्या पेंट करना चाहते हैं, और यह काम करना चाहते हैं कि कभी भी माउस (जितना तेज़ हो सके, वीडियो पर भी)। मुझे लगता है कि समस्या आपको मिली थी, कि पेंट इवेंट को थ्रेड टी द्वारा भी नहीं कहा जा सकता था। मुझे लगता है, यह कोई समस्या नहीं थी, लेकिन किसी भी तरह से "isdone" जोड़ने के साथ इसे ठीक किया गया। – Margus

उत्तर

13

यहाँ निम्नलिखित उल्लेखनीय परिवर्तन के साथ मेरी प्रमुख पुनर्लेखन है:

  • मुझे लगता है मैं बदल दिया है
  • ड्राइंग का कार्य से पिक्सेल रंग का पता लगाने का कार्य अलग कर लिया है robot.getPixelColor (...) robot.createScreenCapture (...) के साथ एक बार में सभी 64 पिक्सेल लाने के लिए, एक समय में
  • मैं ntroduced स्मार्ट क्लिपिंग - केवल फिर से खींचा जाने की जरूरत है redrawn है।
  • मैं तो मॉडल और देखने के लिए सभी अपडेट घटना डिस्पैच थ्रेड

टिकर लगातार चलाता है पर हो सूत्रण तय कर लिया है।जब यह पिक्सेल रंग में परिवर्तन का पता लगाता है (या तो माउस एक अलग क्षेत्र में जाने के कारण या माउस के नीचे पिक्सल के कारण) यह पता लगाता है कि क्या बदल गया है, मॉडल अपडेट करता है, फिर दृश्य को पुन: पेश करने का अनुरोध करता है। यह दृष्टिकोण तुरंत मानव आंखों के लिए अद्यतन करता है। 28 9 स्क्रीन अपडेट संचयी रूप से 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); 
           } 
          }); 
         } 
        } 
       } 

      } 
     } 

    } 

} 
+0

पर कोई अपवॉट उपलब्ध नहीं है, धन्यवाद। – Margus

+0

+1 मैंने अपने वैकल्पिक कोड को तेज़ करने के लिए 'createScreenCapture() 'का उपयोग करने की स्वतंत्रता ली। – trashgod

6

आप स्विंग का उपयोग कर कोई आपत्ति नहीं है, इस example दिखाता है कि कैसे जल्दी से एक BufferedImage एक Icon से प्राप्त पर ज़ूम करने के लिए। आपके मामले में, आप एक 8x8 BufferedImage चाहते हैं जो रोबोट द्वारा देखे गए पिक्सेल के साथ 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(); 
      } 
     }); 
    } 
} 
+0

मुझे यकीन नहीं है। ऐसा लगता है कि यह पॉइंटर जानकारी के साथ एक छवि को चित्रित करने का एक उदाहरण है जहां एक छवि के अंदर खींचा जाने पर माउस में छवि होती है। Buffered छवि का उपयोग करने की कोशिश की, उदाहरण के लिए, कोई ध्यान देने योग्य अंतर के साथ। बाद में पाया गया कि मैं buffered छवि का उपयोग कर रहा था और यह पुनः लिखना छोड़ सकता था। – Margus

+0

क्या आप किसी घटक या डेस्कटॉप पर ज़ूम इन करने का प्रयास कर रहे हैं? – trashgod

+0

ज़ूमिंग स्वयं महत्वपूर्ण नहीं है, केवल ग्राफिक्स बदलने के लिए तेज़ इनपुट की आवश्यकता है। – Margus

0

पेंट विधि के लिए इस विधि जोड़ें:

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 

ठीक है तो टाइमर का उपयोग नीचे देरी धीमा करने के लिए है, न कि सूत्रण, कि बुरा है।

+0

पेंट() इवेंट डिस्पैचिंग थ्रेड पर कॉल किया जाता है .... इसमें थ्रेड.sleep() जोड़ना अच्छा नहीं है। – rolfl

+0

यह ड्राइंग धीमा करने के लिए है इसलिए कोई झिलमिलाहट नहीं है। –

+1

फिर स्विंग टाइमर पर विचार करें: http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html ...** घटना प्रेषण धागे पर ** कभी सो नहीं ;-) ('कभी नहीं' के लगभग हर अर्थ के लिए) – rolfl

-1

बस समय विलंब लूप का उपयोग करें। फिर आप i की सीमाओं को समायोजित करके देरी को ठीक कर सकते हैं। यह आपको कुछ हिट और परीक्षणों द्वारा संक्रमण गति को समायोजित करने के लिए नियंत्रण भी देता है।

(लंबे i = 0; i < = 100000000000; i ++);

canvas.repaint();

यह मेरे साथ बहुत अच्छा काम करता है और buffered छवियों का उपयोग करने की कोई आवश्यकता नहीं है।

+0

देरी को प्रेरित करने के लिए CPU चक्रों को जलाना। ओह ... – carlsb3rg

संबंधित मुद्दे