Java - global reusable download dialog

I am trying to implement a global boot dialog ... I want to call some static function to show the dialog and some static function to close it. At that time I am doing some work in the main thread or in the sub thread ...

I tried following, but the dialog is not updating ... Only once at the end, before hiding it again, it is updated ...

    private static Runnable getLoadingRunable()
{
    if (loadingRunnable != null)
    {
        loadingFrame.setLocationRelativeTo(null);
        loadingFrame.setVisible(true);  
        return loadingRunnable;
    }

    loadingFrame = new JFrame("Updating...");
    final JProgressBar progressBar = new JProgressBar();
    progressBar.setIndeterminate(true);
    final JPanel contentPane = new JPanel();
    contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    contentPane.setLayout(new BorderLayout());
    contentPane.add(new JLabel("Updating..."), BorderLayout.NORTH);
    contentPane.add(progressBar, BorderLayout.CENTER);
    loadingFrame.setContentPane(contentPane);
    loadingFrame.pack();
    loadingFrame.setLocationRelativeTo(null);
    loadingFrame.setVisible(true);  

    loadingRunnable = new Runnable() {
        public void run() {

            try {
                while (running) {
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    loadingFrame.setVisible(false);
                }
            });
        }
    };
    return loadingRunnable;
}

public static void showLoadingBar() {
    System.out.println("showLoadingBar");
    running = true;

    threadLoadingBar = new Thread(getLoadingRunable());
    threadLoadingBar.start();
}

public static void hideLoadingBar() {
    System.out.println("hideLoadingBar");
    running = false;
    threadLoadingBar = null;
}

      

0


source to share


2 answers


If it doesn't animate, it means that you are doing work on the event dispatch thread while the loading frame is displayed. This background work must be done on a different thread.

Here's a non-working example:

public static void main(String[] args) throws Exception {
    SwingUtilities.invokeLater(
        new Runnable() {
            @Override
            public void run() {
                try {
                    showLoadingBar();
                    Thread.sleep(10000L); // doing work in the EDT. Prevents the frame from animating
                    hideLoadingBar();
                }
                catch (InterruptedException e) {
                }
            }
        }
    );
}

      



Here's a working example:

public static void main(String[] args) throws Exception {
    showLoadingBar();
    Thread.sleep(10000L); // doing work outside of the EDT. Everything works fine
    hideLoadingBar();
}

      

Side note: the code that creates, fills in and makes the loadable frame visible must be enclosed in SwingUtilities.invokeLater()

, because it must run in the EDT.

+5


source


Swing uses a single thread model for its event dispatch (including paint updates), so you should never perform any lengthy or blocking operations on a Dispatching Thread (EDT).

Swing is also not thread safe, which means that you should never create or modify any UI component outside of EDT.

The basic concept of the global progress dialogue is to provide a structure that is independent of the work being performed, separates areas of responsibility, a progress dialogue that is responsible for displaying progress and the worker / engine responsible for doing the actual work.



The simplest solution is to use SwingWorker

. It provides mechanisms for running long running tasks on a separate thread, changing state, and notifying about progress.

enter image description here

public class TestProgressDialog {

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

    public TestProgressDialog() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                SwingWorker worker = new SwingWorker() {
                    @Override
                    protected Object doInBackground() throws Exception {
                        for (int index = 0; index < 100; index++) {
                            Thread.sleep(50);
                            setProgress(index);
                        }
                        return null;
                    }

                };

                ProgressDialog.showProgress(null, worker);

                System.exit(0);

            }

        });
    }

    public static class ProgressDialog extends JDialog {

        private JLabel message;
        private JLabel subMessage;
        private JProgressBar progressBar;

        public ProgressDialog(Component parent, SwingWorker worker) {

            super(parent == null ? null : SwingUtilities.getWindowAncestor(parent));
            setModal(true);

            ((JComponent)getContentPane()).setBorder(new EmptyBorder(8, 8, 8, 8));

            message = new JLabel("Doing important stuff");
            subMessage = new JLabel("Go make you're self a cup of coffee...");
            progressBar = new JProgressBar();

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(2, 2, 2, 2);
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;
            add(message, gbc);

            gbc.gridy++;
            add(subMessage, gbc);

            gbc.gridy++;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            add(progressBar, gbc);

            pack();

            worker.addPropertyChangeListener(new PropertyChangeHandler());
            switch (worker.getState()) {
                case PENDING:
                    worker.execute();
                    break;
            }

        }

        public static void showProgress(Component parent, SwingWorker worker) {

            ProgressDialog dialog = new ProgressDialog(parent, worker);
            dialog.setLocationRelativeTo(parent);
            dialog.setVisible(true);

        }

        public class PropertyChangeHandler implements PropertyChangeListener {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals("state")) {
                    SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
                    switch (state) {
                        case DONE:
                            dispose();
                            break;
                    }
                } else if (evt.getPropertyName().equals("progress")) {
                    progressBar.setValue((int)evt.getNewValue());
                }
            }

        }

    }

}

      

+7


source







All Articles