Java, como desenhar charts em constante mudança

Não fiz isso antes, então obviamente eu sou péssimo nisso. Aqui, 64 pixels em torno da posição atual do mouse são desenhados um pouco maiores em um formulário. O problema é que é “meio que” desacelerar, e não tenho ideia de por onde começar a consertar.

Além disso, fiz um thread, que constantemente chama charts de atualização quando está terminado e um pouco de fps como texto, para mostrar realmente o quão rápido as coisas são desenhadas.

Exemplo de imagem: (a imagem é da letra ‘a’ no Eclipse)

texto alternativo

Exemplo de código:

@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(px - 4 + x, py - 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; } 

Mudanças feitas:
* adicionado “gc.dispose ();”
* Adicionado “isdone”, então o redesenho não poderia ser chamado mais rápido, então deveria.
* adicionou este link ao thrashgod source rewrite
* adicionou este link ao thrashgod source rewrite 2

Aqui está minha principal reescrita com as seguintes mudanças dignas de nota:

  • Eu separei a tarefa de detectar colors de pixel da tarefa de desenhar
  • Eu substitui robot.getPixelColor (…) por robot.createScreenCapture (…) para buscar todos os 64 pixels de uma só vez, ao invés de um de cada vez
  • Eu introduzi o recorte inteligente – somente o que precisa ser redesenhado é redesenhado.
  • Corrigimos o encadeamento para que todas as atualizações no modelo e na exibição acontecessem no encadeamento de expedição de events

O ticker funciona constantemente. Quando detecta uma alteração na cor do pixel (seja porque o mouse está se movendo para uma região diferente ou quando os pixels sob o mouse estão sendo alterados), ele detecta exatamente o que foi alterado, atualiza o modelo e solicita que a exibição seja repintada. Essa abordagem é atualizada instantaneamente para o olho humano. 289 atualizações de canvas levaram 1 segundo cumulativamente.

Foi um desafio agradável para uma noite tranquila de sábado.

 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(px - 4, py - 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); } }); } } } } } } } 

Se você não se importa em usar o Swing, este exemplo mostra como aumentar rapidamente o zoom em uma BufferedImage obtida de um Icon . No seu caso, você desejaria uma BufferedImage 8×8 que fosse preenchida em mouseMoved() com os pixels vistos pelo robô.

Adendo: Aqui está um instantâneo do canto superior esquerdo do seu exemplo.

Termo aditivo:

Zoom em si não é importante …

A parte lenta é obter pixels da área de trabalho; o dimensionamento é menor. Se você quiser apenas ver uma variedade de técnicas de animação, dê uma olhada neste exemplo .

Adendo: Como a obtenção de pixels individuais é lenta e o método createScreenCapture() sugerido por @Steve McLeod é rápido, aqui está a ideia que eu estava dirigindo. Você pode ver que também atualiza muito mais suavemente. Note que soltar o botão do mouse permite ver as colors capturadas.

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 = px * SIZE / getWidth(); int y = py * 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(); } }); } } 

Adicione este método ao método Paint:

 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 

Ok, então use o timer para retardar o atraso, não um thread, isso é ruim.

Basta usar um loop de atraso de tempo.Você pode então ajustar o atraso, ajustando os limites de i.Ele também lhe dá o controle para ajustar a velocidade de transição por alguns acertos e tentativas.

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

canvas.repaint ();

Funciona muito bem comigo e também não precisa usar imagens em buffer.