At one point in my application, I have to save a JavaFX UI which takes a long time. During this save, I have to show a Progress Dialog telling the user what is happening at that time.
I have read that heavy tasks should be ran using a Task and not the JavaFX thread. However, this is not possible for me for the 2 following reasons:
1- The heavy tasks include JavaFX confirmation dialog popups which are sometimes buggy on MAC if not called by the JavaFX thread.
2- The save method must return a boolean to tell if the save went ok or not. And this save method is triggered by the JavaFX thread. Meaning the JavaFX thread must return the boolean variable and has to wait for the Task to finish before doing that.
And sadly the JavaFX UI is integrated in a Swing UI which makes it more difficult to work with.
Task is just one implementation of the javafx.concurrent.Worker interface, which provides facilities to communicate with the GUI respectively the JavaFX thread. Other implementations are Service and ScheduledService. Basically, the difference is that Service is designed for reuse, whereas Task isn't, and ScheduledService can restart itself after execution.
So, to address your two concerns:
The heavy tasks include JavaFX confirmation dialog popups which are sometimes buggy on MAC if not called by the JavaFX thread.
As mentioned before, the Worker interface provides a nice API to update the GUI from another thread. For instance, from the JavaFX thread, you can easily bind a Labeled to the message property which gets updated from the background thread.
The save method must return a boolean to tell if the save went ok or not. And this save method is triggered by the JavaFX thread. Meaning the JavaFX thread must return the boolean variable and has to wait for the Task to finish before doing that.
For example, Task's call() method can return arbitrary objects, which includes Boolean. Moreover, the Worker interface has a getValue() method to retrieve the result from the corresponding worker.
I recommend reading the "Concurrency in JavaFX" tutorial for further information. For ProgressBar itself, have a look at the "Progress Bar and Progress Indicator" tutorial.
Related
I have an application that has multiple screens and a process that needs to get UI info from some and update others.
Tried many methods but the result always is always "not a Java FX thread". Without using some kind of thread the UI does not update Because of the multi screen nature of the app (not practical to change) I need to fundamentally change the application architecture which is why I am not posting any code - its all going to change.
What I cant work out is the best way to do this and as any changes are likely to require substantial work I am reluctant to try something that has little chance of success.
I know about Platform.runLater and tried adding that to the updates but that was complex and did not seem to be effective.
I do have the code on GitHub - its a personal leaning project that started in Scala 2 but if you have an interest in learning or pointing out my errors I can provide access.
Hope you have enjoyed a wonderful Christmas.
PS just make the repo public https://github.com/udsl/Processor6502
The problem is not that the Platform.runLater was not working its because the process is being called form a loop in a thread and without a yield the JavaFX thread never gets an opportunity to run. It just appeared to be failing β again I fall foul of an assumption.
The thread calls a method from within a loop which terminates on a condition set by the method.
The process is planned to emulate the execution of 6502 processor instructions in 2 modes run and run-slow, run-slow is run with a short delay after each instruction execution.
The updates are to the main screen the PC, status flags and register contents. The run (debug) screen gets the current instruction display updated and other items will be added. In the future.
The BRK instruction with a zero-byte following is captures and set the execution mode to single-step essentially being a break point though in the future it will be possible via the debug screen to set a breakpoint and for the execution of the breakpoint to restore the original contents. This is to enable the debugging of a future hardware item β time and finances permitting β itβs a hobby after all π
It terns out that the JavaFX thread issue only happens when a FX control is written to but not when read from. Placing all reads and writes in a Platform.runLater was too complex which is why I was originally searching for an alternative solution but now only needed it protect the writes is much less a hassle.
In the process loop calling Thread.βyieldβ() enables the code in the Platform.runLater blocks to be executed on the JavaFX thread so the UI updates without an exception.
The code in the Run method:
val thread = new Thread {
override def run =
while runMode == RunMode.Running || runMode == RunMode.RunningSlow do
executeIns
Thread.`yield`()
if runMode == RunMode.RunningSlow then
Thread.sleep(50) // slow the loop down a bit
}
thread.start
Note that because yield is a Scala reserved word needs to quote it!
Is it safe to use Swing timer for JavaFX or there is an special alternative for Swing? What is the differnce of the thread management between JavaFX and Swing?
In fact I'm interested to know the equivalents of Swing Timer, SwingUtilities.invokeLater() and invodeAndWait() for JavaFX.
By the way what if we use some Swing components in the JavaFX? Should we use two parallel Timer/Threads for updating those components?
JavaFX equivalent of SwingUtilities.invokeLater()
Platform.runLater(java.lang.Runnable runnable)
See also JavaFx response to SwingUtilities.invokeLater.
JavaFX equivalent of invokeAndWait()
The public JavaFX API deliberately does not expose an invokeAndWait call on Platform.runLater because it is easy to deadlock yourself with it, so you can use the below code instead as long as you know exactly what you are doing.
final FutureTask query = new FutureTask(new Callable() {
#Override
public Object call() throws Exception {
return queryPassword();
}
});
Platform.runLater(query);
System.out.println(query.get()); // the get blocks until the query FutureTask completes.
See also Return result from javafx platform runlater.
JavaFX equivalent of javax.swing.Timer.
Use a Timeline. The following will update a label displaying the date every second:
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Label dateLabel = new Label();
Timeline timeline = new Timeline(
new KeyFrame(
Duration.ZERO,
actionEvent -> dateLabel.set(dateFormat.format(new Date()))
),
new KeyFrame(
Duration.seconds(1)
)
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
See also the Timeline based answer to How to update the label box every 2 seconds in java fx?.
If we use some Swing components in the JavaFX? Should we use two parallel Timer/Threads for updating those components?
I think not, depends on the app, but generally a single Timer for the application would be preferred. This is kind of a specialized case. Generally, if you have some asynchronous process happening on a Timer, you want it to happen all at once, so the Timer fires, does some processing, then shunts the results back to the GUI. As you are mixing two UI frameworks, it's a little more complicated because you want to update both frameworks with results at the same time or within the same render frame.
To approximate this, I'd advise using just a plain java.util.Timer, rather than a javax.swing.Timer, or use a ScheduledExectorService if you need more flexibility. Then, in the TimerTask or scheduled Runnable, perform your processing logic and after the processing is done make calls to Platform.runLater and seperately SwingUtilities.invokeLater as appropriate to shunt the results back to either JavaFX or Swing components.
Of course you should consider if mixing two frameworks such as this and dealing with the potential threading complications is worth it. If you are able to just use a single framework and rely on the concurrency approach which works best with that framework, I think that would be a preferred approach.
What is the difference of the thread management between JavaFX and Swing?
From a user point of view it is pretty similar. Both JavaFX and Swing remain single threaded frameworks for application layer UI processing. All user code for JavaFX runs on the JavaFX application thread. Moreover any code which may modify the active scene graph (nodes displayed on the stage), must run on the JavaFX application thread. These rules are similar to the nature of thread management in Swing programming.
The JavaFX application thread and the Swing thread in the initial release of Java 8 are different by default. So:
To update Swing components from the JavaFX application thread, use Platform.runLater to switch processing from the JavaFX thread to the Swing thread.
To update JavaFX nodes from the Swing thread, use SwingUtilities.invokeLater to switch processing from the Swing thread to the JavaFX thread.
A future release of the Java platform may feature a unified application thread for Swing and JavaFX.
Note that the internal threading implementation used in library code differs between Swing and JavaFX. JavaFX will use different hardware and software rendering pipelines which can run on their own thread. However, this internal implementation detail is completely hidden from the application programmer.
Reference Documentation
Concurrency in JavaFX Tutorial by Oracle. In particular, see the sections on Task and Service for managing background operations from JavaFX, topics which are not explicitly discussed in this answer.
I'm a complete noob with JavaFX 2 - (started this morning with a HelloWorld that I'm adapting).
I need to update a Text node with the result of a background thread. Is there anything special I need to be aware of with JavaFX2 or is it simply enough to submit a callable and update the text. A pointer to a tutorial would be appreciated.
After calculating the results, running the
Platform.runLater(new Runnable() {
#Override
public void run() {
// Update the text node with calculated results
}
});
at the end of the same background thread is enough in normal situations. This link also maybe helpful:
Execute task in background in JavaFX.
Platform.runLater() will run later on the JavaFX application thread - which is fine if the executed content is a quick running task (e.g. inexpensive computation without I/O or just a call to update the UI). Use a Timeline for animation or timer based things. Otherwise a Task or Service based solution, for which there is a tutorial. Don't ever read or write from objects involved in an active scenegraph (even updates triggered by binds) off of the JavaFX application thread. Some further discussion and examples are in this forum thread.
I'm new to development on Windows Phone 7 and Silverlight but I do have experience in win32 and threading in general.
Here's my question:
I am trying to "synchronize" the UI thread w/ another thread that seems to be used by the API's of the object that I am working with. In other words, I would like to make sure that before the user dismisses the current XAML page by pressing the back button, the object that I am working with, which is part of the C# class behind the XAML page is deallocated.
The reason for that is that if I have the deallocation code in the NavigatedFrom handler, the UI thread may attempt to release the object WHILE it is in fact used by the other thread. Therefore, I do have to somehow synchronize the deallocation of this object.
Ideally, when the user presses the back button on the phone, all I do is set a flag "quit" to true to indicate that the user intends to exit. The methods used by the object that are running on another thread, would "see" that this flag is set and then would BeginInvoke*emphasized text* the deallocation code of the object (only because the object has been allocated on the UI thread so I figured it makes sense to deallocate it on the same thread, not knowing its internal workings.) Finally, it would call NavigationService.GoBack() to ensure 'orderly' exit.
Unfortunately, I don't see a way of preventing the XAML page to be dismissed when the user presses the back button although I did override the NavigatedFrom and OnBackKeyPress methods. Even though they contain no code at all, the XAML page is dismissed anyway.
Another thing that is interesting and I would appreciate your comments on this, is that I have a timer (System.Windows.Threading.DispatchTimer). Would this timer be associated only with the C# class behind a XAML page that defines it? In other words, is there a concept of a "message pump" associated with each XAML pages or is there just one message pump for the UI thread that basically is used by ALL XAML pages ? I am asking this because although I dismiss the XAML page whose C# class defines the timer, it seems to still be running.
Thank you.
The reason for that is that if I have the deallocation code in the NavigatedFrom handler, the UI thread may attempt to release the object WHILE it is in fact used by the other thread. Therefore, I do have to somehow synchronize the deallocation of this object.
Not really a problem. If you queue the navigation on the Dispatcher as well, you don't get any NullReferenceExceptions.
Simply use Dispatcher.BeginInvoke(() => NavigationService.Navigate(...)) for safe navigation.
Would this timer be associated only with the C# class behind a XAML page that defines it?
If you by "class" means "ViewModel", then yes, it most definitively should be in the ViewModel.
I have a multi-threaded Delphi 6 Pro application that I am currently working on heavily. If I set a breakpoint on any code that runs in the context of the Main thread (VCL thread) I don't have any problems. However, if a breakpoint is triggered on any code in one of my other threads, after I continue the application from the breakpoint, all repaints to the VCL components on the main thread (including the main form) don't happen anymore. The application isn't dead because other background code keeps running, just the main thread. It's as if the windows message dispatcher has been corrupted or rendered dormant.
Note, in this application I allocate my own WndProc() via allocateHwnd() on the main form because I need to catch certain registered messages. From that WndProc() I dispatch any custom messages I handle and if the current message is not handled by my code, I pass the message on by calling the main form's inherited WndProc(). If I do handle the current message I simply return from my WndProc() with Msg.Result set to 1 to tell the dispatcher that the message was handled. I can't simply override the TForm WndProc() instead of allocating my own WndProc() because for some reason the Delphi VCL does not pass through registered messages instantiated with the Windows API RegisterWindowMessage() call.
Has anybody experienced this in similar context and if so, what did you do to fix it?
-- roscherl
Since you call AllocateHWnd, that means you've created another window. You mustn't just take the messages that were addressed to that window and forward them to your form's window. Doing that, you're bound to screw things up in your program, although I'm not sure exactly how. Painting problems sound plausible. You should make sure it's really just painting problems and not that your main thread is still suspended. The debugger should be able to tell you that. (You should call DefWindowProc to make your allocated window handle messages you're not prepared to handle yourself. And returning 1 doesn't tell the dispatcher anything; the dispatcher doesn't care β whoever called SendMessage wants to know the result.)
I promise you that forms are completely capable of receiving registered window messages. Override WndProc or assign a new value to the WindowProc property (and remember to save the old value so you can call it after handling your own messages). The source of your problem lies elsewhere.
UPDATE: I'm not saying the way I got past the problem is a good solution. I need to take Rob Kennedy's notes and do some refactoring. However, to get past the problem for now I gave the thread it's own Window and WndProc() and at the top of the thread Execute loop I have a PeekMessage() while loop with calls to TranslateMessage() and DispatchMessage(). I no longer have a problem with setting breakpoints in the thread, but obviously this compounding of WndProc() methods indicates a structural problem in my code. I wanted to add this reply to fill out the discussion. I'm hoping that once I put Rob's suggestions to work when I clean up my WndProc() methods on the relevant forms, especially the main form, I can get rid of the this new WndProc() that I just added to the thread.
Robert.