Preventing GUI From Freezing When Calling SwingWorker.get( )

◇◆丶佛笑我妖孽 提交于 2019-12-01 22:14:04

问题


I have a program where I am loading a file while at the same time I am displaying a window to inform the user that the file is being loaded. I decided to make a FileLoader class that was a SwingWorker which actually handled loading the file and a ProgressWindow that implements PropertyChangeListener to inform the user about the status of the SwingWorker that was passed into it.

My code currently looks like this:

FileLoader loader = new FileLoader(filePath);
new ProgressWindow(loader, "Loading File", "Loading File");
//ProgressWindow's constructor calls loader.execute() inherited from SwingWorker
doc = loader.get(); //GUI Freezes when called

The problem is that whenever I call loader.get(), it freezes the GUI, thus the progress bar in the Progress Window doesn't run and the whole thing is pointless. As far as I can tell, this is because the thread controlling the GUI is the same thread that calls loader.get(), which goes on hold while loader.execute() is running.

So far, I've tried creating a new thread for either the loader.get() command or the loader.execute() method, and calling SwingUtilities.invokeLater() on the thread, but then the whole program freezes.

I've considered creating a ChangeListener for when SwingWorker.isDone() and then running loader.get(), but this would require some reworking of my code that I would rather not do.

Could anyone tell me what the best way is to get this to work?


回答1:


get() is like join() in that it will block until called, and will wait for the SwingWorker to finish before being called. Using it wrongly can completely nullify all the advantages of using a SwingWorker in the first place.

Solution: Don't call get() until you know that the SwingWorker is done with its processing, by either calling it in the SwingWorker's done() method, or if you need to call it from the calling code, then in a PropertyChangeListener that has been added to the SwingWorker when the SwingWorker's "state" property is SwingWorker.StateValue.DONE.

Something like:

  final FileLoader loader = new FileLoader(filePath);

  loader.addPropertyChangeListener(new PropertyChangeListener() {
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
        if ("state".equals(evt.getPropertyName())) {
           // since DONE is enum, no need for equals(...) method
           if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
              try {
                 loader.get();
              } catch (InterruptedException e) {
                 e.printStackTrace();
              } catch (ExecutionException e) {
                 e.printStackTrace();
              }
           }
        }
     }
  });

  new ProgressWindow(loader, "Loading File", "Loading File");

Note: code not compiled nor tested

Edit: try/catch added.




回答2:


So far, I've tried creating a new thread for either the loader.get() command or the loader.execute() method, and calling SwingUtilities.invokeLater() on the thread, but then the whole program freezes.

If you call SwingUtilities.invokeLater() on the thread that will execute the thread in the EDT which freezes the GUI. Instead, run the thread by calling it's start() method and only use SwingUtilities.invokeLater() when you need to update the progress bar in the PropertyChangeListener.




回答3:


I have create a WorkerThread class which take care of Threads and GUI current/main thread . i have put my GUI application in construct() method of WorkerThread when an event fire to start XXXServer then all threads are activate and GUI work smoothlly wihout freeze. have a look.

/**
* Action Event
* 
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ae) {
    log.info("actionPerformed begin..." + ae.getActionCommand());

    try {
        if (ae.getActionCommand().equals(btnStart.getText())) {
             final int portNumber = 9990;
             try {

                 WorkerThread workerThread = new WorkerThread(){
                    public Object construct(){

                        log.info("Initializing the Server GUI...");
                        // initializing the Server
                         try {
                            xxxServer = new XXXServer(portNumber);
                            xxxServer.start();
                            btnStart.setEnabled(false);                             
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
                            e.printStackTrace();
                        }
                        return null;
                    }
                };workerThread.start();
                } catch (Exception e) {
                    log.info("actionPerformed() Start button ERROR..." + e.getMessage());
                    e.printStackTrace();
             }


        } else if (ae.getActionCommand().equals(btnStop.getText())) {
            log.info("Exit..." + btnStop.getText());
            closeWindow();
        }

    } catch (Exception e) {
        log
            .info("Error in ServerGUI actionPerformed==="
                + e.getMessage());
    }

}


来源:https://stackoverflow.com/questions/11547537/preventing-gui-from-freezing-when-calling-swingworker-get

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!