Java Swing Threading with Updatable JProgressBar - java

First off I've been working with Java's Concurrency package quite a bit lately but I have found an issue that I am stuck on. I want to have and Application and the Application can have a SplashScreen with a status bar and the loading of other data. So I decided to use SwingUtilities.invokeAndWait( call the splash component here ). The SplashScreen then appears with a JProgressBar and runs a group of threads. But I can't seem to get a good handle on things. I've looked over SwingWorker and tried using it for this purpose but the thread just returns. Here is a bit of pseudo code. and the points I'm trying to achieve.
Have an Application that has a SplashScreen that pauses while loading info
Be able to run multiple threads under the SplashScreen
Have the progress bar of the SplashScreen Update-able yet not exit until all threads are done.
Launching splash screen
try {
SwingUtilities.invokeAndWait( SplashScreen );
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }
Splash screen construction
SplashScreen extends JFrame implements Runnable{
public void run() {
//run threads
//while updating status bar
}
}
I have tried many things including SwingWorkers, Threads using CountDownLatch's, and others. The CountDownLatch's actually worked in the manner I wanted to do the processing but I was unable to update the GUI. When using the SwingWorkers either the invokeAndWait was basically nullified (which is their purpose) or it wouldn't update the GUI still even when using a PropertyChangedListener. If someone else has a couple ideas it would be great to hear them. Thanks in advance.
I actually got ready to post better code to help out and found my solution. I thank you for all who helped.

For running a series of operations in the background and reporting progress, use SwingWorker.
The background method does the background processing.
Use the publish method to post periodic status updates.
Override the process method to handle the updates (process always executes on the EDT).
progressBar = new JProgressBar();
sw = new SwingWorker<Boolean,Integer>() {
protected Boolean doInBackground() throws Exception {
// If any of the operations fail, return false to notify done()
// Do thing 1
publish(25); // 25% done
// Do thing 2
publish(50); // 50% done
// Do thing 3
publish(75); // 75% done
// Do thing 4
return true;
}
protected void process(List<Integer> chunks) {
for (Integer i : chunks)
progressBar.setValue(i);
}
protected void done() {
try {
boolean b = get();
if (b)
progressBar.setValue(100); // 100% done
else
// Notify the user processing failed
}
catch (InterruptedException ex) {
// Notify the user processing was interrupted
}
catch (ExecutionException ex) {
// Notify the user processing raised an exception
}
}
};
Addendum:
This can be extended to multiple tasks, it just requires changing how you approach setting the progress bar. Here's what comes to mind:
Have an array of completion counter, one per task.
int[] completions = new int[numTasks];
Arrays.fill(completions,0);
Start the SwingWorkers, each passed an index number. The process or done methods then call something like this to update the overall progress bar.
void update(int index, int percComplete) {
completions[index] = percComplete;
int total = 0;
for(int comp: completions)
total += comp/numTasks;
overallPB.setValue(total);
}
Optionally, display a JProgressBar per task.
Addendum 2:
If the tasks vary in completion time (eg, cache hit vs cache miss), you may want to investigate ProgressMonitor. It's a progress dialog that only appears if the task takes more than some (configurable, default 500ms) amount of time.

No need to call the frame inside invokeAndWait but you should update progress bar state like this.
try {
SwingUtilities.invokeAndWait( new Runnable() {
public void run() {
//update state of the progress bar here
}
});
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }

Related

SwingWorker done method throws cancellationexception with get()

I faced an issue of creating stop/start jbuttons for my gui, and after a LOT of googling, i realized i needed multi-threading. Upon further reading i discovered the swingworker class, and i managed to get my GUI to respond to the STOP button.
now my problem is this
The doinbackground() method executes a piece of code that captures packets in an infinite while loop with the condition (!isCancelled), and once it is cancelled (The STOP button executes worker.cancel()) it returns an ArrayList of packets which theoretically, i should be able to obtain inside the done() method using get(). right? But when i try to do this i get a CancellationException and this is driving me nuts right now.
any help would be highly appreaciated!
Thank you
edit: obj is an ArrayList declared outside of the class to store the return values.
here is my code executed by the START jbutton
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
final ArrayList packet_list = new ArrayList();
obj.clear();
try {
worker = new SwingWorker<ArrayList,Integer>(){//initialze swingworker class
#Override
protected void done(){
try {
obj = get();
}
catch (InterruptedException ex) {
Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExecutionException ex) {
Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
}
}
//opens up stuff required to capture the packets
NetworkInterface [] devices = JpcapCaptor.getDeviceList();
int index = (jComboBox5.getSelectedIndex()-1);
JpcapCaptor captor =JpcapCaptor.openDevice(devices[4], 65535, false, 20);
#Override
protected ArrayList doInBackground(){
while(!isCancelled()){
try {
Packet packets = captor.getPacket(); //captures packets
if (packets != null) //filters out null packets
{
//System.out.println(packets);
packet_list.add(packets); //adds each packet to ArrayList
}
Thread.sleep(100);
} catch (InterruptedException ex) {
return packet_list;
}
}
return packet_list;
}
};
worker.execute();
} catch (IOException ex) {
Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
}
}
The stop button simply executes
worker.cancel(); no errors there. and this is the swingworker declaration
private SwingWorker<ArrayList,Integer> worker;
cancel doesn't just set the isCancelled flag for you to read at your leisure. That would be pretty much useless. It prevents the task from starting if it hasn't already and may actively interrupt the thread if it's already running. As such, getting a CancellationException is the natural consequence of cancelling a running task.
To further the point, the Javadoc on isCancelled states:
Returns true if this task was cancelled before it completed normally.
Hence if this returns true, then your task cannot complete normally. You cannot cancel a task and expect it to continue as per normal.
SwingWorker docs say "An abstract class to perform lengthy GUI-interaction tasks in a background thread". However, the definition of "lengthly" is different for GUI and for an application lifetime. A 100ms task is very long for a GUI, and is best done by a SwingWorker. A 10 minute task is too long for a SwingWorker simply because it has a limited thread pool, that you may exhaust. Judging by your problem description, you have exactly that - a potentially very long running task. As such, you should rather make a proper background thread than use a SwingWorker.
In that thread, you would have either an AtomicBoolean or simply a volatile boolean flag that you can manually set from the EDT. The thread can then post an event to the EDT with the result.
Code:
class PacketCaptureWorker implements Runnable {
private volatile boolean cancelled = false;
public void cancel() {
cancelled = true;
}
public void run() {
while (!cancelled) {
//do work
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Use the result of your computation on the EDT
}
});
}
}
new Thread(new PacketCaptureWorker()).start();
I tried using a volatile boolean instead of using worker.cancel() for the swingworker thread while loop and it works beautifully. (atleast on surface) I managed to create a normal background thread as well and that too worked liked a charm :D Many thanks you saved me a major headache! Wondering what the best method is out of the two.
A follow up, i had to make the volatile boolean available for the whole class, because i had to create 2 seperate instances for the thread class, one to use the START and the other to use the STOP. Apparently two different instances does not address the same instance of the variable. is this bad practice?

Is there a way to know if a JPanel is finished loading it's content?

I'm writing an application that adds cards (JPanels) to a CardLayout during runtime. The problem is that some components on the card loads faster than others, making it appear glitchy and not properly rendered before it's displayed.
I want it to be ready when shown for the first time.
I have solved the issue temporary by a loading screen, which makes the thread sleep for 1500 ms. Is there a more exakt way to know if everything on the panel is loaded?
private void showLoadingScreen() {
final Component glassPane = getGlassPane();
setGlassPane(loadingPanel);
loadingPanel.setVisible(true);
Thread thread = new Thread() {
public void run() {
try {;
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
setGlassPane(glassPane);
}
};
thread.start();
}
Do all your file loading and data manipulation in a background thread that is created using a SwingWorker. Then before executing the SwingWorker, add a PropertyChangeListener. When the PropertyChangeEvents newValue is SwingWorker.StateValue.DONE, then you know all background work is done and you can display your GUI.
Please have a look at the Concurrency in Swing tutorial, and for an example, please have a look at this answer to a similar question.

libgdx - doing something in other thread not working

My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.

How do I read a SwingWorker's result *without* busy wait?

I'm writing an application that executes its file menu actions using SwingWorker. Every called method returns a boolean value that tells, whether the operation was successfully executed or not.
At the moment I'm using busy waiting for the result, like this:
public boolean executeOperation() {
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
return false;
}
// ..
return true;
}
};
worker.execute();
// busy wait
while (!worker.isDone())
;
try {
return worker.get().booleanValue();
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
Is there a less polling-intense way of solving this?
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
EDIT: If possible, I would like to avoid that the method (or the worker) to communicate their result asynchronously. I'm implementing several short methods (file -> open, new, close, save, save as, exit) that rely on each other (i. e. when the trying to exit, exit calls close, close might call save, save might call save as). Solving this asynchronously seems to make the code much more complicated.
The point of the SwingWorker is precisely to launch some task in the background and don't block the EDT. Either you want something synchronous, and the EDT will be blocked whatever you try, or you want something asynchronous, and the background task should update its status using the publish method of the SwingWorker.
You could display a blocking modal dialog with a progress bar while the task is running, and hide it once the task completes.
The alternative is to block for some time, hoping the task will be quick to finish, and then backup to an asynchronous way of doing. This can be done using the get method taking a timeout as argument.
You could use an asynchronous paradigm. Look at Observer / Observable and use the job to transfer the result back to the object which is currently doing the polling.
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
They don't with the current code either. Your busy wait blocks the EDT as much as calling worker.get() does - there is only one event dispatch thread, and the dialogs in the SwingWorker are just as blocked if that thread is spinning in a loop or awaiting a lock. The problem here is that if a method runs on the EDT, it simply can't return a value from an asynchronous operation (without hogging the EDT) to its caller.
The correct way to react to completed async processing is overriding the done() method in SwingWorker.
Also check out http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html for more info.
One way as mentioned by several folks above is to override the SwingWorker's done method. However if for some reason you want the post SwingWorker code outside of the SwingWorker and in the calling code, you can take advantage of SwingWorker's property change support. Simply add a PropertyChangeListener to the SwingWorker and listen for the state property which has a property name of "state". You can then extract the SwingWorker's state with its getState() method. When it is done it will return the DONE value of the SwingWorker.StateValue enum. For example (from an answer I've given in another thread here on SO):
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
#Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
I ran into a similar problem when I wanted a function to return a value that would be calculated in a swing worker. I didn't want to simply get that thread to block the EDT. I also didn't want it to block. So I used a semaphore like this:
public boolean executeOperation() {
final Semaphore semaphore = new Semaphore(1);
semaphore.acquire(1); // surround by try catch...
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
semaphore.release();
return false;
}
// ..
semaphore.release();
return true;
}
};
worker.execute();
try {
semaphore.tryAcquire(1, 600, TimeUnit.SECONDS); // awakes when released or when 10 minutes are up.
return worker.get().booleanValue(); // blocks here if the task doesn't finish in 10 minutes.
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
I guess this is not ideal for all situations. But I thought it was an alternative approach that was very useful for me.

Get and send messages with Java Threads

I want to make a thread, which runs, computes something with the data i give it, and returns a few values, or an object. The thread is a part of a Swing GUI.
My question: How can I make a method that runs when I make the thread, and returns an object (or whatever I want it to return)?
My code:
private void nextTurn () {
// do something
if (turn == white) {
try {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove (board);
// thread should work, next code should be excecuted immediately
}
catch (Exception e) {}
}
// end of Main class
}
This is the first time I am working with Threads, and I know you should avoid them if possible, but I need it this time for my GUI.
The info on the Oracle site on Threads did not help me out. I am able to make a program with multiple Threads that runs indefinately, but I can't make it work with functions.
Since this is with a Swing GUI, consider using a SwingWorker object which creates a background thread (all the code run in the doInBackground method), and then can return a final result and/or interim results. Information on how to use this is well documented in the tutorials here:
Concurrency in Swing
SwingWorkers have property change support and thus will allow listeners to observe its state (as a SwingWorker.StateValue) via a PropertyChangeListener. This is one way your program can determine that the thread has completed its processing, get the returned result and go from there.
On an unrelated note, this isn't in your production code is it?:
catch (Exception e) {}
If so, you will likely want to fix this as ignored exceptions can bite you in the tail big time.
e.g.,
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
#Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
I suggest you use an ExecutorService. It allows you to create a thread pool, you can pass tasks to it and get the results later.
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

Categories