Animation Thread and EDT - java

As I discussed with Inerdia on the earlier post,
something is still strange When I'm in some JPanel (EDT for sure-I checked with the method check) and then I call some animation thread(the thread extend Thread) to start, inside the thread I'm not on EDT by check.
So I guess I should be because animation should be on EDT, so I wrapped the animate method with runnable and invokeAndWait(), but still got that in the animation thread I'm not on EDT, while calling to that code as I said earlier is on EDT, so, my invokeLater seems not to place that animation on EDT? why is that?
Relevant code(before wrapping the animate method with runnable and passing to invoke later:
So, being on a JPanel there is a line:
Animate(trainRailRoadTrack);
Implementation is:
void Animate(ArrayList<RailroadSquare> i_TrainRailRoadTrack) {
ArrayList<JPanelRailoadSquare> playerRailoadPanelsTrack = getRelevantRailroads(i_TrainRailRoadTrack);
new SuspendedAnimation(playerRailoadPanelsTrack).start();
jPanelBoard1.GetGameManager().EmptyPlayerSolution();
}
private class SuspendedAnimation extends Thread
{
private ArrayList<JPanelRailoadSquare> m_PlayerRailoadPanelsTrack;
public SuspendedAnimation(ArrayList<JPanelRailoadSquare> i_PlayerRailoadPanelTrack)
{
m_PlayerRailoadPanelsTrack = i_PlayerRailoadPanelTrack;
}
#Override
public void run()
{
m_IsAnimationNeeded = true;
for (JPanelRailoadSquare currRailoadSquare: m_PlayerRailoadPanelsTrack)
{
System.out.println("Is on Event dispatch thread: "+SwingUtilities.isEventDispatchThread());
currRailoadSquare.SetGoingTrain();
repaint();
try
{
Thread.sleep(150);
}
catch (InterruptedException e){}
currRailoadSquare.UnSetGoingTrain();
repaint();
}
}

Inside of SuspendedAnimation.run() you're not on the EDT. That's where you need to use invokeLater(), not when calling Animate():
#Override
public void run()
{
// We're outside the EDT in most of run()
m_IsAnimationNeeded = true;
for (JPanelRailoadSquare currRailoadSquare: m_PlayerRailoadPanelsTrack)
{
SwingUtilities.invokeAndWait(new Runnable() {
// The code that "talks" to Swing components has to be put on
// the EDT
currRailoadSquare.SetGoingTrain();
repaint();
});
// We want to keep sleeping outside the EDT.
try
{
Thread.sleep(150);
}
catch (InterruptedException e){}
SwingUtilities.invokeAndWait(new Runnable() {
currRailoadSquare.UnSetGoingTrain();
repaint();
}
}
}

Related

Java JProgressBar does not show up by setVisible(true)

I have a method like below.
ProgressWindow is a sub class of JFrame containing JProgressBar.
addProgress() increments a value in the JProgressBar.
If I call this method from a method in another class, a frame of ProgressWindow will show up but not JProgressBar and some JLabels inside the frame. They show up after the last line (System.out.println("finish")).
If I call this method in a main method in the class containing this method, then every component (Bar, labels...) instantly shows up.
What can I do for showing the window correctly?
static void search(){
ProgressWindow window = new ProgressWindow();
window.setVisible(true);
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
progressWindow.addProgress(); // increment progress value
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
The main problem is you seem to be calling search from the context of the Event Dispatching Thread.
The problem occurs because you are using execs.invokeAll which blocks until all the callables have finished running.
This means that the EDT is unable to process new events in Event Queue, including repaint events, this is why your UI is coming to a stand still...
There are a number of issues you are now going to face...
You should never update/modify a UI component from any thread other than the EDT
You should block the EDT for any reason
You seem to want to know when the search is complete, so you know need some kind of event notification...
The first thing we need is some way to be notified that the search has completed, this means you can no longer rely on search returning when the search is complete...
public interface SearchListener {
public void searchCompleted();
}
Next we need an intermeditate search method that builds the UI and ensure that the search is launched within it's own Thread...
static void search(final SearchListener listener) {
final ProgressWindow window = new ProgressWindow();
window.setVisible(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
search(listener, window);
}
});
t.start();
}
Then we need to modify the original search method to utilise the SearchListener interface to provide notification when the search is complete...
static void search(final SearchListener listener, final ProgressWindow window){
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
// This method needs to ensure that
// what ever it does to the UI, it is done from within
// the context of the EDT!!
progressWindow.addProgress();
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
listener.searchCompleted();
}
});
}
Now, without the source code for addProgress, I might be tempted to use
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressWindow.addProgress();
}
});
return null;
}
});
}
Instead...
Take a look at Concurrency in Swing for more details
Sounds like you what you're wanting to do is invoke the setVisible on the Swing UI thread, you can do this with invokeAndWait or invokeLater.
So something like:
final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});

Trouble with SwingUtilities.invokeLater() updating GUI

I have been trying this all day in different variations with little success. Could someone please help explain what I am doing wrong? I am just a beginner with regards to threads.
private JTextArea text = new JTextArea();
private JButton button = new JButton("Cancel");
public StatusFrame() {
text.setEditable(false);
this.add(text);
this.add(button, BorderLayout.EAST);
this.setSize(new Dimension(150, 100));
this.setVisible(true);
}
public void updateStatus(String textIn) {
text.setText(textIn);
}
public JButton getButton() {
return button;
}
In another class, I am calling methods which may take a while to complete. I want to be able to call the StatusFrame.updateStatus() method to keep the user informed on the progress.
This is what I have:
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
//do something
status.update("process 1 completed");
//do something else
status.updateStatus("Process 2 completed");
}
The frame appears but none of the code after the runnable appears to be run/processed. It just stops/blocks/something. But the GUI remains active
Thanks for any advice.
P.S.: I have tried using invokeAndWait() method but again not sure if I am doing it the right way. For now a quick fix would be preferred as I have not learned much about threads yet. Any instructions are welcome.
You have the concepts backwards.
Here's your code
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
//do something
status.update("process 1 completed");
//do something else
status.updateStatus("Process 2 completed");
You should execute the long running code in a thread, and use the SwingUtilities invokeLater method to update the GUI.
someMethod() {
// prevent GUI from freezing using threads
final Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
new Thread(r).start();
// inside the StatusFrame
//do something
SwingUtilities.invokeLater(new Runnable() {
public void run() {
update("process 1 completed");
}
);
//do something else sometime later
SwingUtilities.invokeLater(new Runnable() {
public void run() {
update("Process 2 completed");
}
);
I don't know if I was clear in my answer.
Execute SwingUtilities.invokeLater when you start your Java application to make sure Swing components are on the Event Dispatch thread (EDT).
From the EDT, invoke long running processes as a runnable thread.
In the runnable thread, since you're not on the EDT, execute SwingUtilities.invokeLater whenever you're updating Swing components. This ensures that Swing components are updated on the EDT.
Every Swing application should start with a class like this:
import javax.swing.SwingUtilities;
import com.ggl.text.entry.model.TextEntryModel;
import com.ggl.text.entry.view.TextEntryFrame;
public class TextEntry implements Runnable {
#Override
public void run() {
new TextEntryFrame(new TextEntryModel());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new TextEntry());
}
}
This class does 3 things.
Constructs the GUI data model.
Constructs the GUI JFrame.
Ensures that the Swing components are on the EDT.
You'll need to call the updates on EDT too. I would suggest to sleep on the main thread, to give GUI a chance to show up before any other work:
someMethod() {
// prevent GUI from freezing using threads
Runnable r = new Runnable() {
public void run() {
status = new StatusFrame();
}
};
SwingUtilities.invokeLater(r);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
//do something
r = new Runnable() {
public void run() {
status.update("process 1 completed");
}
};
SwingUtilities.invokeLater(r);
//do something else
r = new Runnable() {
public void run() {
status.update("Process 2 completed");
}
};
SwingUtilities.invokeLater(r);
}
See Concurrency in Swing.
You may find using a Swing Worker easier to work with since it uses a Thread and has methods that will allow you to update the GUI properly.

calling a time consuming method from a JButtonActionPerformed

In the following lines of code when Button1 is pressed the Jframe becomes unresponsive till the execution of the encode() method is completed. But I need to update a progress bar in the Jframe displaying the progress.
private void Button1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
if (flagState == 0) {
WavFile.decode(readWavFile, msg.getText(), key.getText().hashCode());
} else if (flagState == 1) {
WavFile.encode(readWavFile, msg.getText(), key.getText().hashCode());
}
} catch (WavFileException | IOException e) {
notes.setText(e.getMessage());
}
}
I thought of doing this
private void Button1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
if (flagState == 0) {
Thread t = new Thread(new Runnable() {
public void run() {
WavFile.decode(readWavFile, msg.getText(), key.getText().hashCode());
}
};)
t.start();
} else if (flagState == 1) {
Thread t = new Thread(new Runnable() {
public void run() {
WavFile.encode(readWavFile, msg.getText(), key.getText().hashCode());
}
};)
t.start();
}
} catch (WavFileException | IOException e) {
notes.setText(e.getMessage());
}
}
and update the progress bar from the encode() method.
But I understand that it will a strong coupling between the modules and i dont want that.
I also dont think that calling a new thread every time is a good idea ( thought of ExecutorService but not sure how to use it).
What should I do to make this into a decent piece code??
Threading is definitely something you have to introduce here. Anything that takes a significant amount of time to complete should not be run in the awt event thread.
Spawning a new thread each time the button is clicked is not inherently a problem. You should consider, though, that it may be possible to spawn many threads doing the same thing before even the first completes. You could use an Executor if you want, but it probably is not necessary.
As for tracking progress, I would add another thread that periodically queries the other thread and updates the progress bar as necessary. Here's how I would structure it:
private void Button1ActionPerformed(java.awt.event.ActionEvent evt) {
disableButton1();
final Thread t;
if (flagState == 0) {
t = new Thread(new Runnable() {
public void run() {
try {
WavFile.decode(readWavFile, msg.getText(), key.getText().hashCode());
} catch (WavFileException | IOException e) {
notes.setText(e.getMessage());
}
}
});
} else if (flagState == 1) {
t = new Thread(new Runnable() {
public void run() {
try {
WavFile.encode(readWavFile, msg.getText(), key.getText().hashCode());
} catch (WavFileException | IOException e) {
notes.setText(e.getMessage());
}
}
});
}
Thread monitor = new Thread(new Runnable() {
public void run() {
try {
while (notComplete(t)) {
setProgressBar(getProgress(t));
Thread.sleep(SLEEP_TIME);
}
t.join();
} finally {
enableButton1();
}
}
});
t.start();
monitor.start();
}
n the following lines of code when Button1 is pressed the Jframe becomes unresponsive till the execution of the encode() method is completed. But I need to update a progress bar in the Jframe displaying the progress.
you have issue with Concurency in Swing, you block the EDT, caused unresponsive GUI, until code ended
have look at SwingWorker for JProgressBar
use most scallable Swing Action instread of ActionListener
use implemented setEnabled() instead of if (flagState == 0) {
Multithreading is what you need, there is no other nice way i can think of don't worry about calling new threads, that's what they are there for, jvm has a thread pool ready to be used, this sort of things runs really good with threads, try it out!
Create a class that extends Runnable, implement the run method or make it call your current method, that should be enough to do this.
Also you could just make it sleep for a short time and check the status each time the sleep time goes out, if the process finished you can continue, if not, back to sleep for another short time, that way you don't have to ask that many times.
I hope it helps.

Why does my GUI still hang even after using SwingUtilities.invokeLater?

I have this ActionListener that gets called in the EDT. My plot() function is computationally heavy, it can easily take five seconds. It made the GUI hang as expected. I added the SwingUtilities.invokeLater code and it still hangs. Shouldn't the GUI be responsive now that I am spawning a separate thread for my heave computation?
final ActionListener applyListener = new ActionListener()
{
#CommitingFunction
public void actionPerformed(ActionEvent arg0)
{
/*Don't do plotting in the EDT :)*/
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
plot();
}
});
}
};
Not at all. InvokeLater is not producing a new thread. invokeLater exists to tell Swing explicitly "use the Event Dispatching Thread for this, but not right now". invoke and invokeLater exist to let you do operations that are only safe for the Event Dispatching Thread from other threads- not by doing them on those threads, but by telling the EDT to do them.
Your ActionListener will run very quickly, throwing the Runnable on Swing's event dispatching queue. Then when it gets that far, it will take five seconds to run the plot().
The only workaround is to refactor plot(). Use a SwingWorker (or similar multithreading strategy, but SwingWorker is probably the best for this) to actually move the logic of plot() onto a different thread. That thread cannot safely draw anything because it is not the Swing Event Dispatching Thread, so all of its draw operations need to be performed via invokeLater(). For efficiency reasons, you should try to do all of the drawing operations at once, on one invokeLater(), using results stored from your calculation.
You're doing the opposite of what you think you are. Instead of running your computation thread outside of the EDT, you're explicitly calling it within it!
SwingUtilities.invokeLater() queues up the runnable for invocation at a later time, in the EDT! You want to use SwingWorker instead.
invokeLater add a task to the GUIs work queue. It will be invoked after all other tasks have been performed, however it still uses the GUI thread.
I suggest you look at using an ExecutorService.
As #Adam suggests, any actual drawing it does needs to be done via invokeLater.
You don't show what is inside the plot() function, but you should not put any painting in there. Compute whatever you want in the new thread, and do the painting in the EDT. To do this, it is better to use SwingWorker
Here is what I did for my company's app, this is some pseudo code because of legal reasons, but the jist of it is that if the screen is unresponsive, it will reboot the GUI. Whenever you use SwingUtilities to kick off the EDT, in that same init block, create two watcher threads. One thread will simply perform an action on the EDT thread using Swing utilities. Another thread will monitor the first thread to see if feels the first thread is responsive. The first thread will only acknowledge responsiveness if it can perform a very simple command.
set isEDTCheck to true when running in normal fashion, false in debug mode (otherwise you'll constantly get rebooted.
if (isEDTCheck) {
new Thread("EDTHeartbeat") {
#Override
public void run() {
Runnable thisThingYouDo = new Runnable() {
public void run() {
int x = 0;
}
};
while (true) {
// first thread says we are waiting, aka bad state
edtwait=true;
try {
javax.swing.SwingUtilities.invokeAndWait(thisThingYouDo);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// first thread says we are not waiting, good state
edtwait=false;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
new Thread("EDTValidator") {
#Override
public void run() {
while (true) {
// is first thread in bad state?
if (edtwait) {
try {
Thread.sleep(3000);
// after 3 seconds are we still in bad state? if so, get rid of initial frame, pop up a dialog box in AWT that does no commands
if (edtwait) {
mainFrame.setVisible(false);
new Dialog();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
}
public class Dialog extends Frame {
private static final int WIDTH = 400;
private static final int HEIGHT = 300;
Frame f = null;
public Dialog() {
f = this;
hasSomethingBeenEntered=false;
this.setTitle("APP PROBLEM DETECTED");
this.setSize(WIDTH, HEIGHT);
this.setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - myapp.width, 0);
Panel p1 = new Panel() {
#Override
public void paint(final Graphics g) {
int left = Dialog.WIDTH/2 - 45; // don't use WIDTH shadowed by Panel class
int top = Dialog.HEIGHT/2 - 20; // same as above
g.drawString("APP HAS DETECTED A PROBLEM", left, top);
}
};
this.add("Center", p1);
this.setAlwaysOnTop(true);
TextArea tb = new TextArea("APP HAS DETECTED A MAJOR PROBLEM\nIT WILL NOW RESTART IN 5 SECONDS");
this.add(tb);
this.setVisible(true);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
restartApp();
}
private void restartApp() {
Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"cd C:\\Progra~1\\Common~1 && C:\\Progra~1\\Common~1\\MyAppDir\\myjavaapp.jar\"");
System.exit(0);
}

calling invokeAndWait from the EDT

I have a problem following from my previous problem. I also have the code SwingUtillities.invokeAndWait somewhere else in the code base, but when I remove this the gui does not refresh. If I dont remove it the error I get is:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
at java.awt.EventQueue.invokeAndWait(Unknown Source)
at javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
at game.player.humanplayer.model.HumanPlayer.act(HumanPlayer.java:69)
The code in HumanPlayer.act is:
public Action act(final Action[] availiableActions) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
gui.update(availiableActions);
}
});
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
return getActionPerfomed();
}
Image of threads when in debug as screen doesn't paint:
alt text http://img684.imageshack.us/img684/6669/69288941.png
Text version of stack:
ui.startup.LoginScreen at localhost:51050
-> Deamon Thread [AWT-Windows] (Running)
-> Thread [AWT-Shutdown] (Running)
-> Thread [AWT-EventQueue-0] (Running)
-> Thread [DestroyJavaVM] (Running)
The answer was instead of making the call
new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
from the EDT, make it execute on a new (non EDT) thread so that later when invokeAndWait is called it functions as correctly as the thread running that command is not the EDT. The amended code is as follows:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
}
});
t.start();
invokeAndWait() is meant to be called from the non-GUI thread. It sends a Runnable object to the GUI thread where it will be executed.
There's no point in sending a Runnable object from the GUI-thread to itself. It has the same effect as calling run() on the Runnable object directly.
You can check before if your current calling thread is already the event dispatcher:
private void syncExec(final Runnable r) {
try {
if (EventQueue.isDispatchThread()) r.run();
else EventQueue.invokeAndWait(r);
} catch (final Exception e) {
Throws.throwRuntime(e);
}
}
Note that SwingUtilities.invokeAndWait(Runnable) simply delegates to the EventQueue.
Based on the comments, it appears you are not repainting the frame once the actions are completed. If you do not, then the screen will only be updated at what seems to be random times (when another window moves in front, perhaps).
Inside gui.update, I suggest you make the last line:
myFrame.repaint();
(more or less, depending on your circumstances).
Edit: As it turns out, the actual problem is this loop:
synchronized(performedAction){
while(!hasPerformedAction()){
try {
performedAction.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setPerformedAction(false);
}
Since there is only one application thread (which happens to be the EDT), the result of hasPerformedAction() can never change (assuming it's a simple getter). There is no other thread to change the value. Since this infinite loop is on the EDT, the GUI can never be repainted; hence it locks up.
When using XChart java library you can show your chart on button click with this code:
JButton btn = new JButton("View chart");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
new SwingWrapper(yourChart).displayChart();
}
});
t.start();
}
});
try to execute your code from this
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
}
});

Categories