Swing在Thread非阻塞GUI中创建Loader

时间:2015-02-03 08:21:23

标签: java multithreading swing swingutilities awt-eventqueue

在主程序加载大量数据时,我遇到了显示加载程序的问题。下面是一个名为 SplashScreen 的类,它显示了.gif加载器的动画。

公共类SplashScreen扩展了JWindow {

public SplashScreen() {
    super();
    Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/resources/load.gif"));
    try {
        if (image != null) {
            JLabel imageLabel = new JLabel();
            imageLabel.setIcon(new ImageIcon(image));
            this.getContentPane().setLayout(new BorderLayout());
            this.getContentPane().add(imageLabel, BorderLayout.CENTER);
            this.pack();
            Dimension screenSize =
                    Toolkit.getDefaultToolkit().getScreenSize();
            Dimension labelSize = imageLabel.getPreferredSize();
            setLocation(screenSize.width / 2 - (labelSize.width / 2),
                    screenSize.height / 2 - (labelSize.height / 2));
            addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    dispose();
                }
            });
            addKeyListener(new KeyAdapter() {
                public void keyTyped(KeyEvent e) {
                    dispose();
                }
            });
        }
    } catch (Exception ex) {
    }
}

运行这段代码的结果是:

Loader gif

但是当我想加载大量数据(比如100万条记录)时,我有类似的东西:

Loader gif blank

我使用Thread,EventQueue.invokeLater和SwingUtilities在单独的Thread中显示SplashScreen,但它不起作用。加载大量数据时,它始终为空白。不幸的是,我必须说使用EventQueue或SwingUtilities非常困难,因为你无法结束这些实用程序启动的任务。

1 个答案:

答案 0 :(得分:0)

我终于想出了如何正确实施这个案例。

1)实现SplashScreen,它将显示加载程序(.gif)

    public class SplashScreen extends JWindow {

        public SplashScreen() {
            super();
            Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/resources/load.gif"));
            try {
                if (image != null) {
                    JLabel imageLabel = new JLabel();
                    imageLabel.setIcon(new ImageIcon(image));
                    this.getContentPane().setLayout(new BorderLayout());
                    this.getContentPane().add(imageLabel, BorderLayout.CENTER);
                    this.pack();
                    Dimension screenSize =
                            Toolkit.getDefaultToolkit().getScreenSize();
                    Dimension labelSize = imageLabel.getPreferredSize();
                    setLocation(screenSize.width / 2 - (labelSize.width / 2),
                            screenSize.height / 2 - (labelSize.height / 2));
                    addMouseListener(new MouseAdapter() {
                        public void mouseClicked(MouseEvent e) {
                            dispose();
                        }
                    });
                    addKeyListener(new KeyAdapter() {
                        public void keyTyped(KeyEvent e) {
                            dispose();
                        }
                    });
                }
            } catch (Exception ex) {
            }
        }

        @Override
        public void dispose() {
            setVisible(false);
        }
}

2)Init ScheduledExecutorService

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

3)实现负责显示SplashScreen的线程

Thread splashThread = new Thread(new Runnable() {
            public void run() {
                setSplashScreen(new SplashScreen());
                getSplashScreen().setVisible(true);
                getSplashScreen().toFront();
                getSplashScreen().setAlwaysOnTop(true);
            }
        });

4)安排新创建的线程

executor.schedule(splashThread, 0, TimeUnit.MILLISECONDS);

5)当需要处理SplashScreen时

getSplashScreen().dispose();

此外,您可以创建单独的线程来检查是否需要处理SplashScreen。

private void invokeExecutor() {
    executor.scheduleAtFixedRate(new DoneTask(), 0, 200, TimeUnit.MILLISECONDS);
}

private class DoneTask implements Runnable {
    @Override
    public void run() {
        if (fileWorker.isDone()) { //SwingWorker
            getSplashScreen().dispose();
        }
    }
}