JavaFX multithreading operation changing GUI elements
-
I want to make it so that when the user launches the app, it will display the GUI but at the same time it will launch other threads (multithreading) that will do some calculations and when those are finished they will update some GUI elements (which are always created before the thread with calculations is launched, that is not a problem of getting null), also when a button is pressed same as before using multithreading it will do some calculation and update the GUI after each thread is done. Now the problem I have is that if you are using Thread(new Runnable)/start(); to launch multiple threads (even one) you get into the error
Not on FX application thread
. As possible solutions I read about JavaFX Task and Service but those were freezing the GUI thread until they were done. This is what I tried ("Functions.functionX" is the placeholder, the real function takes between 0-20 seconds to finish):button.setOnAction(event -> { Service doSomething = new Service() { @Override protected Task createTask() { Functions.functionX("parameter"); return null; } }; doSomething.start(); });
Now the problem with this is like I said, when the button is pressed, the GUI is unusable until the function finishes. Using straight Task had the same effect unfortunately. What do I need to change/add to make it so that I can launch multiple threads at a time, and inside them to change elements from GUI (right now I only want to update some Labels with .setText() inside those threads, each thread updates one Label)?
-
I want to make it so that when the user launches the app, it will display the GUI but at the same time it will launch other threads (multithreading) that will do some calculations and when those are finished they will update some GUI elements (which are always created before the thread with calculations is launched, that is not a problem of getting null), also when a button is pressed same as before using multithreading it will do some calculation and update the GUI after each thread is done. Now the problem I have is that if you are using Thread(new Runnable)/start(); to launch multiple threads (even one) you get into the error
Not on FX application thread
. As possible solutions I read about JavaFX Task and Service but those were freezing the GUI thread until they were done. This is what I tried ("Functions.functionX" is the placeholder, the real function takes between 0-20 seconds to finish):button.setOnAction(event -> { Service doSomething = new Service() { @Override protected Task createTask() { Functions.functionX("parameter"); return null; } }; doSomething.start(); });
Now the problem with this is like I said, when the button is pressed, the GUI is unusable until the function finishes. Using straight Task had the same effect unfortunately. What do I need to change/add to make it so that I can launch multiple threads at a time, and inside them to change elements from GUI (right now I only want to update some Labels with .setText() inside those threads, each thread updates one Label)?
Where do you get the "Not on FX application thread" error? When trying to launch all those threads or when you try to update the GUI from within one of those threads? If it's the former, I can't help. If it's the latter, you simply need to run your update code on the UI thread. I don't use JavaFX but in my Java / Android, this works fine.
// called from a fragment
Thread worker = new Thread (new Runnable ()
{
@Override public void run ()
{
// stuff to do not on the UI thread
// ...// stuff is done, time to tell the UI activity.runOnUiThread (new Runnable () { @Override public void run () { // code that touches the UI } }); }
});
worker.start ();Be wary of strong drink. It can make you shoot at tax collectors - and miss. Lazarus Long, "Time Enough For Love" by Robert A. Heinlein
-
Where do you get the "Not on FX application thread" error? When trying to launch all those threads or when you try to update the GUI from within one of those threads? If it's the former, I can't help. If it's the latter, you simply need to run your update code on the UI thread. I don't use JavaFX but in my Java / Android, this works fine.
// called from a fragment
Thread worker = new Thread (new Runnable ()
{
@Override public void run ()
{
// stuff to do not on the UI thread
// ...// stuff is done, time to tell the UI activity.runOnUiThread (new Runnable () { @Override public void run () { // code that touches the UI } }); }
});
worker.start ();Be wary of strong drink. It can make you shoot at tax collectors - and miss. Lazarus Long, "Time Enough For Love" by Robert A. Heinlein
I get the error when I'm calling
.setText()
. Everything related to the GUI must run on FX thread, but if you are running something on that thread, well until it is finished the interface is frozen. -
Where do you get the "Not on FX application thread" error? When trying to launch all those threads or when you try to update the GUI from within one of those threads? If it's the former, I can't help. If it's the latter, you simply need to run your update code on the UI thread. I don't use JavaFX but in my Java / Android, this works fine.
// called from a fragment
Thread worker = new Thread (new Runnable ()
{
@Override public void run ()
{
// stuff to do not on the UI thread
// ...// stuff is done, time to tell the UI activity.runOnUiThread (new Runnable () { @Override public void run () { // code that touches the UI } }); }
});
worker.start ();Be wary of strong drink. It can make you shoot at tax collectors - and miss. Lazarus Long, "Time Enough For Love" by Robert A. Heinlein
I get the error when I call
.setText()
. Everything related to the GUI must run on FX thread, but if you are running something intensive on that, then the interface will freeze, that is why you should run that on a different thread and make the updates later. -
I want to make it so that when the user launches the app, it will display the GUI but at the same time it will launch other threads (multithreading) that will do some calculations and when those are finished they will update some GUI elements (which are always created before the thread with calculations is launched, that is not a problem of getting null), also when a button is pressed same as before using multithreading it will do some calculation and update the GUI after each thread is done. Now the problem I have is that if you are using Thread(new Runnable)/start(); to launch multiple threads (even one) you get into the error
Not on FX application thread
. As possible solutions I read about JavaFX Task and Service but those were freezing the GUI thread until they were done. This is what I tried ("Functions.functionX" is the placeholder, the real function takes between 0-20 seconds to finish):button.setOnAction(event -> { Service doSomething = new Service() { @Override protected Task createTask() { Functions.functionX("parameter"); return null; } }; doSomething.start(); });
Now the problem with this is like I said, when the button is pressed, the GUI is unusable until the function finishes. Using straight Task had the same effect unfortunately. What do I need to change/add to make it so that I can launch multiple threads at a time, and inside them to change elements from GUI (right now I only want to update some Labels with .setText() inside those threads, each thread updates one Label)?
I managed to make it work but not with Task or Service. On button action I created a new
Thread thread = new Thread(new Runnable() {...});
, and after I was done with the calculation, still inside thread run function I called:Platform.runLater(new Runnable() { @Override public void run() { label.setText(newValue); } });
I am still interested what I should do to make it work with those too, if someone can explain what I was doing wrong.
-
I get the error when I call
.setText()
. Everything related to the GUI must run on FX thread, but if you are running something intensive on that, then the interface will freeze, that is why you should run that on a different thread and make the updates later.And that is exactly what my code does. It creates the thread worker from the UI thread and starts it. It then exits that UI function, effectively releasing the UI thread. Meanwhile, worker is executing its
Run
method separately from the UI. After it finishes doing stuff, worker then creates and runs a UI thread that updates the UI. JavaFX may have a different method to call instead ofrunOnUiThread
, but the logic is the same. JavaFX has to have an equivalent. Don't be confused by the code appearing to all be in the initial UI function. Each of thoseRun
methods is a chunk of code that executes in a separate and distinct thread. One caveat -- when running on Android, I have found that this doesn't always work to release the UI when it is done from within view creation / fragment startup. I don't know if JavaFX has the same issue. What I've shown works when launched from the UI once the screen is up and established; for example, from a menu item click handler.Be wary of strong drink. It can make you shoot at tax collectors - and miss. Lazarus Long, "Time Enough For Love" by Robert A. Heinlein