[英]Java, how to draw constantly changing graphics
之前沒有這樣做過,所以顯然我很沮喪。 這里,當前鼠標位置周圍的64個像素在表單上繪制得更大。 問題是,它有點'緩慢',我不知道從哪里開始修復。
除此之外,我創建了一個線程,它在完成后不斷調用更新圖形,並且像文本一樣點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(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();”
*添加了“isdone”,因此無法更快地調用重繪,那么應該。
*添加此鏈接到thrashgod source rewrite
* 將此鏈接添加到thrashgod source rewrite 2
這是我的主要改寫,具有以下值得注意的變化:
股票代碼不斷運行。 當它檢測到像素顏色的變化時(由於鼠標移動到不同的區域或鼠標變化下的像素),它會准確檢測到更改的內容,更新模型,然后請求重新繪制視圖。 這種方法立即更新到人眼。 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);
}
});
}
}
}
}
}
}
}
如果你不介意使用Swing,這個例子展示了如何快速放大從Icon
獲得的BufferedImage
。 在你的情況下,你需要一個8x8 BufferedImage
,用mouseMoved()
填充機器人看到的像素。
附錄:這是您示例左上角的快照。
附錄:
縮放本身並不重要......
緩慢的部分是從桌面獲取像素; 縮放是次要的。 如果您只是想看各種動畫技術,請看一下這個例子 。
附錄:由於獲得單個像素很慢並且@Steve McLeod建議的createScreenCapture()
方法很快,這就是我開車的想法。 您可以看到它也更順暢地更新。 請注意,釋放鼠標按鈕可以查看捕獲的顏色。
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();
}
});
}
}
將此方法添加到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();
它對我來說非常好,也不需要使用緩沖圖像。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.