编辑两个
为了防止尖刻的评论和单行的答案漏掉了重点:IFF它就像调用setDoubleBuffered(true)一样简单,那么我如何访问当前的离线缓冲区,以便我可以开始弄乱 BufferedImage 的底层像素数据缓冲区?
我花时间编写了一段正在运行的代码(看起来也很有趣),所以我非常感谢实际回答(多么令人震惊;)我的问题并解释这是什么/如何工作而不是单行和刻薄的注释 ;)
这是一段在 JFrame 上反弹一个正方形的工作代码。我想知道可用于转换这段代码的各种方法,以便它使用双缓冲。
请注意,我清除屏幕并重新绘制正方形的方式不是最有效的,但这实际上不是这个问题的目的(在某种程度上,为了这个例子,它有点慢更好)。
基本上,我需要不断地修改 BufferedImage 中的很多像素(因为有某种动画),并且我不想看到由于屏幕上的单缓冲而导致的视觉伪影。
我有一个 JLabel,它的 Icon 是一个包装 BufferedImage 的 ImageIcon。我想修改那个 BufferedImage。
必须做什么才能使其成为双缓冲?
我知道当我在"image 2"上绘图时,会以某种方式显示"image 1 " 。但是,一旦我完成了“图像 2”的绘制,我如何“快速”将“图像 1”替换为“图像 2”?
这是我应该手动做的事情吗,比如说,通过自己交换 JLabel 的 ImageIcon ?
我是否应该总是在同一个 BufferedImage 中绘制,然后在 JLabel 的 ImageIcon 的 BufferedImage 中对 BufferedImage 的像素进行快速“blit”?(我想不,我不知道如何将其与显示器的“垂直空白行”“同步”[或平面屏幕中的等效项:我的意思是,在不干扰显示器本身刷新它的时刻的情况下进行“同步”像素,以防止剪切])。
“重绘”订单呢?我应该自己触发这些吗?我应该在哪个/什么时候调用repaint()或其他什么?
最重要的要求是我应该直接在图像的像素数据缓冲区中修改像素。
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class DemosDoubleBuffering extends JFrame {
private static final int WIDTH = 600;
private static final int HEIGHT = 400;
int xs = 3;
int ys = xs;
int x = 0;
int y = 0;
final int r = 80;
final BufferedImage bi1;
public static void main( final String[] args ) {
final DemosDoubleBuffering frame = new DemosDoubleBuffering();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing( WindowEvent e) {
System.exit(0);
}
});
frame.setSize( WIDTH, HEIGHT );
frame.pack();
frame.setVisible( true );
}
public DemosDoubleBuffering() {
super( "Trying to do double buffering" );
final JLabel jl = new JLabel();
bi1 = new BufferedImage( WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB );
final Thread t = new Thread( new Runnable() {
public void run() {
while ( true ) {
move();
drawSquare( bi1 );
jl.repaint();
try {Thread.sleep(10);} catch (InterruptedException e) {}
}
}
});
t.start();
jl.setIcon( new ImageIcon( bi1 ) );
getContentPane().add( jl );
}
private void drawSquare( final BufferedImage bi ) {
final int[] buf = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
for (int i = 0; i < buf.length; i++) {
buf[i] = 0xFFFFFFFF; // clearing all white
}
for (int xx = 0; xx < r; xx++) {
for (int yy = 0; yy < r; yy++) {
buf[WIDTH*(yy+y)+xx+x] = 0xFF000000;
}
}
}
private void move() {
if ( !(x + xs >= 0 && x + xs + r < bi1.getWidth()) ) {
xs = -xs;
}
if ( !(y + ys >= 0 && y + ys + r < bi1.getHeight()) ) {
ys = -ys;
}
x += xs;
y += ys;
}
}
编辑
这不是针对全屏 Java 应用程序,而是针对常规 Java 应用程序,在其自己的(有点小)窗口中运行。