Java,如何绘制不断变化的graphics
以前没做过,所以显然我吮吸它。 这里,当前鼠标位置周围的64个像素在窗体上绘制得稍大些。 问题是,这是缓慢的,我不知道从哪里开始修复。
除此之外,我做了一个线程,它在完成时不断地调用更新graphics,并且像文本一样带有一点点fps,以显示事物的绘制速度。
图像示例:(图像来自Eclipse中的字母'a')
代码示例:
@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; }
所做的更改:
*添加“gc.dispose();”
*添加“isdone”,所以重绘不能被调用得更快,那么它应该。
* 将此链接添加到thrashgod源代码重写
*添加此链接到thrashgod源码重写2
这是我的主要重写与以下值得注意的变化:
- 我已经从绘图任务中分离出检测像素颜色的任务
- 我用robot.createScreenCapture(…)replace了robot.getPixelColor(…)以一次获取所有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(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); } }); } } } } } } }
如果您不介意使用Swing,则此示例显示如何快速放大从Icon
获取的BufferedImage
。 在你的情况下,你会想要一个8×8的BufferedImage
在mouseMoved()
被机器人看到的像素填充。
附录:这里是你的例子左上angular的快照。
附录:
缩放本身并不重要
缓慢的部分是从桌面获取像素; 缩放很小。 如果你只是想看到各种animation技术,看看这个例子 。
附录:由于获取单个像素的速度很慢, createScreenCapture()
Steve McLeodbuild议的createScreenCapture()
方法速度很快,所以这里是我开车的想法。 你可以看到它也更顺利的更新。 请注意,释放鼠标button可以让您看到捕获的颜色。
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(); } }); } }
将此方法添加到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
好吧,使用计时器来减缓延迟,而不是一个线程,这是不好的。
简单地使用一个时间延迟循环。然后您可以通过调整i的极限值来微调延迟时间。您还可以通过一些命中和试验来控制转换速度。
for(long i = 0; i <= 100000000000; i ++);
canvas.repaint();
它对我来说工作得很好,也不需要使用缓冲图像。