关于Java闪屏问题使用双缓存方法解决的方法
2014-10-16 09:36
911 查看
一,Java闪屏出现的原因:
在用java中绘图或者添加图片的时候,使用多线程处理动态问题会出现闪屏的现象,因为AWT先用背景色覆盖组件再重绘图像的方式(即先把屏幕整个清空,然后重绘),而每次重绘都是一个过程,尽管很短但仍需要时间,这就导致了闪烁现象。如果重绘的面积较大的话花去的时间也是比较可观的,这个时间甚至可以大到足以让闪烁严重到让人无法忍受的地步。另外,用paint(Graphics g)函数在屏幕上直接绘图的时候,由于执行的语句比较多,或者创建的线程多导致程序不断地改变窗体中正在被绘制的图象,会造成绘制的缓慢,这也从一定程度上加剧了闪烁。
二,Java闪屏解决的方法:
可以利用双缓冲的手段来解决这个问题。解决思路:既然由于屏幕刷新与屏幕显示之间不能很好的衔接才造成了屏幕闪烁的结果,那么我们可不可以在屏幕显示之前将它所需要显示的下一屏幕内容提起准备好,当需要显示时直接满屏刷新,这样当需要一个屏幕时该屏幕已经被准备好,循环下去就能解决闪屏的问题。要使用双缓冲来提前绘制所需要的显示图像,就需要了解Java重回机制,然后重新相应的代码即可。
在awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();所以我们只需要重写awt中的upodate()方法来改变其工作方式,跳过清屏动作即可:
awt中upodate()源码:
重写后的代码:
三,示例代码:
我使用多线程的方法实现雪花漫天纷飞的情景,相应代码如下:
改代码出现闪屏情况,仅需要将代码中注释掉的update()去掉注释即可!
源代码下载:
点击打开链接
在用java中绘图或者添加图片的时候,使用多线程处理动态问题会出现闪屏的现象,因为AWT先用背景色覆盖组件再重绘图像的方式(即先把屏幕整个清空,然后重绘),而每次重绘都是一个过程,尽管很短但仍需要时间,这就导致了闪烁现象。如果重绘的面积较大的话花去的时间也是比较可观的,这个时间甚至可以大到足以让闪烁严重到让人无法忍受的地步。另外,用paint(Graphics g)函数在屏幕上直接绘图的时候,由于执行的语句比较多,或者创建的线程多导致程序不断地改变窗体中正在被绘制的图象,会造成绘制的缓慢,这也从一定程度上加剧了闪烁。
二,Java闪屏解决的方法:
可以利用双缓冲的手段来解决这个问题。解决思路:既然由于屏幕刷新与屏幕显示之间不能很好的衔接才造成了屏幕闪烁的结果,那么我们可不可以在屏幕显示之前将它所需要显示的下一屏幕内容提起准备好,当需要显示时直接满屏刷新,这样当需要一个屏幕时该屏幕已经被准备好,循环下去就能解决闪屏的问题。要使用双缓冲来提前绘制所需要的显示图像,就需要了解Java重回机制,然后重新相应的代码即可。
在awt中对于窗体画布的重绘其条用顺序是repaint() —>update()—>paint();所以我们只需要重写awt中的upodate()方法来改变其工作方式,跳过清屏动作即可:
awt中upodate()源码:
/** * Updates the container. This forwards the update to any lightweight * components that are children of this container. If this method is * reimplemented, super.update(g) should be called so that lightweight * components are properly rendered. If a child component is entirely * clipped by the current clipping setting in g, update() will not be * forwarded to that child. * * @param g the specified Graphics window * @see Component#update(Graphics) */ public void update(Graphics g) { if (isShowing()) { if (! (peer instanceof LightweightPeer)) { g.clearRect(0, 0, width, height); } paint(g); } }
重写后的代码:
// 重写update方法,先将窗体上的图形画在图片对象上,再一次性显示 public void update(Graphics g) { <span style="white-space:pre"> </span>if(offScreenImage == null) { <span style="white-space:pre"> </span> // 截取窗体所在位置的图片 .创建一幅用于双缓冲的、可在屏幕外绘制的图像。 <span style="white-space:pre"> </span> offScreenImage = this.createImage(1200, 800); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>// 获得截取图片的画布 <span style="white-space:pre"> </span>Graphics gOffScreen = offScreenImage.getGraphics(); <span style="white-space:pre"> </span>// 将截下的图片上的画布传给重绘函数,重绘函数只需要在截图的画布上绘制即可,不必在从底层绘制 <span style="white-space:pre"> </span>paint(gOffScreen); <span style="white-space:pre"> </span>//将截下来的图片加载到窗体画布上去,才能达到每次重画的效果 <span style="white-space:pre"> </span>g.drawImage(offScreenImage, 0, 0, null); }
三,示例代码:
我使用多线程的方法实现雪花漫天纷飞的情景,相应代码如下:
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Table extends Frame implements ActionListener { Button start = new Button("开始"); int[] xx = new int[100]; int[] yy = new int[100]; int[] fs1 = new int[100]; Font fs = null; Image offScreen = null; public Table() { super("雪花飞"); setSize(1200, 800); //setBackground(Color.black); // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); setLayout(new FlowLayout()); add(start); start.addActionListener(this); validate(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void actionPerformed(ActionEvent e) { if (e.getSource() == start) begin(); } public void begin() { for (int i = 0; i < xx.length; i++) { xx[i] = (int) (1200 * Math.random()); yy[i] = (int) (800 * Math.random()); fs1[i] = (int) (20 * Math.random() + 12); } new Thread() { public void run() { while (true) { for (int i = 0; i < xx.length; i++) { if ((yy[i] > 800) || (yy[i] < 0)) yy[i] = 0; yy[i]++;} repaint(); try { Thread.sleep(10); } catch (InterruptedException e) { System.err.println("Thread interrupted"); } } } }.start(); } public void paint(Graphics g) { super.paint(g); g.setColor(Color.BLACK); g.fillRect(0, 0, 1200, 800); Image img = new ImageIcon("11.jpg").getImage(); g.drawImage(img, 0, 0, 1200, 800, null); for (int i = 0; i < xx.length; i++) { Font fs = new Font("宋体", Font.BOLD, fs1[i]); g.setColor(Color.white); g.setFont(fs); g.drawString("*", xx[i], yy[i]);// 画雪 } } /*public void update(Graphics g) { if(offScreen == null) {offScreen = createImage(1200, 800);} Graphics gOffScreen = offScreen.getGraphics(); paint(gOffScreen); g.drawImage(offScreen, 0, 0, null); } */ public static void main(String args[]) { new Table(); } }注意:该代码包含图片11.jpg,仅需要在该文件所在路径创建一个相同的图片即可,这样更能看出效果。
改代码出现闪屏情况,仅需要将代码中注释掉的update()去掉注释即可!
源代码下载:
点击打开链接
相关文章推荐
- 关于ASP.NET“操作必须使用一个可更新的查询”问题的解决方法
- 关于在英创em9161板上使用ADO.net连接远程数据库提示 “无法找到 PInvoke dll"dbnetlib.dll"”问题解决方法
- 关于使用gVim编写Java源文件时产生乱码的解决方法
- 关于使用VS.Net2003调试器出现的问题及相关解决方法[转]
- IE6背景图片不缓存问题解决方案及图片使用策略多个方法小结
- VC使用双缓存技术,解决闪屏问题
- 关于使用VS.Net2003调试器出现的问题及相关解决方法
- 关于更改ip后dbconsole服务不能启动(em不能使用)问题的根本解决方法
- 关于使用VS.Net2003调试器出现的问题及相关解决方法 (转)
- Java使用Oracle遇到的最大游标超出问题及其解决方法
- 关于使用asp.net调试器出现的问题及相关解决方法
- 关于使用super.getHibernateTemplate()中的方法报java.lang.NullPointerException的解决办法
- VC使用双缓存技术,解决闪屏问题
- Java使用Oracle遇到的最大游标超出问题及其解决方法
- 关于在做java的Web开发中遇到跨域访问的问题的解决方法汇总
- 关于CSS中内层使用float导致外层的背景无法显示的问题的解决方法
- 关于PPT制作和使用的个别问题提出来的解决方法
- 关于IIS服务启动失败的问题:“IIS提示‘另一个程序正在使用此文件,进程无法访问’”,的解决方法
- 使用网上流传的一个数据库连接池在Proxy.newProxyInstance处引起 java.lang.ClassCastException 问题的解决方法
- Java使用Oracle遇到的最大游标超出问题及其解决方法