如何显示启动画面,在后台加载数据,然后隐藏启动画面?

时间:2013-02-18 02:24:20

标签: java multithreading swing splash-screen countdownlatch

我正在设计一个简单的JavaFX表单。

首先,我加载JavaFX环境(并等待它完成),如下所示:

final CountDownLatch latch_l = new CountDownLatch(1);
try {
    // init the JavaFX environment
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new JFXPanel(); // init JavaFX
            latch_l.countDown();
        }
    });
    latch_l.await();
}

这很好用。 (之所以我需要首先以这种方式加载JavaFX,是因为它主要是一个Swing应用程序,里面有一些JavaFX组件,但是后来加载了它们)

现在,我想在启动时添加一个启动画面,并在JavaFX环境加载时显示它(实际上在屏幕上放置了5秒钟,因为有徽标,商标等等。我需要展示的应用程序)

所以我想出了一个SplashScreen类,它只是在屏幕上显示一个JWindow:

public class SplashScreen {

    protected JWindow splashScreen_m = new JWindow();
    protected Integer splashScreenDuration_m = 5000;

    public void show() {
        // fill the splash-screen with informations
        ...

        // display the splash-screen
        splashScreen_m.validate();
        splashScreen_m.pack();
        splashScreen_m.setLocationRelativeTo(null);
        splashScreen_m.setVisible(true);
    }

    public void unload() {
        // unload the splash-screen
        splashScreen_m.setVisible(false);
        splashScreen_m.dispose();
    }
}

现在,我想让启动画面加载并显示5秒钟。 同时,我也希望加载JavaFX环境。

所以我像这样更新了CountDownLatch:

final CountDownLatch latch_l = new CountDownLatch(2); // now countdown is set to 2

final SplashScreen splash_l = new SplashScreen();

try {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            // show splash-screen
            splash_l.show();
            latch_l.countDown();

            // init the JavaFX environment
            new JFXPanel(); // init JavaFX
            latch_l.countDown();
        }
    });
    latch_l.await();
    splash_l.unload();
}

所以,它正在工作,但是只有JavaFX环境才能加载,所以基本上它会很快卸载(这是正常的,考虑到我编写的代码)。

如何在不冻结EDT的情况下显示启动画面最少5秒(如果JavaFX加载速度更快)?

感谢。

1 个答案:

答案 0 :(得分:3)

最重要的问题是您正在阻止事件调度线程,这意味着它在被阻止时无法显示/更新任何内容。同样的问题也适用于JavaFX。

您也应该永远不会从其他任何事件队列中更新任何事件。

现在,您可以采用多种方式解决此问题,但SwingWorker可能是最简单的方法。

enter image description here

我道歉,这是我曾经接触过JavaFX的全部内容......

public class TestJavaFXLoader extends JApplet {

    public static void main(String[] args) {
        new TestJavaFXLoader();
    }

    public TestJavaFXLoader() throws HeadlessException {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                Loader loader = new Loader();
                loader.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        if (evt.getPropertyName().equals("state") && evt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
                            System.out.println("Load main app here :D");
                        }
                    }
                });
                loader.load();
            }
        });
    }

    public class Loader extends SwingWorker<Object, String> {

        private JWindow splash;
        private JLabel subMessage;

        public Loader() {
        }

        protected void loadSplashScreen() {
            try {
                splash = new JWindow();
                JLabel content = new JLabel(new ImageIcon(ImageIO.read(...))));
                content.setLayout(new GridBagLayout());
                splash.setContentPane(content);

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;

                subMessage = createLabel("");

                splash.add(createLabel("Loading, please wait"), gbc);
                splash.add(subMessage, gbc);
                splash.pack();
                splash.setLocationRelativeTo(null);
                splash.setVisible(true);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        protected JLabel createLabel(String msg) {
            JLabel message = new JLabel("Loading, please wait");
            message.setForeground(Color.CYAN);
            Font font = message.getFont();
            message.setFont(font.deriveFont(Font.BOLD, 24));
            return message;
        }

        public void load() {
            if (!EventQueue.isDispatchThread()) {
                try {
                    SwingUtilities.invokeAndWait(new Runnable() {
                        @Override
                        public void run() {
                            loadSplashScreen();
                        }
                    });
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            } else {
                loadSplashScreen();
            }
            execute();
        }

        @Override
        protected void done() {
            splash.dispose();
        }

        @Override
        protected void process(List<String> chunks) {
            subMessage.setText(chunks.get(chunks.size() - 1));
        }

        @Override
        protected Object doInBackground() throws Exception {

            publish("Preparing to load application");
            try {
                Thread.sleep(2500);
            } catch (InterruptedException interruptedException) {
            }
            publish("Loading JavaFX...");

            runAndWait(new Runnable() {
                @Override
                public void run() {
                    new JFXPanel();
                }
            });

            try {
                Thread.sleep(2500);
            } catch (InterruptedException interruptedException) {
            }
            return null;
        }

        public void runAndWait(final Runnable run)
                throws InterruptedException, ExecutionException {
            if (Platform.isFxApplicationThread()) {
                try {
                    run.run();
                } catch (Exception e) {
                    throw new ExecutionException(e);
                }
            } else {
                final Lock lock = new ReentrantLock();
                final Condition condition = lock.newCondition();
                lock.lock();
                try {
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            lock.lock();
                            try {
                                run.run();
                            } catch (Throwable e) {
                                e.printStackTrace();
                            } finally {
                                try {
                                    condition.signal();
                                } finally {
                                    lock.unlock();
                                }
                            }
                        }
                    });
                    condition.await();
//                    if (throwableWrapper.t != null) {
//                        throw new ExecutionException(throwableWrapper.t);
//                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}

我找到了runAndWait代码here