SWT GIF工具类

直接代码,详见注释。


问题: 1.性能方面不是很理想,该实现方式会向目标控件请求redraw,频繁的刷新可能会引起闪屏等问题

                 建议:a)使用双缓存

                             b)如果可以的话,在单独的canvas上绘制,这时所有的处理仅针对canvas即可

                 本想按照b)封装的,但考虑到其灵活性,并没有这样做

             2.如果面对大量的GIF图片或者帧间隔时间很小,或许会存在问题。

             3.当心BUG,它无处不在


[java]  view plain copy
  1. package cn.schina.dbs.ui.swt2d;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.ArrayList;  
  5. import java.util.Collections;  
  6. import java.util.HashMap;  
  7. import java.util.List;  
  8. import java.util.Map;  
  9. import java.util.Map.Entry;  
  10. import java.util.Queue;  
  11. import java.util.concurrent.ConcurrentLinkedQueue;  
  12.   
  13. import org.eclipse.swt.events.PaintEvent;  
  14. import org.eclipse.swt.events.PaintListener;  
  15. import org.eclipse.swt.graphics.GC;  
  16. import org.eclipse.swt.graphics.Image;  
  17. import org.eclipse.swt.graphics.ImageData;  
  18. import org.eclipse.swt.graphics.ImageLoader;  
  19. import org.eclipse.swt.widgets.Control;  
  20. import org.eclipse.swt.widgets.Display;  
  21. import org.eclipse.swt.widgets.Shell;  
  22.   
  23. /** 
  24.  * 该类管理GIF图像的绘制 
  25.  *  
  26.  * 注意:该类不会dispose任何资源 
  27.  *  
  28.  * @author Administrator 
  29.  *  
  30.  */  
  31. public class SWTGifAnimal {  
  32.     /** 
  33.      * 存储已注册的图像及控件的映射关系 
  34.      */  
  35.     private static Map<Image, List<Control>> images = Collections  
  36.             .synchronizedMap(new HashMap<Image, List<Control>>());  
  37.     /** 
  38.      * 存储图像及GIF帧的关系 
  39.      */  
  40.     private static Map<Image, ImageLoader> loaders = Collections  
  41.             .synchronizedMap(new HashMap<Image, ImageLoader>());  
  42.     /** 
  43.      * 存储图像的当前帧序号 
  44.      */  
  45.     private static Map<ImageLoader, Integer> currentFrame = Collections  
  46.             .synchronizedMap(new HashMap<ImageLoader, Integer>());  
  47.     /** 
  48.      * 存储图像上一帧的绘制时间 
  49.      */  
  50.     private static Map<ImageLoader, Long> lastDrawingTime = Collections  
  51.             .synchronizedMap(new HashMap<ImageLoader, Long>());  
  52.   
  53.     private static Thread drawingThread = null;;  
  54.     private static Thread dispatchThread = null;  
  55.   
  56.     /** 
  57.      * 读取GIF图像 
  58.      *  
  59.      * @param ins 
  60.      * @return 
  61.      */  
  62.     public static ImageLoader loadGif(InputStream ins) {  
  63.         ImageLoader loader = new ImageLoader();  
  64.         loader.load(ins);  
  65.         return loader;  
  66.     }  
  67.   
  68.     /** 
  69.      * 读取GIF图像 
  70.      *  
  71.      * @param clazz 
  72.      * @param path 
  73.      * @return 
  74.      */  
  75.     public static ImageLoader loadGif(Class clazz, String path) {  
  76.         ImageLoader loader = new ImageLoader();  
  77.         loader.load(clazz.getResourceAsStream(path));  
  78.         return loader;  
  79.     }  
  80.   
  81.     /** 
  82.      * 创建GIF的第一帧图像 
  83.      *  
  84.      * @param display 
  85.      * @param loader 
  86.      * @return 
  87.      */  
  88.     public static Image createFirstFrame(Display display, ImageLoader loader) {  
  89.         return new Image(display, loader.data[0]);  
  90.     }  
  91.   
  92.     /** 
  93.      * 注册GIF图像 
  94.      *  
  95.      * @param control 
  96.      *            GIF图像绘制的控件 
  97.      * @param image 
  98.      *            GIF图像绘制的目标图像 
  99.      * @param loader 
  100.      *            GIF图像帧 
  101.      */  
  102.     synchronized public static void registerGif(Control control, Image image,  
  103.             ImageLoader loader) {  
  104.         if (control == null  
  105.                 || control.isDisposed()  
  106.                 || loader == null  
  107.                 || loader.data.length < 1  
  108.                 || (images.containsKey(image) && images.get(image).contains(  
  109.                         control))) {  
  110.             return;  
  111.         }  
  112.         if (!images.containsKey(image)) {  
  113.             images.put(image, new ArrayList<Control>());  
  114.         }  
  115.         images.get(image).add(control);  
  116.         if (!loaders.containsKey(loader)) {  
  117.             loaders.put(image, loader);  
  118.         }  
  119.         currentFrame.put(loader, 0);  
  120.         /* 
  121.          * 若线程未启动,则启动绘制和分发线程 
  122.          */  
  123.         if (drawingThread == null || !drawingThread.isAlive()) {  
  124.             drawingThread = new GifDrawingThread();  
  125.             drawingThread.start();  
  126.         }  
  127.         if (dispatchThread == null || !dispatchThread.isAlive()) {  
  128.             dispatchThread = new GifFrameDispatchThread();  
  129.             dispatchThread.start();  
  130.         }  
  131.     }  
  132.   
  133.     /** 
  134.      * 移除指定图像 
  135.      *  
  136.      * @param image 
  137.      */  
  138.     synchronized private static void removeImage(Image image) {  
  139.         images.remove(image);  
  140.         currentFrame.remove(image);  
  141.         lastDrawingTime.remove(image);  
  142.         loaders.remove(image);  
  143.   
  144.         if (images.isEmpty()) {  
  145.             drawingThread.interrupt();  
  146.             dispatchThread.interrupt();  
  147.         }  
  148.     }  
  149.   
  150.     /** 
  151.      * GIF图像绘制线程 
  152.      *  
  153.      * 该线程根据队列中的任务,在图像中绘制GIF的当前帧,同时请求控件进行重绘 
  154.      *  
  155.      * @author Administrator 
  156.      *  
  157.      */  
  158.     private static class GifDrawingThread extends Thread {  
  159.         /** 
  160.          * 存储当前要绘制的GIF帧 
  161.          */  
  162.         private static Queue<Object[]> loadersQueue = new ConcurrentLinkedQueue<Object[]>();  
  163.   
  164.         private boolean interrupted;  
  165.   
  166.         public GifDrawingThread() {  
  167.             super("Gif-Drawing-Thread");  
  168.         }  
  169.   
  170.         public void run() {  
  171.             Object[] objs = null;  
  172.             while (!interrupted) {  
  173.                 if ((objs = loadersQueue.poll()) == null) {  
  174.                     // 如果当前绘制任务为空,则休眠5s  
  175.                     try {  
  176.                         Thread.sleep(5);  
  177.                     } catch (InterruptedException e) {  
  178.                         return;  
  179.                     }  
  180.                     continue;  
  181.                 }  
  182.                 final Image image = (Image) objs[0]; // 绘制帧的目标图像  
  183.                 final int frameIndex = (Integer) objs[1]; // 帧的序号  
  184.                 for (int i = 0; i < (images.get(image) == null ? 0 : images  
  185.                         .get(image).size()); i++) {  
  186.                     final Control control = images.get(image).get(i);  
  187.                     if (control.isDisposed()) {  
  188.                         // 控件被释放,则移除  
  189.                         images.get(image).remove(i--);  
  190.                         if (images.get(image).isEmpty()) {  
  191.                             // 若当前图像没有被请求绘制的控件,则移除该图像  
  192.                             removeImage(image);  
  193.                         }  
  194.                         continue;  
  195.                     }  
  196.   
  197.                     control.getDisplay().asyncExec(new Runnable() {  
  198.                         public void run() {  
  199.                             GC gc = new GC(image);  
  200.                             ImageLoader loader = loaders.get(image);  
  201.                             ImageData currentFrameData = loader.data[frameIndex];  
  202.                             // 创建当前帧图像  
  203.                             Image frameImage = new Image(control.getDisplay(),  
  204.                                     currentFrameData);  
  205.                             // 在图片中绘制当前帧  
  206.                             gc.drawImage(frameImage, currentFrameData.x,  
  207.                                     currentFrameData.y);  
  208.                             gc.dispose();  
  209.                             frameImage.dispose();  
  210.                             // 向控件请求重绘  
  211.                             control.redraw();  
  212.                         }  
  213.                     });  
  214.                 }  
  215.             }  
  216.         }  
  217.   
  218.         /** 
  219.          * 向队列中加入一个绘制任务 
  220.          *  
  221.          * @param loader 
  222.          *            需要绘制的gif 
  223.          * @param frameIndex 
  224.          *            需要绘制的gif图像的帧序号 
  225.          */  
  226.         public static void addDrawingTask(Image image, int frameIndex) {  
  227.             loadersQueue.add(new Object[] { image, frameIndex });  
  228.         }  
  229.   
  230.         public void interrupt() {  
  231.             super.interrupt();  
  232.             interrupted = true;  
  233.         }  
  234.     }  
  235.   
  236.     /** 
  237.      * Gif图像帧的派发线程 
  238.      *  
  239.      * 该线程遍历注册的gif图像,将需要绘制的帧放入GifDrawingThread的任务队列中 
  240.      *  
  241.      * @author Administrator 
  242.      *  
  243.      */  
  244.     private static class GifFrameDispatchThread extends Thread {  
  245.         private boolean interrupted;  
  246.   
  247.         public GifFrameDispatchThread() {  
  248.             super("Gif-Frame-Dispatch-Thread");  
  249.         }  
  250.   
  251.         public void run() {  
  252.             while (!interrupted) {  
  253.                 for (Entry<Image, ImageLoader> entry : loaders.entrySet()) {  
  254.                     ImageLoader loader = entry.getValue();  
  255.                     // 该帧延迟时间  
  256.                     int delayTime = loader.data[currentFrame.get(loader)].delayTime;  
  257.                     if (lastDrawingTime.get(loader) != null // 如果并非从未被绘制过  
  258.                             && lastDrawingTime.get(loader) + delayTime * 10 > System  
  259.                                     .currentTimeMillis()) {  
  260.                         // 如果与上一帧绘制时间的时间差小于延时时间  
  261.                         continue;  
  262.                     }  
  263.                     // 记录当前帧绘制时间  
  264.                     lastDrawingTime.put(loader, System.currentTimeMillis());  
  265.                     // 将该帧加入绘制队列  
  266.                     GifDrawingThread.addDrawingTask(entry.getKey(),  
  267.                             currentFrame.get(loader));  
  268.                     // 定位下一帧  
  269.                     int nextImage = currentFrame.get(loader) == loader.data.length - 1 ? 0  
  270.                             : currentFrame.get(loader) + 1;  
  271.                     currentFrame.put(loader, nextImage);  
  272.                 }  
  273.                 try {  
  274.                     Thread.sleep(5);  
  275.                 } catch (InterruptedException e) {  
  276.                     return;  
  277.                 }  
  278.             }  
  279.         }  
  280.   
  281.         public void interrupt() {  
  282.             super.interrupt();  
  283.             interrupted = true;  
  284.         }  
  285.     }  
  286.   
  287.     /** 
  288.      * 示例程序 
  289.      *  
  290.      * @param args 
  291.      */  
  292.     public static void main(String[] args) {  
  293.         Display display = new Display();  
  294.         Shell shell = new Shell(display);  
  295.         // 加载图片  
  296.         ImageLoader loader = SWTGifAnimal.loadGif(SWTGifAnimal.class,  
  297.                 "/icons/progressbar.gif");  
  298.         // 取第一帧  
  299.         final Image image = SWTGifAnimal.createFirstFrame(display, loader);  
  300.         shell.addPaintListener(new PaintListener() {  
  301.             public void paintControl(PaintEvent evt) {  
  302.                 evt.gc.drawImage(image, 1020);  
  303.             }  
  304.         });  
  305.         // 注册gif  
  306.         SWTGifAnimal.registerGif(shell, image, loader);  
  307.         shell.setSize(300160);  
  308.         shell.open();  
  309.         while (!shell.isDisposed()) {  
  310.             if (display.readAndDispatch()) {  
  311.                 display.sleep();  
  312.             }  
  313.         }  
  314.     }  
  315. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值