在 bufferedImage 上绘制时闪烁
Flickering when drawing onto bufferedImage
我有一个 3d 对象,它由我使用 graphics2D 绘制的多个多边形组成。当我旋转它时,似乎没有足够的时间在每一帧绘制整个对象,因为在某些帧,一些多边形只是丢失(未绘制)。我不明白这是怎么回事,因为我在 paintComponent 中首先将所有多边形绘制到 bufferedImage myImg 上,然后将完成的图像绘制到屏幕上。当我删除 clearRect 时,此问题得到解决,但当然它不会在绘制下一帧之前删除最后一帧的绘图。
注意:我是一个业余爱好者,但我已经非常努力地理解了,所以这是我最后的选择,我很乐意得到一些帮助。代码(去掉不必要的代码如下):
public class Main {
long temp = System.currentTimeMillis() + frameRate;
public static void main(String[] args) {
myGUI = new GUI(width, height);
while(true) {
if (System.currentTimeMillis() >= temp) {
temp += frameRate;
rotateObject();
myGUI.myCanvas.myLabel.repaint();
}
}
}
}
public class GUI extends JFrame {
public Canvas myCanvas;
public GUI(int w, int h) {
this.setSize(w, h);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myCanvas = new Canvas(w, h);
this.getContentPane().add(myCanvas);
this.setVisible(true);
this.pack();
}
}
public class Canvas extends JPanel {
public BufferedImage myImg;
public Graphics2D g2d;
public JLabel myLabel;
public Canvas(int w, int h) {
myImg = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
myLabel = new JLabel(new ImageIcon(myImg));
this.add(myLabel);
g2d = myImg.createGraphics();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d.clearRect(0, 0, myImg.getWidth(), myImg.getHeight());
g2d.setColor(Color.RED));
g2d.fillPolygon(pointsX, pointsY, 3);
g.drawImage(myImg, 0, 0, null);
}
}
This is how my object is flickering
你真的需要花时间通读:
- Performing Custom Painting
- Painting in AWT and Swing
- 2D Graphics
- Concurrency in Swing
- How to Use Swing Timers
这些不是“初学者”主题,对一般的 Swing 和特定的语言有合理的理解将非常有利。
永远不要在组件上使用 getGraphics
。这简直是个坏主意(我不知道为什么这个方法是 public
)。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage myImg;
private double rotation;
public TestPane() throws IOException {
myImg = ImageIO.read(getClass().getResource("/images/happy.png"));
Timer timer = new Timer(33, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rotation += Math.toRadians(5);
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = AffineTransform.getTranslateInstance((getWidth() - myImg.getWidth()) / 2, (getHeight() - myImg.getHeight()) / 2);
at.rotate(rotation, myImg.getWidth() / 2, myImg.getHeight() / 2);
g2d.transform(at);
g2d.drawImage(myImg, 0, 0, this);
g2d.dispose();
}
}
}
我有一个 3d 对象,它由我使用 graphics2D 绘制的多个多边形组成。当我旋转它时,似乎没有足够的时间在每一帧绘制整个对象,因为在某些帧,一些多边形只是丢失(未绘制)。我不明白这是怎么回事,因为我在 paintComponent 中首先将所有多边形绘制到 bufferedImage myImg 上,然后将完成的图像绘制到屏幕上。当我删除 clearRect 时,此问题得到解决,但当然它不会在绘制下一帧之前删除最后一帧的绘图。
注意:我是一个业余爱好者,但我已经非常努力地理解了,所以这是我最后的选择,我很乐意得到一些帮助。代码(去掉不必要的代码如下):
public class Main {
long temp = System.currentTimeMillis() + frameRate;
public static void main(String[] args) {
myGUI = new GUI(width, height);
while(true) {
if (System.currentTimeMillis() >= temp) {
temp += frameRate;
rotateObject();
myGUI.myCanvas.myLabel.repaint();
}
}
}
}
public class GUI extends JFrame {
public Canvas myCanvas;
public GUI(int w, int h) {
this.setSize(w, h);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myCanvas = new Canvas(w, h);
this.getContentPane().add(myCanvas);
this.setVisible(true);
this.pack();
}
}
public class Canvas extends JPanel {
public BufferedImage myImg;
public Graphics2D g2d;
public JLabel myLabel;
public Canvas(int w, int h) {
myImg = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
myLabel = new JLabel(new ImageIcon(myImg));
this.add(myLabel);
g2d = myImg.createGraphics();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2d.clearRect(0, 0, myImg.getWidth(), myImg.getHeight());
g2d.setColor(Color.RED));
g2d.fillPolygon(pointsX, pointsY, 3);
g.drawImage(myImg, 0, 0, null);
}
}
This is how my object is flickering
你真的需要花时间通读:
- Performing Custom Painting
- Painting in AWT and Swing
- 2D Graphics
- Concurrency in Swing
- How to Use Swing Timers
这些不是“初学者”主题,对一般的 Swing 和特定的语言有合理的理解将非常有利。
永远不要在组件上使用 getGraphics
。这简直是个坏主意(我不知道为什么这个方法是 public
)。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public class TestPane extends JPanel {
private BufferedImage myImg;
private double rotation;
public TestPane() throws IOException {
myImg = ImageIO.read(getClass().getResource("/images/happy.png"));
Timer timer = new Timer(33, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
rotation += Math.toRadians(5);
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = AffineTransform.getTranslateInstance((getWidth() - myImg.getWidth()) / 2, (getHeight() - myImg.getHeight()) / 2);
at.rotate(rotation, myImg.getWidth() / 2, myImg.getHeight() / 2);
g2d.transform(at);
g2d.drawImage(myImg, 0, 0, this);
g2d.dispose();
}
}
}