用java显示Gif动画

用java显示Gif动画,java,swing,gif,Java,Swing,Gif,您好,我正在用Swing在Java1.6上编写GUI应用程序 我有一个弹出屏幕,当我的Swing gui加载时,应该会显示一个gif动画,稍后也会显示 我的弹出屏幕是一个JDialog。t动画应显示在通过以下方式添加到Jdialog的JLabel上: ImageIcon myImgIcon = getMyImgIcon(); JLabel imageLbl = new JLabel(myImgIcon); add(imageLbl, BorderLayout.CENTER); 现在的问题是,

您好,我正在用Swing在Java1.6上编写GUI应用程序

我有一个弹出屏幕,当我的Swing gui加载时,应该会显示一个gif动画,稍后也会显示

我的弹出屏幕是一个JDialog。t动画应显示在通过以下方式添加到Jdialog的JLabel上:

ImageIcon myImgIcon = getMyImgIcon();
JLabel imageLbl = new JLabel(myImgIcon);
add(imageLbl, BorderLayout.CENTER); 
现在的问题是,只有在加载gui之后才会显示动画。我相信当GUI加载时(在我的应用程序中这是一个繁重的操作),EDT是如此繁忙以至于无法运行动画

现在的问题是,让GUI加载到另一个线程(不是EDT)上是错误的,所以我不知道如何解决这个问题


有人有想法吗?

也许您正在尝试制作一个动画,在应用程序开始时播放,而不会干扰即将到来的事件或组件。因此,您可能想尝试一下启动屏幕。从这里阅读:


在上面的链接中,它演示了名为
SplashScreen
的类的用法,该类刚从Frame类派生而来。所以机制是这样的:你显示一个单独的框架(启动屏幕,你的动画在这里),然后在一段时间后你的主应用程序启动。

你只需要释放EDT线程中的一些繁重任务,然后在一个单独的线程中完成它们。在这种情况下,gif动画将与其他正在运行的进程一起工作

您也可以在单独的线程中创建应用程序接口(是的,不在EDT中),但只能在显示它之前创建应用程序接口。之后,您应该在EDT内进行所有更改,否则您可能会遇到很多问题

稍后,您还可以在单独的线程中加载更多UI元素,只需确保将它们添加到EDT中显示的框架/容器中,这是最重要的

下面是一个“重型”接口加载的小示例:

public static void main ( String[] args ) throws InvocationTargetException, InterruptedException
{
    // Main window

    final JFrame frame = new JFrame ();

    final JPanel panel = new JPanel ( new FlowLayout ( FlowLayout.LEFT, 5, 5 ) )
    {
        public Dimension getPreferredSize ()
        {
            Dimension ps = super.getPreferredSize ();
            ps.width = 0;
            return ps;
        }
    };
    frame.add ( new JScrollPane ( panel ) );

    frame.setSize ( 600, 500 );
    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
    frame.setLocationRelativeTo ( null );

    SwingUtilities.invokeAndWait ( new Runnable ()
    {
        public void run ()
        {
            frame.setVisible ( true );
        }
    } );

    // Load dialog

    final JDialog load = new JDialog ( frame );

    JPanel panel2 = new JPanel ( new BorderLayout () );
    panel2.setBorder ( BorderFactory.createEmptyBorder ( 15, 15, 15, 15 ) );
    load.add ( panel2 );

    final JProgressBar progressBar = new JProgressBar ( 0, 100 );
    panel2.add ( progressBar );

    load.setModal ( false );
    load.pack ();
    load.setLocationRelativeTo ( frame );

    SwingUtilities.invokeAndWait ( new Runnable ()
    {
        public void run ()
        {
            load.setVisible ( true );
        }
    } );

    // Heavy task (takes approx. 10 seconds + some time on buttons creation) 

    for ( int i = 0; i < 100; i++ )
    {
        Thread.sleep ( 100 );

        final JButton button = new JButton ( "Button" + i );
        final int finalI = i;

        // Updating panel and progress in EDT
        SwingUtilities.invokeLater ( new Runnable ()
        {
            public void run ()
            {
                panel.add ( button );
                button.revalidate ();
                progressBar.setValue ( finalI );
            }
        } );
    }
}
publicstaticvoidmain(String[]args)抛出InvocationTargetException、InterruptedException
{
//主窗口
最终JFrame=新JFrame();
最终JPanel面板=新JPanel(新FlowLayout(FlowLayout.LEFT,5,5))
{
公共维度getPreferredSize()
{
维度ps=super.getPreferredSize();
ps.width=0;
返回ps;
}
};
frame.add(新的JScrollPane(面板));
框架尺寸(600500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(空);
SwingUtilities.invokeAndWait(新的可运行()
{
公开作废运行()
{
frame.setVisible(true);
}
} );
//加载对话框
最终JDialog负载=新JDialog(帧);
JPanel panel2=新的JPanel(新的BorderLayout());
panel2.setboorder(BorderFactory.createEmptyBorder(15,15,15,15));
load.add(面板2);
最终JProgressBar progressBar=新的JProgressBar(0,100);
面板2.add(进度条);
load.setModal(假);
load.pack();
load.setLocationRelativeTo(框架);
SwingUtilities.invokeAndWait(新的可运行()
{
公开作废运行()
{
load.setVisible(true);
}
} );
//繁重的任务(大约需要10秒钟+创建按钮需要一些时间)
对于(int i=0;i<100;i++)
{
睡眠(100);
最终JButton按钮=新JButton(“按钮”+i);
最终int finalI=i;
//EDT中的更新面板和进度
SwingUtilities.invokeLater(新的可运行()
{
公开作废运行()
{
panel.add(按钮);
button.revalidate();
progressBar.setValue(finalI);
}
} );
}
}
如您所见,所有接口更新操作都是在EDT中进行的,其他所有操作都在另一个线程中运行

还要注意的是,主线程不是EDT线程,所以我们可以马上做一些重要的事情

在某些情况下,不需要立即显示界面的加载部分,因此您可以在“繁重”操作结束时将它们全部添加到一起。这将节省一些加载时间,并使初始化代码更加简单

关于EDT和我在回答中所说内容的简要说明…

…这是我在Swing L&F和许多基于Swing的应用程序下工作三年后发现的。我挖掘了很多Swing源代码,发现了很多不为人所知的有趣的东西

正如您所知,单线程接口更新(其EDT在Swing中)的整体思想是将每个单独的组件可视化更新(及其事件)保持在队列中,并在该线程内逐个执行。这主要是为了避免绘制问题,因为单个帧内的每个组件都绘制到保存在内存中的单个图像。那里的绘制顺序很严格,因此一个组件不会覆盖最终图像上的另一个组件。绘制顺序取决于组件树,组件树是通过在另一个容器中添加一些组件或容器创建的(这是在Swing上创建任何应用程序接口时的基本操作)

总而言之,您必须将所有可视化更新(可能导致更新的方法/操作)保存在EDT内。任何其他操作都可以在EDT之外完成-例如,您可以在EDT之外准备应用程序接口(同样,除非您在已经可见的容器中添加/删除/移动组件)

但在一些非常罕见的情况下,这可能存在一些内部问题。很久以前,这里对这个问题进行了很好的讨论:

简而言之:自从第6版JDK以来,Sun在文档中声明,甚至Swing组件的创建都应该在EDT内部完成,以避免可能<
URL url = this.getClass().getResource(path);
Icon myImgIcon = new ImageIcon(url);
JLabel imageLbl = new JLabel(myImgIcon);
component.add(imageLbl, BorderLayout.CENTER);
Icon imgIcon = new ImageIcon(this.getClass().getResource("ajax-loader.gif"));
JLabel label = new JLabel(imgIcon);
label.setBounds(669, 42, 45, 15); // You can use your own values
frame.getContentPane().add(label);