baka1408
baka1408

Reputation: 433

Multi threading with Swing progress bar

I am running out of ideas how to make my progress bar responsive during performing RMI connection, so I have decided to ask You for help.

Here's the code :

Thread performLogin = new Thread(new Runnable()
{

    @Override
    public void run()
    {
        LoginResult = TryLogin();
    }
});

performLogin.start();
WaiterFrame.setVisible(true);
SetProgressDialog();

try
{
    performLogin.join();
}
catch(InterruptedException exc)
{
    System.err.println(exc.getLocalizedMessage());
}

if (LoginResult)
{ ... }


WaiterFrame.setVisible(false);
this.dispose();

Progress bar is unresponsive - does not animate as it should while performing performLogin thread. I was trying to run progress bar frame on the other thread too, but result was the same (as well as using Eventqueue.invokelater()).

Upvotes: 0

Views: 1566

Answers (3)

baka1408
baka1408

Reputation: 433

Thank You very much MadProgrammer! Progress bar works as intended with SwingWorker usage. I'm posting code if someone would encourage same problem in future :

PerformLogin = new SwingWorker<Boolean, Object>()
{
    @Override
    protected Boolean doInBackground() throws Exception
    {
        LoginResult = TryLogin();
        if (LoginResult)
        {
            MainF = new MainFrame();
            MainF.Connection = DataEntry.TestConnection;
            MainF.prepareFormToShow();
        }
        return LoginResult;
    }

    @Override
    protected void done()
    {
        if (LoginResult == true)
        {
            EventQueue.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        MainF.setVisible(true);
                        WaiterFrame.setVisible(false);
                    }
                });
        }
        else
        {
            setVisible(true);
            this.cancel(true);
            JOptionPane.showMessageDialog(null, "Wrong adress!",
            "Błąd",JOptionPane.WARNING_MESSAGE);
        }
    }

and

WaiterFrame.setVisible(true);
PerformLogin.execute();

in the main thread

Upvotes: 0

MadProgrammer
MadProgrammer

Reputation: 347184

The likely cause is performLogin.join(); is blocking the Event Dispatching Thread, making the UI non-responsive.

Two things to remember with Swing (and most GUI frameworks);

  1. It is single threaded, meaning if your block the EDT for any reason, it will no longer able to process new events or perform repaints
  2. It's not thread safe, so you should never modify the state of the UI from outside the context of the EDT.

You could use a SwingWorker, which would allow you to run your long running process in a background thread but provides a number of mechanism through which you can send updates back to the EDT safely.

See Worker Threads and SwingWorker for more details and Issues with SwingWorker and JProgressBar for an example

Upvotes: 1

Ulises
Ulises

Reputation: 9625

If you're using Java 8 you could try something like this:

CompletableFuture<LoginResult> loginResult = CompletableFuture.supplyAsync(this::tryLogin);
WaiterFrame.setVisible(true);
setProgressDialog();
loginResult.thenAccept(lr -> {
   //do your thing 
   WaiterFrame.setVisible(false); 
})

There are other options to "thenAccept" depending on what you need to do. "thenAccept" only consumes the the content of the Future.

The same could be accomplished using Guava's ListenableFuture and Executors if Java 8 is not an option.

Upvotes: 1

Related Questions