-2

Possible Duplicate:
SwingWorker in Java

I have several classes that need to work together but, they're not.

For one, I have Main:

public class Main
{

 public static void main(String[] args)
 {

  SwingUtilities.invokeLater(new Runnable()
  {

   @Override
   public void run()
   {

   //JFrame dummy for JDialog errors
   modal = new JFrame();

   new PrimaryErrorDialog("Title", "Message", e, false);

    JFrame masterWindow = new JFrame();
     masterWindow.setVisible();
   }
  }
 }
}

It creates PrimaryErrorDialog class:

private JDialog dialog = this;
private JTextArea text;
private JPanel buttonContainer;
private JButton sendErrorReportT, sendErrorReportF;

public PrimaryErrorDialog(String title, String message,
final Exception error, final boolean exit)
{
 super(Main.modal, title, true);

 //JButton for sending error report
 sendErrorReportT = new JButton("Send Error Report");
 sendErrorReportT.addActionListener(new ActionListener()
 {
  @Override
  public void actionPerformed(ActionEvent e)
  {
   dialog.dispose();

   dialog = new JDialog(Main.modal, "Sending...", true);

   Worker thread = new Worker(error);
   thread.start();

   JProgressBar progress = new JProgressBar();
   progress.setIndeterminate(true);

   dialog.add(progress);    
   dialog.pack();
   dialog.setVisible(true);
  }
 });

 //JButton for not sending error report
 sendErrorReportF = new JButton("Don't send error report");
 sendErrorReportF.addActionListener(new ActionListener()
 {
  @Override
  public void actionPerformed(ActionEvent e)
   {
    dialog.dispose();

    if (exit)
    {
     System.exit(0);
    }
   }
  });

 buttonContainer = new JPanel();
 buttonContainer.add(sendErrorReportT);
 buttonContainer.add(sendErrorReportF);

 add(text);
 add(buttonContainer);

 pack();
 setLocationRelativeTo(null);
 setVisible(true);
}

public void cleanUpAndContinue()
 {
  dialog.dispose();
  dialog = new JDialog(Main.modal, "title", true);
  dialog.add(/*Jbutton with listener that disposes this dialog*/)
  dialog.setVisible(true);
 }

It calls thw Worker class that extends Thread:

public class Worker extends Thread
{
    Exception e;

    public Worker(Exception error)
    {
        e = error;
    }

    @Override
    public void run()
    {
    //do something that takes time
     PrimaryErrorDialog.cleanUpAndContinue();
    }

It goes back to PrimaryErrorDialog, which would then have to inform the user that task was completed, and then terminate that dialog.

Then we go back to main where masterWindow is created.

All of this code is executed prior to creation of masterWindow, because this segment is ran when an error occurrs (if LAF is not present, .proprties files are missing, etc)...

That's why I created the dummy JFrame, so JDialog can attach to it, I didn't wan't to make it a JFrame.

This code is also executed later in program, for "real" runtime errors, some classes just have a bit different parameters and/or constructors.

However, this does not work, I have tried it in milion ways, i tried with SwingWorker, nothing seems to do what I want. Usually the email code is not even reached, or program doesn't wait for the dialogs to be disposed...

And what do I want?

Error occurrs. Dialog pops up telling me an error occurred and asking me if I want to send an error report. I say no - dialog closes, taking down the whole program if error is fatal. I say yes - dialog closes, new one opens with indetermined progressbar, WHILE email with stacktrace is being sent in the background. Email gets sent, dialog with progressbar closes and a new one opens telling my my error report was sent. I press ok and dialog closes, taking down the whole program if error is fatal, else, continues where it left of from Main class.

Note: An error can occurr in any class, it doesn't be from Main only...

Community
  • 1
  • 1
Karlovsky120
  • 6,212
  • 8
  • 41
  • 94
  • 2
    What was wrong with the answer provided in your [previous question](http://stackoverflow.com/q/12641887/1076463). Why not simply edit that question? Note: your `Worker` class should not access/modify any Swing components (as it does not run on the EDT). So that `cleanUpAndContinue` call should either be wrapped in an `invokeLater`, or simply removed – Robin Sep 28 '12 at 17:47
  • 1
    You need to go back to your previous question and mark David's answer as accepted if you can. He deserves credit for the answer he provided you. While it had an initial problem, it has now been updated correctly. – MadProgrammer Sep 28 '12 at 21:32
  • shaking head in disbelief: you got a correct answer **twice** (even before the one that @Robin cited - http://stackoverflow.com/q/12397980/203657) and still _insist_ on doing it completely wrong? Why do you ask when you don't take the advice given? That's wasting everybody's time, trying over and over again to explain the exact same thingies and come up with answers ... – kleopatra Sep 29 '12 at 09:14

2 Answers2

4

I've not read you're previous question, however...

The basic problem you have is needing to notify the dialog (which is within the EDT) that the background thread has completed (as well as provide feedback to the user if possible).

This is covered in the Concurrency in Swing lesson.

Below is a simple proof of concept. Personal, I would normally construct a custom panel and put it onto the a JDialog, but this just a proof of concept.

public class TestSwingWorker {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {

                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                final JDialog dialog = new JDialog((Frame)null, "Happy, Happy, Joy, Joy", true);
                // This is so I can get my demo to work, you won't need it...
                dialog.addWindowListener(new WindowAdapter() {

                    @Override
                    public void windowClosing(WindowEvent e) {
                        System.exit(0);
                    }

                });

                JPanel panel = new JPanel(new GridBagLayout());
                panel.setBorder(new EmptyBorder(8, 8, 8, 8));
                dialog.setContentPane(panel);

                // You'll need you own icon...
                JLabel lblIcon = new JLabel(new ImageIcon(getClass().getResource("/waiting-64.png")));
                JLabel lblMessage = new JLabel("<html>Hard and work here<br>Please wait...</html>");
                final JProgressBar progressBar = new JProgressBar();

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.anchor = GridBagConstraints.NORTH;
                gbc.weighty = 1;
                gbc.insets = new Insets(2, 2, 2, 2);
                gbc.gridheight = GridBagConstraints.REMAINDER;
                dialog.add(lblIcon, gbc);

                gbc.gridheight = 1;
                gbc.gridx = 1;
                gbc.gridy = 0;
                gbc.anchor = GridBagConstraints.WEST;
                gbc.weighty = 0;
                gbc.weightx = 1;
                dialog.add(lblMessage, gbc);

                gbc.gridy = 1;
                gbc.anchor = GridBagConstraints.NORTH;
                gbc.weighty = 1;
                dialog.add(progressBar, gbc);

                dialog.pack();
                dialog.setLocationRelativeTo(null);

                MyWorker worker = new MyWorker();
                // Get notification back from the worker...
                worker.addPropertyChangeListener(new PropertyChangeListener() {

                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {

                        MyWorker worker = (MyWorker) evt.getSource();
                        // Progress has been updated
                        if (evt.getPropertyName().equalsIgnoreCase("progress")) {

                            progressBar.setValue((Integer)evt.getNewValue());

                        // The state of the worker has changed...
                        } else if (evt.getPropertyName().equalsIgnoreCase("state")) {

                            if (worker.getState().equals(SwingWorker.StateValue.DONE)) {

                                dialog.dispose();

                            }

                        }

                    }
                });

                worker.execute();

                dialog.setVisible(true);

            }

        });

    }

    protected static class MyWorker extends SwingWorker<Object, Object> {

        @Override
        protected Object doInBackground() throws Exception {

            // My long running task...
            for (int index = 0; index < 100; index++) {

                // Change this to make it faster or slower...
                Thread.sleep(250);
                setProgress(index);

            }

            return null;

        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
3
  • dirty hack wrap dialog.setVisible(true); into invokeLater()

  • use SwingWorker or Runnable#Thread instead or plain Thread

  • is there issue that you ignored answers and especially comments from your previous question

  • Swing Gui doesn't care about output from Thread, because there isn't implemented notifiers for Event Dispatch Thread, you have to invoke that by invokeLater, or to use SwingWorker,

  • SwingWorkers methods done, publish and progress can notify EDT correctly

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Well, one guy came up with the solution ,and then you proved it wouldn't work, and since the way I asked is not how I should have done it, I figured I'd have more luck with this... However, this answers won't work... I need to know what part of my code is wrong... I really tried it in many different ways, and it's not that dfficullt what I'm trying to ahcieve, I thik I could do it with both, swingworker and thread or runnable#thread, I just keep messing something up... I've went trought a bunch of tutorial and it never works. I've been trying to figure out this for 7 hours straight now... – Karlovsky120 Sep 28 '12 at 17:51
  • 3
    he is excelent contributor, but by mistake post an wrong code, all answerers here are peoples, often with own mistakes – mKorbel Sep 28 '12 at 17:54
  • 2
    [here is one hint](http://stackoverflow.com/a/7049095/714968) , there are four methods and all methods implemented there notified EDT properly – mKorbel Sep 28 '12 at 17:59
  • 1
    I agree with mKorbel, David's updated code is correct. – MadProgrammer Sep 28 '12 at 21:28
  • I hate SwingWorker, and without PropertyChangeListener is quite empty and useless +1 – mKorbel Sep 28 '12 at 21:32
  • I, personally, very rarely use it, but that's got more to do with having several years of library code dedicated to making syncing with the EDT easier (before `SwingWorker` was introduced) - doesn't mean I wouldn't recommend it to newbies, as trying to explain things like `.invokeLater` and `.invokeAndWait` would be more of a headache :P – MadProgrammer Sep 28 '12 at 21:35