-2

i am running a long task on the click of a button. I want to show a message that the task has started. Using swingworker, the JOptionPane creates the message box but its contents are left blank till the task is complete. I guess my EDT is getting blocked and hence the GUI does not get updated unless the task is complete. Is there any way to show this (swingutils.invokelater cannot be used as i need the display at the start of the task) Sample code :-

public class myClass  {
private JFrame frame;
private display1 dis;

class display1 extends SwingWorker<Void,Void>
{
    public Void doInBackground() throws InterruptedException
    {
    JOptionPane.showMessageDialog(null,
                "Task Started");
        return null;
    }
}
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                myClass window = new myClass();
                window.frame.setVisible(true);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


 public myClass() {
    initialize();
}


private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            dis=new display1();
            dis.execute();

         System.out.println("starting");
           for(int i=0;i<10000;i++)
               System.out.println("this is " +i);// Long task


         System.out.println("Finished");
        }
    });
    btnNewButton.setBounds(166, 228, 89, 23);
    frame.getContentPane().add(btnNewButton);

}
}
sam
  • 59
  • 1
  • 1
  • 7
  • What's `display1`? You're running a long task in the context of the EDT which explains why your UI is blank – MadProgrammer Apr 18 '17 at 10:36
  • display1 is the name of the class which implements SwingWorker. I know the reason why it is not working. All that i am asking is a way to show the dialogue that task is started and simultaneously execute the task (The task contains manipulating certain GUI components ) – sam Apr 18 '17 at 10:41
  • 2
    Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses – MadProgrammer Apr 18 '17 at 11:04
  • The program above is very lucid and pretty understandable. I posted the full code for better visibility/understanding and the code in itself is very simple and short. Stop unnecessary commenting if you do not have anything positive to contribute – sam Apr 18 '17 at 11:10
  • Excuse me for trying to understand your problem in an attempt to help you find a solution, but `for(int i=0;i<10000;i++)` is going to block the EDT which could prevent the UI from been updated, but I guess that's irrelevant and unhelp, then I'm sorry – MadProgrammer Apr 18 '17 at 11:19

2 Answers2

2

Because SwingWorker notifies any PropertyChangeListener on the event dispatch thread, simply listen for the bound property state. Possible values include DONE, PENDING and STARTED. This TaskListener is an example that writes to the console, but it's perfectly safe to update a label in your implementation of propertyChange(). A modal dialog is permissible but superfluous.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
0

Anything run in invokeLater(Runnable); is send to Event Dispatch Thread "gui-thread". Your method initialize() run in EDT which is ok, but you need to keep in mind that any action related to UI is being processed in EDT. So if user click on button, ActionListener code is executed in EDT. Any long running task executed in EDT blocks from processing of another UI events. Therefore you need to move your "long task" to separate thread e. g. to SwingWorker.

If you need to display something before running the task, just put it before calling swingWorker.execute(); (make sure, given code is executed in EDT):

button.addActionListener(new ActionListener() {
    @Override public void actionPerformed(ActionEvent arg0) {
        // we are are in EDT = dialog will be displayed without any problems
        JOptionPane.showMessageDialog(null, "About to start");
        // executes SwingWorker's doInBackground task
        new BackgroundTask().execute(); 
    }
});

Following code illustrates how to work with SwingWorker:

class BackgroundTask extends SwingWorker<
        String/*background task's result type*/, 
        Integer/*inter-step's result type*/
        >
{
    /**
     * This method is designed to perform long running task in background 
     * i. e. in "non-EDT" thread = in SwingWorker thread.
     * 
     * After method is completed, {@link #done()} is called, which is 
     * executed in "EDT" (gui-thread).
     * 
     * Note, you can {@link #publish(Integer)} progress to {@link #process(List<V> chunks)} 
     * which is executed in "EDT" (gui-thread).
     *  
     * You can also use {@link SwingUtilities#invokeLater(Runnable)}
     * to send "message" to "EDT" which contains code to be executed
     * This is similar to {@link #publish(Object)} except not-processed-yet 
     * messages are not collected and processed all at once like in 
     * {@link #publish(Object)} case.
     */
    @Override
    protected String doInBackground() throws Exception {
        // or you can put JOptionPane.showMessageDialog(null, "About to start"); 
        // in ActionListener before calling swingWorker.execute();
        SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null, "About to start"));
        // System.out.println("starting");
        for(int i = 0; i < 10000; i++) {
            // System.out.println(i);
            publish(i);
        }
        // result of the background task
        return "Task completed"; 
    }

    /**
     * Method is executed in "EDT" after calling {@link #publish(Integer)}. 
     * 
     * This is the right place to update GUI about inter-step result.
     * 
     * Note, this method is not executed immediately after calling {@link #publish(Integer)}, 
     * since EDT can process at this time sime other GUI tasks.
     * Therefore, list contains all inter-step results send from SwingWorker 
     * to EDT which were not processed yet. 
     */
    @Override
    protected void process(List<Integer> chunks) {
        for (int number : chunks) {
            textArea.append(number + "\n");
        }
    }

    /**
     * Method is executed in "EDT" after {@link #doInBackground()} is finished.
     * This is the right place to update GUI about final result.
     */
    @Override
    protected void done() {
        String result = get(); // returns result of the doInBackground();
        JOptionPane.showMessageDialog(null, result);
    }
}
matoni
  • 2,479
  • 21
  • 39