Java桌面技术

Java Desktop Technology

常用链接

统计

友情连接

最新评论

《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif

利用gif图片制作简单动画是常用的渲染手段,swing虽然支持gif图片格式并可以自动地实现动画效果。
通常最简单地将gif图片放到swing组件上是调用JButton或JLabel的setIcon(Icon icon)方法。
还有一种方法是重写paintComponent(Graphics g)或paint(Graphics g)方法。例如
public class ShowGifPanel extends JPanel{
    ImageIcon image = new ImageIcon("/root/opt/loading.gif");

    @Override
    public void paint(Graphics g) {
        g.drawImage(image.getImage(), 0, 0, this);
    }
}
通过上述方法呈现如下3个gif。



但是事实情况却是:不要企图通过这样简单的处理达到理想的效果。如果你这样做的话马上会发现gif的刷新率往往非常快,看上去gif图片桢刷新很快,或者应该说太快了。
swing还提供了一种实现手段是设置一组相似的gif,通过轮循显示来呈现,通过下图就明了了。

这样虽然可以呈现,但是对于一个动画来说就必须提供多个gif。对于占用空间和给美工的负担都不利。

如果你使用SWT呈现Gif,Eclipse提供了一个方案。
http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet141.java?view=co
其基本原理就是将Gif的各个桢轮循地显示,如果你以这个程序运行loading.gif,看上去还是很快,可以通过修改第131~137行之间的代码来调节刷新率。这样SWT就能完美实现处理Gif了。
不幸的是,将SWT的那种方式移植到Swing中却达不到很好的效果。在Swing中要想完美实现处理Gif需要额外的一些工作。

首先需要对Gif这种图片格式有一些基本认识。
第一:Gif由一系列Image组成,也就是桢,Gif动画就是连续地显示这些桢,但是这还不够。
第二:无论某一时刻轮循到哪一桢,第1桢,总是要当作背景画出来,而且第1桢也是所有桢当中最长最高的,它的尺寸也是整个Gif图象的尺寸,位置从(0, 0)开始,其余各桢可能只是描述与相临各桢变化的部分,所以长和高要小且不完整,起始位置是该桢相对整体背景的位置。(这点SWT也是这样做的)
第三:Gif动画连续显示不一定是各个桢轮循单独显示,而是不仅仅显示当前该显示的桢,还要向前追溯到"第一桢",从"第一桢"开始到当前应该显示的桢组成的连续一系列"桢簇",所以某一时刻单单显示背景和当前桢是不够的,而是显示背景和当前"桢簇"。""桢簇""是我自己取的名字,而且我看SWT轮循的例子中并没有用到"桢簇",而是传统的单桢轮循。但是同样的方法对Swing不奏效,现在我对此还不得其解。关于"第一桢",是和com.sun.imageio.plugins.gif.GIFImageMetadata类的disposalMethod属性有关,在SWT中这个属性是org.eclipse.swt.graphics.ImageData.disposalMethod。disposalMethod据我的研究是描述处理桢的方法,常见的disposalMethod取值有none(取值0,不处理)、Background(取值2,背景)两种,所谓的当前桢的"第一桢"就是向前追溯到最近的disposalMethod取值为2的那一桢的下一桢,也就是说或者"第一桢"的前一桢的disposalMethod取值为2,或者"第一桢"就是Gif索引为2的桢,因为Gif的第1桢总要当背景显示。
第四:桢的元数据在SWT中用org.eclipse.swt.graphics.ImageData类封装,在Swing中对应的是com.sun.imageio.plugins.gif.GIFImageMetadata(可是截止到JDK6.0 u11,这个类的版本号还是0.5,有些另人失望:(),可以通过次类获取到delayTime这个属性,也就是下一桢的间隔时间,但是有很多Gif,这个值总是0,所以Swing显示频率相当的快。

以下是本人写的2个参考实现,其中GifAnalysis.java是gif的分析工具,它将Gif的各个桢单独拿出来分析比对,并列出了上面提到的一些属性。如下图





通过比较发现loading.gif各个桢的delayTime均为0,因此单纯地将loading.gif设置为JLabel等组件的icon属性效果必定会出问题,可以通过美工解决。

Gif.java是呈现gif的参考,需要留意构造函数public Gif(File gifFile, int delayFactor),第二个参数是延时因子,数值越大每一桢的间隔就越长,对于loading.gif该值调节为105较为合适,而tt1.gif和javafx-loading-100x100.gif这个值应该是10。
参考代码这里下载

posted on 2008-12-07 20:36 sun_java_studio@yahoo.com.cn(电玩) 阅读(42581) 评论(7)  编辑  收藏 所属分类: NetBeans

评论

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif[未登录] 2008-12-12 14:00 Matthew Chen

swing 也可以很简单地实现gif动画绘制,同时试了一下JLabel和JButton,直接setIcon就可以了。

public class ShowGifPanel extends JPanel{
ImageIcon image = new ImageIcon("/root/opt/loading.gif");

protected void paintComponent(Graphics g) {
//记得调用超类方法,还有容器的绘制应该在这个方法里添加才对。
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif[未登录] 2008-12-12 14:14 Matthew Chen

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Graphics;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import com.matthew.common.UIManagerUtil;

public class GifDraw {

private JFrame frame;

/**
* Launch the application
*
* @param args
*/
public static void main(String args[]) {

try {
UIManagerUtil.setSystemLookAndFeel();
GifDraw window = new GifDraw();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* Create the application
*/
public GifDraw() {
initialize();
}

/**
* Initialize the contents of the frame
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 500, 375);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final ImageIcon i = new ImageIcon("105.gif");
final JPanel panel = new JPanel() {

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(i.getImage(), 0, 0, this);
}
};
panel.setLayout(null);
frame.getContentPane().add(panel, BorderLayout.CENTER);

final JPanel panel_1 = new JPanel();
panel_1.setLayout(new FlowLayout());
frame.getContentPane().add(panel_1, BorderLayout.NORTH);

final JLabel label = new JLabel(i);
label.setText("New JLabel");
panel_1.add(label);

final JButton button = new JButton(i);
button.setText("New JButton");
panel_1.add(button);

}

}
  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif 2008-12-12 23:46 sun_java_studio@yahoo.com.cn(电玩)

@Matthew Chen
用loading.gif试过吗?
记住我提到的“但是事实情况却是:不要企图通过这样简单的处理达到理想的效果。”  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif[未登录] 2008-12-13 14:55 Matthew Chen

试了一下,还真的不行...
我之前只是用某个的gif动画  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif 2008-12-16 12:46 电玩

@Matthew Chen
用GifAnalysis可以查看gif各frame的delayTime属性,美工应该知道如何更改这个值。  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif[未登录] 2009-01-04 12:52 AllenME

希望继续发关于这本书的笔记。 看您的blog ,就不用看书了,哈哈  回复  更多评论   

# re: 《FilthyRichClients》读书笔记(二)-让Swing正确显示Gif[未登录] 2014-10-16 19:28 1

很好  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
TWaver中文社区