JavaFX.Scene.Robot crashes / UI freezes - multithreading

I am trying to write a simple JavaFX app which acts as an auto clicker for a game I play. I choose two Points that the mouse should click alternately. Everything works fine until the Robot needs to do his work.
When I put it like this:
robot.mouseMove(join);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
robot.mouseMove(accept);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
my App crashes. I've read things up online and it seems like you should not sleep in the JavaFX application thread. My new approach was to create a new thread that takes care of the clicking from the application thread like this:
clicker = new Clicker(join, accept);
Thread clickerThread = new Thread(clicker);
clickerThread.start();
And here how it looks in Clicker:
public void run() {
while (running){
try {
robot.mouseMove(join);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
robot.mouseMove(accept);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Clicker sleep interrupted!");
}
}
}
However with the new approach I suddenly get this error:
Exception in thread "Thread-3" java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = Thread-3
Does anyone know how I could fix this problem?

When you want to execute a periodic foreground task on the JavaFX Application Thread you should first consider using an animation. Here's an example of using a Timeline:
Point2D join = ...;
Point2D accept = ...;
Robot robot = ...;
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, e -> robot.mouseMove(join)),
new KeyFrame(Duration.seconds(2), e -> robot.mouseClick(MouseButton.PRIMARY)),
new KeyFrame(Duration.seconds(4), e -> robot.mouseMove(accept)),
new KeyFrame(Duration.seconds(6), e -> robot.mouseClick(MouseButton.PRIMARY)),
new KeyFrame(Duration.seconds(8))
);
timeline.play();
The above will execute each KeyFrame's on-finished handler two seconds after the previous one (the first one immediately after the animation is started). The last KeyFrame matches your final call to sleep though it may not be necessary. All this will occur on the JavaFX Application Thread.
You can configure an animation to replay a certain number of times, or even forever, by setting its cycleCount property. For example:
timeline.setCycleCount(5); // play 5 times then stop
// or
timeline.setCycleCount(Animation.INDEFINITE); // play forever

You need to execute the mouseMove on the UI thread try wrapping the calls with Platform.runlater(() -> robot.mouseMove(MouseButton.PRIMARY));
public void run() {
while (running){
try {
Platform.runlater(() -> robot.mouseMove(join));
Thread.sleep(2000);
Platform.runlater(() -> robot. mouseClick(MouseButton.PRIMARY));
Thread.sleep(2000);
Platform.runlater(() -> robot.mouseMove(accept));
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Clicker sleep interrupted!");
}
}
}
Platform.runLater() will schedule an action on the main thread and return immediately. It may take some time before the action is actually executed, in small applications this delay is usually not perceptible. If the delay were long it may happen that you schedule your action, sleep and schedule again before the first action was executed. If you want your clickerThread to wait for the action to execute before continuing then you will need some form of synchronisation, see below for an example of a method that wraps Platform.runlater() with a lock.
public void waitUntilExecutedOnMainThread(Runnable runnable){
Semaphore semaphore = new Semaphore(0);
Platform.runLater(() -> {
try {
runnable.run();
} finally {
semaphore.release();
}
});
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
waitUntilExecutedOnMainThread(() -> robot. mouseClick(MouseButton.PRIMARY))

Related

Do I need to use thread and a task in JavaFX to run something in background when a thread will do the job?

I'm using a thread to periodically run a three second background animation.
I adapted the code in question from a Thread Demo example written in Swing and used
it to replace a not quite working earlier version that used both a thread and a task.
My program stops/suspends the thread when either playing a video or running an animation
and starts a new thread when ending the video or animation. This seems to work without
any downside which is why I'm puzzled why my earlier JavaFX searches hadn't turned up
a similar solution to the one I'm using. It seems a rather direct approach for running
short, simple background animations.
Where am I going wrong with this? What am I missing? How would I rewrite this code
using both a Thread and a Task or do I need to?
I should add - the while and run statements are virtually unchanged from the original
and the only significant addition to the Swing code was to add thread.setDaemon( true )
to startThread().
A podcast listener.
// background thread
class BackGround extends Thread {
#Override
public void run() {
while ( suspend.getValue() == false ) {
try {
int r = shared.randInt( 5, 10 );
Thread.sleep( r * 1000 );
} catch ( InterruptedException e ) {
// do nothing
}
if ( suspend.getValue() == false ) {
Platform.runLater( () -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt( 0, g );
gradientColor.set( shared.cssGradients[g] );
Boolean bif = shared.updatePanes( shared.cssGradients[g],
leftPane, rightPane );
});
}
}
}
} // class background
// start thread
public synchronized void startThread() {
thread = new BackGround(); // Thread thread ...defined elsewhere
thread.setDaemon( true );
thread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
The reason the Task class is useful for JavaFX is that it provides a number of callbacks like succeeded(), failed() or cancelled() and methods like updateProgress() and updateMessage() that will run in the JavaFX Application thread and therefore let you update the UI without Platform.runLater( () -> { ... }); This makes the Task class a perfect choice for doing background tasks like downloading data or long running computations.
However, since your thread simply runs continuously without ever really finishing its work, it doesn't seem that you would need any of the additional functionality a Task would provide you with over a simple Thread.
Still, if you really wanted to convert your code to use a Task, it would look just like this:
class BackGround extends Task<Void> {
#Override
protected Void call() throws Exception {
while (suspend.getValue() == false) {
try {
int r = shared.randInt(5, 10);
Thread.sleep(r * 1000);
} catch (InterruptedException e) {
// do nothing
}
if (suspend.getValue() == false) {
Platform.runLater(() -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g],
leftPane, rightPane);
});
}
}
return null;
}
}
// start thread
public synchronized void startThread() {
Task<Void> bg = new BackGround();
Thread taskThread = new Thread(bg);
taskThread.setDaemon(true);
taskThread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
As you see, it really doesn't make a difference for you, as you don't need anything that a Thread couldn't give you. If however you wanted to have closer communication with the UI thread, e.g. showing a progress bar or showing status updates, then a Task would give you the tools to do that.
I guess its also worth mentioning that the use of a Timeline would be quite elegant for triggering your animations. It would look somewhat like this:
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g], leftPane, rightPane);
}
}
));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
The code inside the handle() method is run every second in the JavaFX Application thread. Unfortunately this only lets you set a fixed time between executions, while you seem to want to wait a random amount of time each time.
TL;DR: Using a Thread is ok, because you don't need the additional functionalities of a Task in your use case.

What is the purpose of await() in CountDownLatch?

I have the following program, where I am using java.util.concurrent.CountDownLatch and without using await() method it's working fine.
I am new to concurrency and want to know the purpose of await(). In CyclicBarrier I can understand why await() is needed, but why in CountDownLatch?
Class CountDownLatchSimple:
public static void main(String args[]) {
CountDownLatch latch = new CountDownLatch(3);
Thread one = new Thread(new Runner(latch),"one");
Thread two = new Thread(new Runner(latch), "two");
Thread three = new Thread(new Runner(latch), "three");
// Starting all the threads
one.start(); two.start(); three.start();
}
Class Runner implements Runnable:
CountDownLatch latch;
public Runner(CountDownLatch latch) {
this.latch = latch;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName()+" is Waiting.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
System.out.println(Thread.currentThread().getName()+" is Completed.");
}
OUTPUT
two is Waiting.
three is Waiting.
one is Waiting.
one is Completed.
two is Completed.
three is Completed.
CountDownLatch is the synchronization primitive which is used to wait for all threads completing some action.
Each of the thread is supposed to mark the work done by calling countDown() method. The one who waits for the action to be completed should call await() method. This will wait indefinitely until all threads mark the work as processed, by calling the countDown(). The main thread can then continue by processing the worker's results for example.
So in your example it would make sense to call await() at the end of main() method:
latch.await();
Note: there are many other use cases of course, they don't need to be threads but whatever that runs usually asynchronously, the same latch can be decremented several times by the same task etc. The above describes just one common use case for CountDownLatch.

I can't show a 'Wait' screen when I need to wait for a thread to be finished

I need to show some kind of animation(progress indicator) when a task takes some time to complete.
This is the code for my wait screen:
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.StringItem;
public class scrWaitForm extends Form {
public static scrWaitForm create() {
return new scrWaitForm();
}
private final Gauge gagProgressBar;
private final StringItem strMensaje;
protected scrWaitForm() {
super("Procesando");
this.gagProgressBar = new Gauge("", false, Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
this.gagProgressBar.setLayout(Item.LAYOUT_CENTER| Item.LAYOUT_VCENTER);
this.append(gagProgressBar);
this.strMensaje=new StringItem("Loading...", null);
this.append(strMensaje);
}
}
And this is how I show it :
public void showWaitForm() {
scrWaitForm frmWaitForm = scrWaitForm.create();
mDisplay.setCurrent(frmWaitForm);
}
As you can see, it is very simple. I only use a Gauge. The problem is that the wait screen won't be displayed if I need to wait for a thread to be finished so that I can use some operation results(from the thread) in other operations. However, if I only call the wait screen without waiting for the thread to complete it works as expected.
This is what I initially did:
thrLoadCustomers load = new thrLoadCustomers(rmsCustomers, url);
Thread t = new Thread(load);
showWaitForm()
t.start();
try {
t.join();
} catch (InterruptedException ex) {
}
But then with the help of Mister Smith I ended up using something like this :
WSResult result = new WSResult();
//Start thread here
new Thread(new LoadCustomersTask(result)).start();
//This is old school thread sync.
synchronized(result){
showWaitForm();
while(!result.isCompleted()){
result.wait();
}
}
Am I doing something wrong?? How do you normally show an animation or another screen so that user sees that something is taking place and don't intend to invoke the same action over and over again.
Thanks in advance.

JavaFX working with threads and GUI

I have a problem while working with JavaFX and Threads. Basically I have two options: working with Tasks or Platform.runLater. As I understand Platform.runLater should be used for simple/short tasks, and Task for the longer ones. However, I cannot use any of them.
When I call Thread, it has to pop up a captcha dialog in a middle of task. While using Task, it ignores my request to show new dialog... It does not let me to create a new stage.
On the other hand, when I use Platform.runLater, it lets me show a dialog, however, the program's main window freezes until the pop up dialog is showed.
I need any kind of solution for this. If anyone knows how to deal with this or had some similar experience and found a solution I am looking forward to hearing from you!
As puce says, you have to use Task or Service for the things that you need to do in background. And Platform.runLater to do things in the JavaFX Application thread from the background thread.
You have to synchronize them, and one of the ways to do that is using the class CountDownLatch.
Here is an example:
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
return null;
}
};
}
};
service.start();
Use a Worker (Task, Service) from the JavaFX Application thread if you want to do something in the background.
http://docs.oracle.com/javafx/2/api/javafx/concurrent/package-summary.html
Use Platform.runLater from a background thread if you want to do something on the JavaFX Application thread.
http://docs.oracle.com/javafx/2/api/javafx/application/Platform.html#runLater%28java.lang.Runnable%29
It's too late to answer but for those who have the error, here is the solution XD
You can use one Thread.
Use the lambda expression for the runnable in the thread and the runlater.
Thread t = new Thread(() -> {
//Here write all actions that you want execute on background
Platform.runLater(() -> {
//Here the actions that use the gui where is finished the actions on background.
});
});
t.start();
You can user directly this code
Don't forget you can't send non-final variable in thread .
you can send final variable in thread
//final String me="ddddd";
new Thread(new Runnable() {
#Override
public void run() {
// me = me + "eee";
//...Your code....
}
}).start();
Use in
your code
try/catch

If the task thread is itself blocked, then how can it cancel out of there? (Java7, JavaFX2)

I have two threads; TaskThread, BackgroundThread.
TaskThread
blocks on a 'receive data' semaphore.
synchronized (receiveSemaphore) {
while (!dataIsReady) {
try {
receiveSemaphore.wait();
} catch (InterruptedException e) {
}
}
...
}
BackgroundThread
notifies all threads waiting on the 'receive data' semaphore
receiveSemaphore.notifyAll();
Unfortunately as in life, things can sometimes go wrong and BackgroundThread never executes the statement notifying the waiting threads.
How is a user to cancel when he gets tired of waiting?
I have a Cancel button on my JavaFX2 UI - but then what?
In JavaFX2, the only examples shown have a thread running in a loop and checking the isCancelled() flag.
http://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html
Again, if the task thread is itself blocked, then how can it cancel out of there?
When the cancel button is pressed, invoke cancel on the task. This will interrupt the task if it is waiting and execution will flow to the InterruptedException block, where you can check to see if the Interrupt cause was a cancel call and, if so, return from your Task's call method, effectively cancelling and ending the task.
Your sample is actually pretty similar to the sample titled "A Simple Loop With Progress Notification And Blocking Calls" in the Task documentation, but your sample is even simpler because there is no loop involved, so you only need to worry about the blocking call.
Behind the scenes, when you invoke cancel on the task, an interrupt is sent to the Task thread to generate the InterruptedException on the thread.
Here is some sample code.
// Task cancel button logic.
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
task.cancel();
}
})
....
// Task call method logic
synchronized (receiveSemaphore) {
while (!dataIsReady) {
try {
receiveSemaphore.wait();
} catch (InterruptedException e) {
if (isCancelled()) {
return;
}
}
}
...
}

Resources