Timers and javafx - multithreading

I am trying to write a code that will make things appear on the screen at predetermined but irregular intervals using javafx. I tried to use a timer (java.util, not javax.swing) but it turns out you can't change anything in the application if you are working from a separate thread.(Like a Timer) Can anyone tell me how I could get a Timer to interact with the application if they are both separate threads?

You don't need java.util.Timer or java.util.concurrent.ScheduledExecutorService to schedule future actions on the JavaFX application thread. You can use JavaFX Timeline as a timer:
new Timeline(new KeyFrame(
Duration.millis(2500),
ae -> doSomething()))
.play();
Alternatively, you can use a convenience method from ReactFX:
FxTimer.runLater(
Duration.ofMillis(2500),
() -> doSomething());
Note that you don't need to wrap the action in Platform.runLater, because it is already executed on the JavaFX application thread.

berry120 answer works with java.util.Timer too so you can do
Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}, delay, period);
I used this and it works perfectly

If you touch any JavaFX component you must do so from the Platform thread (which is essentially the event dispatch thread for JavaFX.) You do this easily by calling Platform.runLater(). So, for instance, it's perfectly safe to do this:
new Thread() {
public void run() {
//Do some stuff in another thread
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}.start();

Related

how to do something when liferay module stop

i am making cron job like loop to do something using new thread.
when module stop, this thread keeps running, so when i deployed updated module, i'm afraid it will make duplicate thread doing similar task
#Component(immediate = true, service = ExportImportLifecycleListener.class)
public class StaticUtils extends Utils{
private StaticUtils() {}
private static class SingletonHelper{
private static final StaticUtils INSTANCE = new StaticUtils();
}
public static StaticUtils getInstance() {
return SingletonHelper.INSTANCE;
}
}
public class Utils extends BaseExportImportLifecycleListener{
public Utils() {
startTask();
}
protected Boolean CRON_START = true;
private void startTask() {
new Thread(new Runnable() {
public void run() {
while (CRON_START) {
System.out.println("test naon bae lah ");
}
}
}).start();
}
#Deactivate
protected void deactivate() {
CRON_START = false;
System.out.println(
"cron stop lah woooooooooooooooooy");
}
}
i'm using liferay 7
I have populated task that i store from db, so this thread is checking is there a task that it must do, then if it exist execute it.
I'm quite new in osgi and liferay. i've try to use scheduler and failed and also exportimportlifecycle listener but dont really get it yet
think again: Do you really need something to run all the time in the background, or do you just need some asynchronous processing in the background, when triggered? It might be better to start a background task as a one-off, that automatically terminates
Liferay provides an internal MessageBus, that you can utilize to listen to events and implement background processing, without the need for a custom thread
You're in the OSGi world, so you can utilize #Activate, #Modified, #Deactivate (from org.osgi.service.component.annotations) or use a org.osgi.framework.BundleActivator.
But, in general, it's preferable if you don't start your own thread

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

JavaFX 2.1: Toolkit not initialized

My application is Swing-based. I would like to introduce JavaFX and configure it to render a Scene on a secondary display.
I could use a JFrame to hold a JFXPanel which could hold a JFXPanel but I would like to achieve this with JavaFX API.
Subclassing com.sun.glass.ui.Application and using Application.launch(this) is not an option because the invoking thread would be blocked.
When instantiating a Stage from Swing EDT, the error I get is:
java.lang.IllegalStateException: Toolkit not initialized
Any pointers?
EDIT: Conclusions
Problem: Non-trivial Swing GUI application needs to run JavaFX components. Application's startup process initializes the GUI after starting up a dependent service layer.
Solutions
Subclass JavaFX Application class and run it in a separate thread e.g.:
public class JavaFXInitializer extends Application {
#Override
public void start(Stage stage) throws Exception {
// JavaFX should be initialized
someGlobalVar.setInitialized(true);
}
}
Sidenote: Because Application.launch() method takes a Class<? extends Application> as an argument, one has to use a global variable to signal JavaFX environment has been initialized.
Alternative approach: instantiate JFXPanel in Swing Event Dispatcher Thread:
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
}
});
latch.await();
By using this approach the calling thread will wait until JavaFX environment is set up.
Pick any solution you see fit. I went with the second one because it doesn't need a global variable to signal the initialization of JavaFX environment and also doesn't waste a thread.
Found a solution. If I just create a JFXPanel from Swing EDT before invoking JavaFX Platform.runLater it works.
I don't know how reliable this solution is, I might choose JFXPanel and JFrame if turns out to be unstable.
public class BootJavaFX {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JFXPanel(); // this will prepare JavaFX toolkit and environment
Platform.runLater(new Runnable() {
#Override
public void run() {
StageBuilder.create()
.scene(SceneBuilder.create()
.width(320)
.height(240)
.root(LabelBuilder.create()
.font(Font.font("Arial", 54))
.text("JavaFX")
.build())
.build())
.onCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent windowEvent) {
System.exit(0);
}
})
.build()
.show();
}
});
}
});
}
}
Since JavaFX 9, you can run JavaFX application without extending Application class, by calling Platform.startup():
Platform.startup(() ->
{
// This block will be executed on JavaFX Thread
});
This method starts the JavaFX runtime.
The only way to work with JavaFX is to subclass Application or use JFXPanel, exactly because they prepare env and toolkit.
Blocking thread can be solved by using new Thread(...).
Although I suggest to use JFXPanel if you are using JavaFX in the same VM as Swing/AWT, you can find more details here: Is it OK to use AWT with JavaFx?
I checked the source code and this is to initialize it
com.sun.javafx.application.PlatformImpl.startup(()->{});
and to exit it
com.sun.javafx.application.PlatformImpl.exit();
I used following when creating unittests for testing javaFX tableview updates
public class testingTableView {
#BeforeClass
public static void initToolkit() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
});
if (!latch.await(5L, TimeUnit.SECONDS))
throw new ExceptionInInitializerError();
}
#Test
public void updateTableView() throws Exception {
TableView<yourclassDefiningEntries> yourTable = new TableView<>();
.... do your testing stuff
}
}
even though this post is not test related, then it helped me to get my unittest to work
without the BeforeClass initToolkit, then the instantiation of TableView in the unittest would yield a message of missing toolkit
There's also way to initialize toolkit explicitly, by calling:
com.sun.javafx.application.PlatformImpl#startup(Runnable)
Little bit hacky, due to using *Impl, but is useful, if you don't want to use Application or JXFPanel for some reason.
re-posting myself from this post
private static Thread thread;
public static void main(String[] args) {
Main main = new Main();
startup(main);
thread = new Thread(main);
thread.start();
}
public static void startup(Runnable r) {
com.sun.javafx.application.PlatformImpl.startup(r);
}
#Override
public void run() {
SoundPlayer.play("BelievexBelieve.mp3");
}
This is my solution. The class is named Main and implements Runnable. Method startup(Runnable r) is the key.
Using Jack Lin’s answer, I found that it fired off the run() twice. With a few modifications that also made the answer more concise, I offer the following;
import com.sun.javafx.application.PlatformImpl;
public class MyFxTest implements Runnable {
public static void main(String[] args) {
MyFxTest main = new MyFxTest();
PlatformImpl.startup((Runnable) main);
}
#Override
public void run() {
// do your testing;
System.out.println("Here 'tis");
System.exit(0); // Optional
}
}

Problem in calling thread inside Eclipse view run method, after using asyncExec. Invalid Thread Exception

I am having an eclipse View. Inside the view I added a Table. Now I am calling a thread from run method of the view using asyncExec.
My View class is like -
public class SampleViewAction implements IWorkbenchWindowActionDelegate{
Thread t;
int Count;
#Override
public void run(IAction arg0) {
}
}
Now I added a thread like this -
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
new UDPReadThread();
}
});
Where UDPReadThread is a class extends a thread where in UDPReadThread 's constructor I started the thread.
But I am getting invalid Thread exception.
How to resolve the issue.
Similar to AWT and the EventDispatchThread, SWT must process everything in the UI thread.
Your SampleViewAction is run on the UI thread already, in response to a menu or tool item selection.
It looks like your problem comes from then using an asyncExec(*) which will post the runnable to be run on the UI thread (which delays it), and starting a new thread from that asyncExec Runnable. You may as well simply start your thread, and get rid of that asyncExec.
Your UDPReadThread is not the UI thread. If you need to update UI widgets from UDPReadThread, that's the code that needs the asyncExec:
display.asyncExec(
new Runnable() {
public void run(){
label.setText(text);
}
});
Just as an aside, you should not subclass Thread unless you really are extending threads capabilities. The normal pattern when you just want to start another thread:
UDPReadRunnable udpRunnable = ....;
Thread thread = new Thread(udpRunnable);
thread.start();
You can get more information on the display thread from http://www.eclipse.org/swt/faq.php#uithread

Thread Invalid Access Error in SWT

Could you let me know the reason for this error in SWT
"org.eclipse.swt.SWTException" Invalid Thread access ?
And How to fix such errors.
It happens when you try to act upon an interface item from a thread that's not the UI thread.
To run a code on the UI thread you have to use a Runnable and ask the display thread to run it. This way:
Display.getDefault().syncExec( new Runnable() {
#Override
public void run() {
// Do your job here
}
} );
As stated by the syncExec method javadoc,
the thread which calls this method is suspended until the runnable completes.
Also, you might check the asyncExec method.
In SWT you can access GUI resources only from the display thread. For example when setting the text in a org.eclipse.swt.widgets.Text control you must already be in the display thread or call
final Text text = ...;
Display.getCurrent().syncExec(new Runnable() {
#Override
public void run() {
text.setText("test");
}
});

Resources