自定义PopupFactory能解决Popup窗口的动画显示,但并不能解决普通窗口如JFrame, Frame, JDialog, Dialog, JWindow和Window的动画显示。这在前篇文章已经指明了。这是因为这些窗口并不使用PopupFactory提供的getPopup方法获取窗口对象,它们实际上是AWT窗口,是作为顶层容器存在的,是Swing所有组件的基础。Swing组件依赖于这些窗口提供的图形和事件等环境来绘制自己并传播和处理事件。
前面文章的一个评论希望“
对话框,窗口之类的重型组件的弹出或显示也要有这种效果”,显然这样的窗口就不能再使用自定义PopupFactory来创建了。最直接的方法是继承窗口和对话框来自定义显示过程。但更深入的想一下,这些窗口的动画过程只需要使用窗口的一些公共接口就可以实现,比如setSize、setVisible。这启发了我,其实可以提供类似于PopupFactory那样统一接口类来实现各类型窗口显示的动画。于是写了下面的Invoker类来实现这以功能:
/**
* 一个简单的窗口动画显示工具
* @author William Chen
*/
public class Invoker implements ActionListener{
private static final int ANIMATION_INTERVAL=10;
private static final int ANIMATION_FRAMES=10;
/**
* 调用此静态方法显示窗口,可以出现动画效果
* 被显示的窗口是任何继承自Window的窗口,包括显示模态的对话框
*/
public static void show(Window w){
if(w.isVisible())
return;
new Invoker(w).invoke();
}
//要被显示的窗口
private Window window;
//窗口全部展开时大小
private Dimension full_size;
//动画定时器
private Timer timer;
//当前动画帧
private int frameIndex;
//私有构造函数,不允许直接访问
private Invoker(Window w){
//初始化
window=w;
full_size=window.getSize();
timer=new Timer(15, this);
frameIndex=0;
window.setSize(0, 0);
}
//激活动画过程
private void invoke(){
if(!windows.isVisible()){
timer.start();
window.setVisible(true);
}
}
//动画的一帧处理方法
public void actionPerformed(ActionEvent e) {
//计算和设置当前帧尺寸
int w=full_size.width*frameIndex/ANIMATION_FRAMES;
int h=full_size.height*frameIndex/ANIMATION_FRAMES;
window.setSize(w, h);
if(frameIndex==ANIMATION_FRAMES){
//最后一帧,停止时钟,释放资源
timer.stop();
timer=null;
window=null;
full_size=null;
}else
//前进一帧
frameIndex++;
}
}
非常简单和直接的想法。唯一需要注意的是invoke方法中timer.start()和window.setVisiable(true)的调用顺序。因为有一些窗口是模态对话框,它们在调用window.setVisible(true)就进入阻塞状态,如果将timer.start()调用放在window.setVisible之后就会启动不了动画进程。整个类的动画的处理方法和前篇文章中处理方法大同小异。
这个类的编程接口只有一个静态方法
public static void show(Window w)
调用代码如下:
public static void main(String[] args) {
......
EventQueue.invokeLater(new Runnable() {
public void run() {
//使用Invoke.show方法动画显示窗口
Invoker.show(new SampleFrame());
}
});
}
下图是使用Invoker写的一个动画显示窗口和对话框的演示:
点击上面的两个按钮分别弹出模态和非模态对话框。能用Invoker显示的动画窗口包括所有继承自Window的窗口,包括JFrame, Frame, JDialog, Dialog, JWindow和Window。