Java Swing 双缓冲技术解决图像闪烁问题

       我们看电视时,看到的屏幕称为OSD层,也就是说,只有在OSD层上显示图像我们才能看到。现在,我需要创建一个虚拟的、看不见但是可以在上面画图(比如说画点、线)的OSD层,我称之为offscreen(后台缓冲区)。这个offscreen存在于内存中,我们在上面画图,这个offscreen上面的东西可以显示在OSD层上,需要一个创建这个offscreen的函数,返回这个offscreen的句柄(整型指针)、宽度、高度、指向新建offscreen数据缓冲区的指针,该缓冲区是一个在函数外创建的offscreen的数据缓冲区,大小是offscreen的高度*宽度*每个像素点数据的大小。闪烁是图形编程的一个常见问题。需要多重复杂绘制操作的图形操作会导致呈现的图像闪烁或具有其他不可接受的外观。双缓冲的使用解决这些问题。双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。当启用双缓冲时,所有绘制操作首先呈现到内存缓冲区,而不是屏幕上的绘图图面。所有绘制操作完成后,内存缓冲区直接复制到与其关联的绘图图面。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁。

在Java swing中,绘制的原理如下:

update() -> paint(Graphics g) -> paintComponent(Graphics g)

       它们是逐渐调用的,Java swing内置有双缓冲,在paint(Graphics g)中。

       假如我们的图像绘制在JPanel上,我们可以继承JPanel,然后复写里面的paintComponent(Graphics g)和update方法。我们可以在paintComponent上绘制图像,然后调用paint方法就可以调用paintComponent方法绘制图像。

 

 双缓冲的实现:

        复写JPanel类中的update()方法,新建一个图像缓存空间,然后把它的画笔拿过来,用paint方法把要绘制的东西绘制上去。再一次性把图像显示在JPanel控件上。

       我在这里是用鼠标画线消除闪动的例子来说明双缓冲的使用。

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class DrawTrail
{
 BufferedImage image = new BufferedImage(500, 500,
   BufferedImage.TYPE_INT_RGB);
 Graphics g = image.getGraphics();
 private DrawCanvas canvas = new DrawCanvas();
 private int preX = -1;
 private int preY = -1;
    private Image offScreenImage;  //图形缓存
    
 public void init()
 {
  g.fillRect(0, 0, 1600, 1000);
  JFrame frame = new JFrame("测试画出鼠标的轨迹");
  frame.setSize(600, 600);
  
  frame.add(canvas);
  frame.setLayout(null);
  canvas.setBounds(0, 0, 500, 500);
  frame.setVisible(true);
  
  canvas.addMouseMotionListener(new MouseMotionAdapter()
  {
   @Override
   public void mouseDragged(MouseEvent e)
   {
    if (preX > 0 && preY > 0)
    {
     g.setColor(Color.black);
     g.drawLine(preX, preY, e.getX(), e.getY());
    }
    preX = e.getX();
    preY = e.getY();
    canvas.repaint();
   }
  });
  
  frame.addWindowListener(new WindowAdapter()//添加窗口关闭处理函数
     {
            public void windowClosing(WindowEvent e)
            {
               System.exit(0);
            }});
 }
 
 public static void main(String[] args)
 {
  DrawTrail dc = new  DrawTrail();
  dc.init();
  
 }
 
 class DrawCanvas extends Canvas
 {
  private static final long serialVersionUID = 1L;
  @Override
  public void paint(Graphics g)
  {
   Graphics2D g2 = (Graphics2D)g;
   g2.drawImage(image, 0, 0, null);
  }
  
  @Override
  public void update(Graphics g)
  {
         if(offScreenImage == null)
            offScreenImage = this.createImage(500, 500);     //新建一个图像缓存空间,这里图像大小为800*600
            Graphics gImage = offScreenImage.getGraphics();  //把它的画笔拿过来,给gImage保存着
            paint(gImage);                                   //将要画的东西画到图像缓存空间去
            g.drawImage(offScreenImage, 0, 0, null);         //然后一次性显示出来
  }
 }
}


       


  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值