Hi,
I'm working on sketch with a Background thread, which updates a progress bar in the main thread. But I'm fairy new to all this java stuff.
The goal is to perform heavy calculations, based on where the user clicked, but without the sketch locking up. Also I want to display a small progress bar to indicate how far the calculation is proceeding.
I tried to use
SwingWorker because from the description, this seemed to do exactly what I needed, but I couldn't get it to work with processing, so I gave up.
In the end I managed to create the following sketch with FutureTask, but I have still some questions:
- 1. to update the progress bar I call getProgress() from the main thread. But since the background thread is also manipulating completedPercentage in setProgress(int, int) I'm not sure if this is (thread)safe. Is there a better or safer way to get progress feedback from a background thread like this?
- 2. This code is not yet doing any heavy calculation. It's mainly sleeping and reversing a string. When it would be doing much more intensive calculations (e.g. calculate prime numbers based on the mouse position) do I then need to keep a Thread.currentThread().sleep() statement in the code, to allow the main thread to do its drawing? And how long should it sleep for then?
The code:
background_process_sketch.pde
Code:
import java.util.concurrent.*;
boolean backgroundTaskRunning = false;
int progressBarValue = 100; // from 0 to 100
ExecutorService executor;
BackgroundTask task;
void setup() {
size (300, 300);
smooth();
noStroke();
}
void draw() {
// try every loop
if (backgroundTaskRunning) {
if (!task.isDone()) {
//println("Task not yet completed.");
} else {
println("Here is the result..." + task.getResult());
executor.shutdown();
backgroundTaskRunning = false;
}
}
background(150);
displayProgressBar();
fill (255);
ellipse (mouseX, mouseY, 20, 20);
}
void mousePressed() {
if (!backgroundTaskRunning) {
println("Start a background process");
executor = Executors.newSingleThreadExecutor();
task = new BackgroundTask("foobar");
executor.execute(task.future);
backgroundTaskRunning = true;
}
}
void displayProgressBar() {
if (backgroundTaskRunning) {
int progressX = 195;
int progressY = 290;
int progressHeight = 8;
fill (100);
progressBarValue = task.getProgress();
rect(progressX, progressY, progressBarValue, progressHeight);
}
}
void displayAnswer(int answer) {
println("We have an answer: ");
print(answer);
}
BackgroundTask.java
Code:
//BackgroundTask.java
import java.util.concurrent.*;
public class BackgroundTask
{
SlowStringReverser reverser = new SlowStringReverser();
FutureTask<String> future;
int completedPercentage;
BackgroundTask(String argument) {
completedPercentage = 0;
try {
createTask(argument);
} catch (InterruptedException ie) {
System.out.println(ie);
}
}
void createTask(final String target) throws InterruptedException {
future = new FutureTask<String> (
new Callable<String>()
{
public String call()
{
return reverser.reverseString(target);
}
});
}
boolean isDone() {
return future.isDone();
}
String getResult() {
try {
try {
return future.get();
} catch (ExecutionException ex) {}
} catch (InterruptedException ie) {
System.out.println(ie);
}
return "";
}
int getProgress() {
return completedPercentage;
}
void setProgress(int currentValue, int maxValue) {
completedPercentage = (currentValue * 100) / maxValue;
}
//-----------------------------
class SlowStringReverser {
StringBuffer orgString;
StringBuffer reversedString;
SlowStringReverser(String orgStr) {
orgString = new StringBuffer(orgStr);
}
SlowStringReverser() {
}
public String reverseString(String str) {
orgString = new StringBuffer(str);
reversedString = new StringBuffer();
for (int i = (orgString.length() - 1); i >= 0; i--) {
reversedString.append(orgString.charAt(i));
//setProgressBarValue((orgString.length() - i), orgString.length());
setProgress((orgString.length() - i), orgString.length());
System.out.println("Reversing one character per second." + reversedString);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException ie) {}
}
return reversedString.toString();
}
}
}
Thanks!
Dirk