Search code examples
javaswingjframeswingworker

java SwingWorker dialog is not shown


In Netbeans, I created a GUI project which uses the frame frontend that I can add components and double click to edit their events. I am referring to the window which has "Source", "Design" and "History" tabs.

Here are the components and relations:

1- A Button which opens a file chooser.

2- a TextArea to show the result of the file chooser. If user selects a file, it will show the file name in the TextArea; otherwise it will write "canceled by user".

3- Meanwhile, if user selects a file, I want to open a "please wait" dialog witch SwingWorker and do some works in the background.

Problem is that, when the user selects a file, I don't see the please wait dialog!! The full code generated by Netbeans is available at pastebin. Part of the code is shown here:

private void OpenSongFileActionPerformed(java.awt.event.ActionEvent evt) {                                              
    // TODO add your handling code here:
    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setAcceptAllFileFilterUsed(false);
    FileNameExtensionFilter filter = new FileNameExtensionFilter("MP3 files", "mp3");
    fileChooser.addChoosableFileFilter(filter);
    fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
    int result = fileChooser.showOpenDialog(this);
    if (result != JFileChooser.APPROVE_OPTION) {
        //ReadInfo.setText("No song has been selected");
        System.out.println("OpenSongFile canceled by user");
        return;
    }
    final JDialog loading = new JDialog(this);
    JPanel p1 = new JPanel(new BorderLayout());
    p1.add(new JLabel("Please wait..."), BorderLayout.CENTER);
    loading.setUndecorated(true);
    loading.getContentPane().add(p1);
    loading.pack();
    loading.setLocationRelativeTo(this);
    loading.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
    loading.setModal(true);
    SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
        @Override
        protected String doInBackground() throws InterruptedException {
            for (int i = 0; i < 10000; i++) 
                for (int j = 0; j < 10000; j++) 
                    ;
            return "hello";
        }
        @Override
        protected void done() {
            loading.dispose();
        }
    };
    worker.execute();
    loading.setVisible(true);
    try {
        worker.get();
    } catch (Exception e1) {
        e1.printStackTrace();
    }

    File selectedFile = fileChooser.getSelectedFile();
    ReadInfo.setText("Selected file: " + selectedFile.getAbsolutePath());
}                              

P.S: I used the SwingWorker code explained here.


Solution

  • worker.get(); will block until the SwingWorker returns, meaning you're blocking the EDT, preventing the dialog from been shown.

    Instead, make use of the SwingWorkers PropertyChangeListener support and monitor for the START and DONE events

    SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
        @Override
        protected String doInBackground() throws InterruptedException {
            Thread.sleep(5000);
            return "hello";
        }
    
        @Override
        protected void done() {
            loading.dispose();
        }
    };
    worker.addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            System.out.println(evt.getPropertyName());
            Object value = evt.getNewValue();
            if (value instanceof SwingWorker.StateValue) {
                SwingWorker.StateValue state = (SwingWorker.StateValue) value;
                switch (state) {
                    case DONE: {
                        try {
                            String result = worker.get();
                            JOptionPane.showMessageDialog(null, result);
                        } catch (InterruptedException | ExecutionException ex) {
                            ex.printStackTrace();
                        }
                    }
                    break;
                }
            }
        }
    });
    worker.execute();
    loading.setVisible(true);
    

    The other issue is that your loop is probably running so fast that the window is been closed before it's realised on the screen.

    For example, I simply used Thread.sleep to pause the doInBackground method for 5 seconds...

    import java.awt.BorderLayout;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.concurrent.ExecutionException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.JDialog;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    
    public class Memory extends JFrame {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    makeItSo();
                }
            });
        }
    
        public static void makeItSo() {
            final JDialog loading = new JDialog();
            JPanel p1 = new JPanel(new BorderLayout());
            p1.add(new JLabel("Please wait..."), BorderLayout.CENTER);
            loading.setUndecorated(true);
            loading.getContentPane().add(p1);
            loading.pack();
            loading.setLocationRelativeTo(null);
            loading.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
            loading.setModal(true);
            SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
                @Override
                protected String doInBackground() throws InterruptedException {
                    Thread.sleep(5000);
                    return "hello";
                }
    
                @Override
                protected void done() {
                    loading.dispose();
                }
            };
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    System.out.println(evt.getPropertyName());
                    Object value = evt.getNewValue();
                    if (value instanceof SwingWorker.StateValue) {
                        SwingWorker.StateValue state = (SwingWorker.StateValue) value;
                        switch (state) {
                            case DONE: {
                                try {
                                    String result = worker.get();
                                    JOptionPane.showMessageDialog(null, result);
                                } catch (InterruptedException | ExecutionException ex) {
                                    ex.printStackTrace();
                                }
                            }
                            break;
                        }
                    }
                }
            });
            worker.execute();
            loading.setVisible(true);
        }
    
    }