Search code examples
javaswingconcurrencyswingworker

GUI has to wait until splashscreen finishes executing


I have a SplashScreen class which displays a image and a progress bar until some databases are initialized. I want that after the splashscreen ends a new window is opened. I have the following code:

Main class

public class Gui{

private static final String IMG_PATH = "../opt/images/splashscreendef.jpg";

public static void main(String[] args) throws ClassNotFoundException,
        InstantiationException, IllegalAccessException,
        UnsupportedLookAndFeelException {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Gui ui = new Gui();
        }
    });
}

private inTouchGui() {
    InitSplashScreen splash = null;
    splash = new InitSplashScreen();
    try {
        splash.initUI();
    } catch (MalformedURLException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    BufferedImage img = null;
    try {
        img = ImageIO.read(new File(IMG_PATH));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    ImageIcon icon = new ImageIcon(img);
    JLabel label = new JLabel(icon);
    JOptionPane.showMessageDialog(null, label);
}

}

Splash screen class

public class InitSplashScreen {
private JDialog dialog;
private JProgressBar progress;

public void initUI() throws MalformedURLException {
    showSplashScreen();
    SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>(){

        @Override
        protected Void doInBackground() throws Exception {
            Thread thread = new Thread(new InitProcess());
            thread.start();
            int i = 0;
            while (thread.isAlive()){
                i++;
                Thread.sleep(200);// Loading of databases
                publish(i);// Notify progress
            }
            if (i < 10){
                for (i = 0; i < 100; i++){
                    Thread.sleep(50);// We simulate loading even if database is fully loaded
                    publish(i);// Notify progress
                }
            }
            return null;
        }

        @Override
        protected void process(List<Integer> chunks) {
            progress.setValue(chunks.get(chunks.size() - 1));
        }

        @Override
        protected void done() {
            hideSplashScreen();
        }

    };
    worker.execute();
}



protected void hideSplashScreen() {
    dialog.setVisible(false);
    dialog.dispose();
}

protected void showSplashScreen() throws MalformedURLException {
    dialog = new JDialog((Frame) null);
    dialog.setModal(false);
    dialog.setUndecorated(true);
    JLabel background = new JLabel(new ImageIcon("splashscreendef.jpg"));
    background.setLayout(new BorderLayout());
    dialog.add(background);
    progress = new JProgressBar();
    background.add(progress, BorderLayout.SOUTH);
    dialog.pack();
    dialog.setLocationRelativeTo(null);
    dialog.setVisible(true);
}

}

When I run the code I get at the same time both the splash screen and the image window, I have tried to use worker.get() but then nothing appears in screen. Could you give me some advice? I am pretty new to Java Swing.

By the way, would it be possible (with possible meaning not a insane load of code and hours to make it work) to implement a login window like this one, for example?

http://designsparkle.com/wp-content/uploads/2014/06/a-simple-html-css-login-for.jpg

Thanks in advice.


Solution

  • Change your way of thinking

    Initialise and show the splash screen, when it's finished, initialise and show the Gui

    This will require to have some way to tell who ever initialised the splash screen that it has completed, to do this, you can use a PropertyChangeListener...

    public class InitSplashScreen {
        //...
        public void initUI(PropertyChangeListener listener) throws MalformedURLException {
            showSplashScreen();
            SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
                //...
            };
            worker.addPropertyChangeListener(listener);
            worker.execute();
        }
    

    Then you listen for the state change property and check the state of the work...

    public static void main(String[] args) throws ClassNotFoundException,
                    InstantiationException, IllegalAccessException,
                    UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                InitSplashScreen splashScreen = new InitSplashScreen();
                try {
                    splashScreen.initUI(new PropertyChangeListener() {
                        @Override
                        public void propertyChange(PropertyChangeEvent evt) {
                            String name = evt.getPropertyName();
                            if ("state".equalsIgnoreCase(name)) {
                                SwingWorker worker = (SwingWorker) evt.getSource();
                                if (worker.getState().equals(SwingWorker.StateValue.DONE)) {
                                    Gui ui = new Gui();
                                }
                            }
                        }
                    });
                } catch (MalformedURLException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }
    

    But remember, you need to remove the splash screen from the Gui code.

    You can also use this to "get" any information from the SwingWorker that the Gui might need and pass it as a parameter to the constructor or via setters depending on your needs

    Also, to me, this...

    Thread thread = new Thread(new InitProcess());
    thread.start();
    

    Looks like a strange thing to do within a SwingWoker. You could simply leave the JProgressBar in indeterminate mode if you don't know how much work is required