I'm trying to teach myself JavaFX and stumbled over a problem I can't seem to fully understand even after reading anything remotely related I could find.
What I'm trying to do :
I basically want to run some quick processing in the background of my JavaFX application so to not block the UI for the user. While this is happening a UI element is put up which then should be removed as soon as the background process is finished.
So what I attempted to do was to just move those method calls into a Task which should then run without making the UI freeze.
Task task = new Task<Void>() {
#Override
protected Void call() {
step1();
step2();
step3();
}};
new Thread(task).start();
I want to call multiple methods of the class we're currently in, but what's happening instead is that only the first method gets invoked. It seems to me that after step1 has reached it's end it doesn't actually "return" to the Task. I've tried looking up how this works and what I could do but honestly didn't get any smarter. Basically all examples of threading and workers only included how to loop and do recurring things but I really just want a "single execution" but in background.
It's probably a really idiotic thing I'm trying to do and shows my little understanding of this but if anyone could point me into the right direction I'd be very thankful.
Thanks a lot!
Solution :
When working with JavaFX the use of "Platform.runLater(task)" is advisable since a normal Thread cannot interact with the UI. A IllegalStateException will be thrown and the thread is halted/canceled(?). The Task itself can remain unchanged but has to be handed to the Platform to execute it to prevent this issue. I changed that one line and everything was perfect afterwards.
I hope this might help someone, someday :-)
Related
I just try to show a loading-animation while I access an ERP in my code like this:
protected void submit()
{
messageField.getStyleClass().add("smallLoading");
submitImpl();
messageField.getStyleClass().remove("smallLoading");
}
Sadly the animation is never shown... Just the result as before. I tried using Platform.runLater, which yielded the same result. I also transfered the last 2 lines in a Thread, which worked (the animation was shown), but lead to the error "Not on FX application thread", when the Submitter tried to write to my message-field. When I passed the Thread to Platform.runLater it did not show the animation... I googled a little bit, but could not find a solution. Maybe I'm missing something important...
I appreciate any help. Thank you!
It seems like you don't really fully understand how the UI thread works.
The code you've posted is single-threaded. It all operates on the UI thread. You add a style class, do some work, then remove it. The problem is that this sequence of operations is effectively "atomic": the UI doesn't actually update anything until its all done. This is why you don't see the loading symbol change.
When you put all of this within runLater the result is the same. It's still all on the UI thread. The only difference here is that rather than running the code now, you're deferring it until some point "later" (probably actually very soon).
When you try to put the last two lines in a separate thread, the issue is that you're trying to make UI changes on a non-UI thread. That's not allowed.
What you want to do is run everything on a non-UI thread, and push back the UI operations to the UI thread with runLater. Something like this:
new Thread(() -> {
Platform.runLater(()-> messageField.getStyleClass().add("smallLoading"));
submitImpl();
Platform.runLater(()-> messageField.getStyleClass().remove("smallLoading"));
}).start();
Helo guys!
I am new to JavaFX. I am writing really small application which simulates working of printer. Simulation is running on special thread called PrintingProcess (this process is doing only one thing - waits given time and then increment counter). I need to send this value to window, where labels should show how many pages was "printed". Is any way to do it? So far I wrote small singleton class to hold value.
[edit] I solved it using tasks :) thanks for help
You should use the Task.updateProgress method. Call it to specify the current percentage of pages printed. Override Task.call to perform the action which needs to run in another thread. This method should never manipulate a JavaFX component. You can then oerride methods such as Task.succeeded to implement the behaviour of your UI when the print job is over. Look at the doc of this class to fully take advantage of it.
Platform.runLater(new Runnable() {
#Override public void run() {
textLabel.setText(yourValue);
}
});
The example above is quite simple. You ask JavaFX a runnable as soon as it can. I don't know how that works exactly but that's the way to change UI components from a non-JavaFX thread.
You could pass textLabel variable to any thread with a custom class or a new anonymous thread.
EDIT:
I find Dici's answer more appropriate for your application. I wouldn't recommend putting this code in any loop incase you may still use this.
Actually a basic Java question which I did not come along when I was learning this programming language.
For best understanding my question I will provide a simple sample:
block of code {
-new AsynTask..
-some code which I want to execute after AsyncTask finishes executing..
}
I know I can put the second line of code in postExcecute in AsyncTask object. But is it possible for program flow to continue after AsyncTask is finished executing?
You don't want to do this. This totally destroys the purpose of using an AsyncTask- it will halt the original thread until the task is done, preventing it from doing other things. If you wanted to do that, you'd be better off without the task. Instead, you should put the code you want to execute after the task is done in the onPostExecute method of the AsyncTask.
I have a GUI(JFrame), with two Buttons and 1 Panel to show the result. One Button is to start the algorithm, one for stopping it. By pressing start, a method is called and it starts running. The runtime of this method varies from couple of seconds to 2-3 minutes, depending on the input.
The problem I have hereby is, by pressing the start-button, the GUI gets completely locked. I cannot press any button till the algorithm terminates. It would be great to be able to stop the algorithm and to visualize parts of the solution after a certain amound of time.
I checked every single line of the Frame, there is nothing that disables it.
//If needed I can provide code, but its pretty long and just some hints and reasons for the problem would be great and I try to fix it by myself.
thanks in advance.
Don't put long-running tasks on the EDT, or the Event Dispatching Thread. Use threading or a SwingWorker instead. Hopefully that's enough google keywords to get you started. :)
It sounds like your algorithm is running in the same thread as the UI components. You probably want to read up on Concurrency and Concurrency in Swing to better understand how to create threads, monitor execution, integrating these concepts with a Swing-based user interface, and so forth. At a very high level, you are going to need to somehow spawn a new thread when your algorithm starts and observe it for intermediate state changes to update the UI. You only want user interface related code running in the event dispatch thread.
In my university, we are working with interfaces, using QT Jambi (Java) with the Eclipse Integration.
I would like to improve my design of my Elevator interface.
The main problem is that I would like to update the QLCDNumber with the floor in real-time.
What I do to simulate the elevator working, is to do a Thread.sleep(1000) between 2 floors, so that way, my QLCDNumber will display "an animation" saying "1...2...3...4". The problem is that the QLCDNumber only displays 1 and 4, no animation.
So, for example (resumed), the code I made is this one:
private void simulate(int floor){
while(actualFloor < floor){
try{
Thread.sleep(1000);
}catch(InterruptedException e){};
actualFloor++;
ui.LCDfloor.display(actualFloor);
}
}
Why this code only shows the 1st floor and the last one?
Sorry if you didn't understand what I wanted, my English is improving every day :)
Thank you in advance.
*Please note that LCDFloor is the name of the QLCDNumber widget
It looks like you have two problems:
(I assume) You're calling Thread.sleep() on the GUI thread. In other words, when you call simulate, you're doing so on the same thread as the rest of the gui operations. This causes the entire gui to pause.
You've never given Qt the chance to actually update the UI. When you call ui.LCDfloor.display(actualFloor), the a paint event is queued so that the UI can be updated, but rather than giving the UI a chance to actually execute the paint event, you continue with your loop which prevents the UI from ever being updated until after your simulation is finished.
You have two basic fixes:
Don't sleep, it's poor design. Instead, use timer's and signals to simulate the changes.
Force events to be processed using processEvents.
Also keep in mind that you can't update a GUI element from a non gui thread. And as this is homework, I'll leave the rest to you :).