双缓存技术与Canvas,JPanel

双缓存技术与Canvas,JPanel

刚学java,最近用java写了一个画板小程序,使用了双缓存技术。第一次写,可能有点菜,大家将就看一下。

这次写博客,更多是为了自己能够更好的理解和记忆,先说一点废话,理解一下双缓存技术。

在有关绘图及图片动态操作的java程序中,都绕不开repaint()方法重绘。重绘的过程,实质上是一个不断 刮白-重画 的过程。但在屏幕上完成这一系列操作是需要一定时间的,而且屏幕上的图形越复杂,所花的时间就越长,我们肉眼可见的 刮白-重画操作,就会让我们直观的感受到屏幕闪烁。

要解决闪烁问题,本质上是解决我们肉眼可以感知到的 刮白-重画 过程,于是引入双缓存技术。双缓存技术的核心在于,在内存中开辟一块与当前画面等大的“逻辑屏幕“。我们的画图和动画操作都先作用于这块”逻辑屏幕“,当一个操作在这块”逻辑屏幕“上完成之后,再把整块”逻辑屏幕“投放到我们的屏幕上,这样的话,我们就看不见整个图形在屏幕上的重绘过程,从而解决了闪烁问题。就好像看动漫一样,不用双缓存技术,就是画一帧看一帧,肯定会卡顿。而用了双缓存技术,会事先把每一帧画好,不断翻动给你看。
先在类中定义两个私有变量,这两个私有变量,这两个私有变量会在后续的代码中充当“逻辑屏幕”和“逻辑画笔”,

private java.awt.Image iBuffer;
private Graphics2D gBuffer;

Dimension封装了调用它的容器的长和宽,通过这个类,获取当前显示屏幕的长和宽,方便定义逻辑屏幕。这里需要注意的是,gBuffer所绘制的图形不会立即呈现在屏幕上,它所绘制的图形只针对于逻辑画板。

public void paint(Graphics g) {
         Dimension size = getSize();
	      int width = size.width;
	      int height = size.height;
	      
	      if(iBuffer==null)
	      {
	         iBuffer=createImage(width,height);//创建一块和显示屏幕等大的“逻辑屏幕”。
	         gBuffer=(Graphics2D)iBuffer.getGraphics();//用“逻辑屏幕”的getGraphics操作创建并返回“逻辑画笔”。
	      }
	      
	      gBuffer.setColor(Color.WHITE);
	      gBuffer.fillRect(0,0,width,height);//这两步操作,将“逻辑画板”刮白
	      
	      
	      abstract_shape shape=null;
	      myiterator list=save.create_iterator();
	      while(list.isnext()) {
	    	  shape=list.next();
	    	  shape.paint(gBuffer);
	      }//这两步操作,是通过之前就保存好的绘图信息。将之前的画图内容重现。也就是重绘
	      
	   ....................
	   ....................
	   ...................//这里省略的操作,应该是用 gBuffer画笔,在“逻辑画板”上绘制当前想要画的图形。
	   
          g.drawImage(iBuffer,0,0,this);//这一步操作,将“逻辑画板”上的内容整个投射到屏幕上,让我们可以看见。
	  }

这样的操作条件下,重绘过程不可见,解决了屏幕闪烁。这里需要特别注意的是,g和gBuffer都是画笔类,然而他们针对的对象不同。画笔类g针对于屏幕,用g画出的图形直接显示在屏幕,不用双缓存技术时,就直接用g作图。gBuffer作用于iBuffer,也就是“逻辑画板”。

说完了双缓存,我就来探讨一下,我在写这个画板过程中出现的问题。作为一个初学者,问题可能很低级,希望各位大佬指证。

public class draw extends Canvas implements MouseListener, MouseMotionListener

最开始,我自定义的画板类继承了Canvas画布类。查询资料得知,repaint方法会判断组件的量级,重量级调用update()方法,轻量级直接调用paint()方法。而Canvas是重量级组件,于是我想把双缓存技术写在update()方法里面,这样便于代码维护。重写update()并运行后,发现依旧闪烁。检测中发现update()方法并没有被调用,查找资料无果。于是摆在我面前的解决方案是,重写reapint()或者将双缓存技术写进paint()中,考虑自身技术问题,选择第二种。

双缓存写完之后,发现还是闪烁,只不过换了一种方式。不用双缓存,是每个图形依次序闪烁。用了双缓存之后,变成了整个画板闪烁,查找资料未果。于是我尝试,将Canvas改成JPanel。

public class draw extends JPanel implements MouseListener, MouseMotionListener

就此,困扰我一天的闪烁问题得以解决,但是抛出了两个我暂时无法得到答案的问题。

1.为什么我继承Canvas类的,调用repaint()方法时,update()方法没有被调用,是因为被继承的原因吗?
2.Canvas类和JPanel类到底有什么区别。我已知Canvas是重量级组件,JPanel是轻量级组件,会不会跟这个有关系呢?

作为一个初学者,希望各位大佬指教。

猜你喜欢

转载自blog.csdn.net/weixin_43797829/article/details/106530283