0

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.

Community
  • 1
  • 1
mahmood
  • 23,197
  • 49
  • 147
  • 242

1 Answers1

1

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);
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I doubt it the background task is running because the no operation loops (delays) are not executed. Please explain more. – mahmood Apr 21 '17 at 07:58
  • How do you know, you don't print anything in the `doInBackground` method. I have no doubt it's working, unless `if (result != JFileChooser.APPROVE_OPTION) {` is `true`, it has to run. I also have no doubt that `get` is a blocking method, it's document as such. Try the updated example. If it still doesn't work, then you'll need to supply a runnable example which demonstrates your issue. The other issue would be that the worker completes so fast that the window is closed before it can be realised on the screen – MadProgrammer Apr 21 '17 at 08:02
  • Which of the import lines is related to `addPropertyChangeListener`? – mahmood Apr 21 '17 at 08:12
  • `import java.beans.PropertyChangeEvent;` and `import java.beans.PropertyChangeListener;` – MadProgrammer Apr 21 '17 at 08:13
  • One more thing. I see "please wait" message inside the frame (which contains buttons and other staffs). I want to pop up a window/frame (without any close or ok button) which shows please wait and the disapears – mahmood Apr 21 '17 at 08:33
  • 1
    Well, the second example I posted, which is based on your code, does that. It's display "ontop" of your other frame. You use the frames [`glassPane` to produce a "blocked" view](http://stackoverflow.com/questions/16639950/jframe-glasspane-is-also-over-jdialog-but-shouldnt/16641115#16641115) or something like [this instead](http://stackoverflow.com/questions/12982863/secure-desktop-mode-effect-for-java-application/12983564#12983564) – MadProgrammer Apr 21 '17 at 08:54