FXML performance is an issue with JavaFX, if you have complex screens and have divided them into small components (for maintainability / reuse) that use FXML, then it can get really slow.
As FXML parsing is made in UI Thread (not sure of this, still it blocks the JavaFX Application Thread), you cannot show a glasspane / popup / etc in JavaFX when FXML is being processed.
The only workaround I found is to use a Swing popup (as it is in Swing UI Thread, you can still show something) to provide a feedback to the user (it is working / not a bug / wait a little more) when FXML is being loaded and to close it when no more FXML files are parsed.
I have built a facade above FXMLLoader to do so. Also this also works with OpenGL libraries as well (LWJGL for instance, instead of Swing, anything that is UI and is not in JavaFX Application Thread works).
I was wondering if a better solution exists (JavaFX only, not mixing UI frameworks) as this artificially adds complexity to the project and won't be ported well with OpenJFX ports.
Recommended Solution
Use JavaFX 8u40+, you can find an early access release.
For 8u40, the following bug was fixed:
RT-17716 Some controls can only be created on the FX application thread
This fix allows you to create all controls (except currently a WebView) off of the JavaFX application thread. That means you can load up your FXML asynchronously to the JavaFX application thread within a standard JavaFX Task. While the task is running you can have a please wait dialog or animated progress indicator displayed or whatever you like (in JavaFX, no need to use other frameworks like Swing/LWJGL).
My favorite way of handling this is to load the FXML elements up while the user is shown a login prompt or needs to create some input (but whether or not you use the "load stuff in the background while awaiting user input" trick is app dependent).
You can also load your FXML in the init function of your application, so that the FXML is loaded in parallel to the JavaFX system starting up (you need to take care around threading a bit for that to ensure that you don't actually try to show your scene until all the FXML is loaded and the operation to show the scene occurs on the JavaFX application thread).
Alternate Solution
You could also try this solution to Convert FXML to Java as part of the build, then perhaps there won't be any issue with slow loading of FXML (because there is no longer any FXML, it has been converted to Java). But I don't know if that solution is currently mature and stable enough for your purposes.
Related
I have some code and when it executes, it throws a RuntimeException, saying:
JXBrowser should only be constructed on the EDT
it is stemming from when I'm creating a JXbrowser component
browser = (JXBrowser) browserFactory.create(true, WebBrowserType.JX);
What should I look for in fixing this error?
JavaFX (OpenJFX) is not thread-safe.
Like Swing, Vaadin, and most any other user-interface framework, you must limit all access to, and manipulation of, the widgets and other UI-related objects only from within the one thread dedicated to that framework.
Apparently your app is starting other threads and then performing JavaFX work on them. Never do this.
There are ways for you to perform lengthy tasks on background threads, and then upon completion post a request to the UI thread to update the UI widgets with the results. But you must study to learn those techniques.
See this tutorial and this one.
JxBrowser dropped this requirement since version 7.
In JxBrowser 7, you can initialize Engine and Browser in any thread. These operations are heavy and it's better not to do them in EDT.
Once the browser is created, you will need to create BrowserView and add it to your interface inside of EDT, according to Swing rules.
I am building a JavaFX app and am using JOptionPane to display dialogs
One of the problems I've encountered is that creating a new dialog and not dismissing it within 5 or so seconds will cause the main JavaFX stage go into a 'Not Responding' state
Running the joptionpane code in a new thread works, but causes the dialog not to be modal, which is not suitable for the app i'm building
This is all running in Windows.
Any ways to fix the not responding problem would be greatly appreciated :)
EDIT: The code I use is (from the main JavaFX thread)
JOptionPane.showMessageDialog(null, "message here");
Perhaps null is causing the problem?
You can't just show a JoptionPane, which is a Swing component, from the FX thread. You have three options:
create a Swing application and place all the fx nodes in JFXPanels.
use FX nodes only, for example by using a modal stage or by using an external library such as ControlsFX (JavaFX 8 only but there are other libraries available that work with JavaFX 2)
place your JOptionPane in a SwingNode (JavaFX 8 only)
For 1 and 3 you need to be careful to create/modify the Swing components on the Swing EDT thread and the JavaFX nodes on the JavaFX thread (unless you merge the two with the new JVM option available in Java 8). And I'm not 100% sure how the modality week work if you mix Swing and JavaFX.
If you are creating a JavaFX application there is little reason not to choose 2.
Don't use JOptionPane in a JavaFX application, use a JavaFX Alert instead. Alert was introduced in Java 8u40.
Using JOptionPane in JavaFX may be problematic due to the reasons pointed out in assylias's answer.
See also:
No errors, but crashing - JOptionPane - JavaFX
I'm trying to create a Window class which I can use to open multiple windows, and which will automatically add an event handler to listen for the Swt.CLOSE event, and call the shell.dispose() method when it is called.
My questions are:
Do I need to listen for shell.dispose() in this case, or to only listen for display.dispose() in my main method?
Do I need to run each window in its own thread, or can all the windows share the same UI thread? I've read some reports of buggy behavior related to event handling in case of multiple windows being open.
I recommend you should always have a single UI thread, which the single Display object runs on. See SWT: single vs. multiple displays or even the Eclipse documentation on Display that strongly recommends using a single Display object:
Applications which are built with SWT will almost always require only a single display. In particular, some platforms which SWT supports will not allow more than one active display.
There are even several sample apps available (such as this one) that demonstrate multiple shells in SWT. Calling shell.dispose() when you want to close a window is the way to go.
You should only use display.dispose() when you are shutting down the entire app, basically as a 'last step' - see this example, or this one, or pretty much any snippet on the SWT Snippets page.
Edit
The Eclipse framework itself is an example of an application that can have multiple windows - it still uses a single Display, with a single UI Thread and shared event system. Eclipse documentation on Threading Issues has a basic explanation of this:
Underneath any GUI application, regardless of its language or UI toolkit, the OS platform detects GUI events and places them in application event queues. [...] It determines which window and application should receive each event and places it in the application's event queue.
I am not too experienced with Java and am having trouble getting a progress bar to work. I am using Netbeans' built-in GUI maker. Currently my program reads in images from a directory into an image array. Obviously this takes a bit of time, thus I would like a simple progress bar to update the user to know how far the loading is. I have used one of those drag-and-drop progress bar components.
I currently can get the number of files in a directory and can calculate the percentage of files loaded
The files successfully load into the array, but the progress bar is only updated after all files are loaded. I have tried revalidating and repainting while I loop but this does not work
I have tried the various tutorials on docs.oracle but can't seem to get anything working.
I believe SwingWorker is the class I should be using, is this correct?
Any help with an example or some advice would be greatly appreciated!
Thanks!
Yes, you have run into the trap of all new Swing programers - the Event Dispatching Thread
Basically speaking, this Thread is the heart of any Swing system. Is is responsible for dispatching events to all the UI components, as well as making requests to the repaint manager to update the UI.
If you do any time consuming tasks while in the EDT, you will prevent the UI from been updated.
I'd suggest you start by having a read through Worker Threads and SwingWorker and Concurrency in Swing and, because I know you're going to ask, have a read of this answer, it has a number of examples of using SwingWorker, JTextArea appending problems
I have a Java application that run as a background service, i.e. no GUI. But when starting it, say through a batch script, I have some preparation works to be done at the very beginning of my program (something like communicate with server).
I want a busy cursor appear at this busy moment. Is it possible to do this without using any Swing component? Thanks for any suggestion or alternative approach.
I'd go for a console-based "progress bar". It's possible to use Swing but it would render your solution useless in a headless environment. Drawing progress bars with characters in terminal is quite a common practice.
You can either implement it yourself or use a ready class. Just take a look at github or bitbucket and you'll find something for sure.
A busy cursor could even be displayed as a caption with alternating last character (as simple as possible), with "frames" like these (rotating bar)
LOADING DATA /
LOADING DATA |
LOADING DATA \
LOADING DATA -
Implementing something like this wouldn't take much time. We're talking about minutes here.
If the only thing that prevents you from using Swing is an appearing window, you can change its appearance thanks to window translucency. This way you'd get an animated image overlaying your screen. It wouldn't work in a terminal though.
If you're able to use Java AWT (Abstract Window Toolkit) I beleive you can use the setCursor of Component class to change the cursor.
More on this : http://www.roseindia.net/java/example/java/awt/ChangeCursor.shtml