JavaFX
From APIDesign
(8 intermediate revisions not shown.) | |||
Line 1: | Line 1: | ||
- | [[wikipedia:JavaFX|JavaFX]] is new, modern UI toolkit for rendering [[Java]] UIs. The idea is tempting - instead of bloated [[wikipedia:Abstract_Window_Toolkit|AWT]] with [[Swing]] on top, one can use a completely independent UI and lightweight library instead. However, as usual when offering [[AlternativeBehaviour]], the problem is [[co-existence]] - there are tons of [[Swing]] applications around and they need to migrate to [[JavaFX]] in an incremental fashion. Unless such migration is smooth, people will rather stick with what they have right now. | + | [[wikipedia:JavaFX|JavaFX]] is new, modern UI toolkit for rendering [[Java]] UIs. The idea is tempting - instead of bloated [[wikipedia:Abstract_Window_Toolkit|AWT]] with [[Swing]] on top, one can use a completely independent UI and lightweight library (which can for example be deployed to [[iOS]]) instead. However, as usual when offering [[AlternativeBehaviour]], the problem is [[co-existence]] - there are tons of [[Swing]] applications around and they need to migrate to [[JavaFX]] in an incremental fashion. Unless such migration is smooth, people will rather stick with what they have right now. |
=== Dispatch Threads === | === Dispatch Threads === | ||
- | Up until today (e.g. May 2012) mixing [[Swing]] and [[JavaFX]] was not easy because each of these two systems used its own dispatch thread. Whenever one needed to operate with [[Swing]] one had to enter the dispatch thread by using {{JDK|java/awt|EventQueue}}.invokeLater({{JDK|java/lang|Runnable}}). As soon as there was a need to manipulate with [[JavaFX]] components one had to use {{FX|javafx/application|Platform}}.runLater({{JDK|java/lang|Runnable}}). As [[Java]] is not very good at this kind of [[wikipedia:Actor_model|actor]] based coding, the result was completely unreadable code full of deeply nested {{JDK|java/lang|Runnable}}s: | + | Up until today (e.g. May 2012) mixing [[Swing]] and [[JavaFX]] was not easy because each of these two systems used its own dispatch thread. Whenever one needed to operate with [[Swing]] one had to enter the dispatch thread by using {{JDK|java/awt|EventQueue}}.invokeLater({{JDK|java/lang|Runnable}}). As soon as there was a need to manipulate with [[JavaFX]] components one had to use {{FX|javafx/application|Platform}}.runLater({{JDK|java/lang|Runnable}}). As [[Java]] is not very good at this kind of [[wikipedia:Actor_model|actor]] based coding, the result was completely unreadable code full of deeply nested {{JDK|java/lang|Runnable}}s. Here is very simple example: |
<source lang="java"> | <source lang="java"> | ||
Line 36: | Line 36: | ||
When your code is running (handling a [[Swing]] event) how can you tell in which thread it is running? Of course, there is {{JDK|java/lang|Thread}}.getName(), but beyond that, there is no way for your code to see any differences between the old ''AWT-EventQueue-X'' thread and new {{FX|javafx/application|Platform}}.runLater thread. All event processing remains synchronized (no code runs in parallel), so how could your code tell it is running in different thread? No chance, that is why I believe this change is completely safe. | When your code is running (handling a [[Swing]] event) how can you tell in which thread it is running? Of course, there is {{JDK|java/lang|Thread}}.getName(), but beyond that, there is no way for your code to see any differences between the old ''AWT-EventQueue-X'' thread and new {{FX|javafx/application|Platform}}.runLater thread. All event processing remains synchronized (no code runs in parallel), so how could your code tell it is running in different thread? No chance, that is why I believe this change is completely safe. | ||
- | + | The change has been integrated as http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/ae4683a6b860 and is available in [[JDK]]8. To greatly improve life for guys trying to mix [[Swing]] with [[JavaFX]] just do following before instantiating your AWT and FX objects: | |
+ | |||
+ | <source lang="java"> | ||
+ | public static void main(String... args) { | ||
+ | System.setProperty("javafx.embed.singleThread", "true"); | ||
+ | SwingUtilities.invokeLater(new Runnable() { | ||
+ | @Override | ||
+ | public void run() { | ||
+ | JFrame frame = new JFrame("FX"); | ||
+ | final JFXPanel fxPanel = new JFXPanel(); | ||
+ | frame.add(fxPanel); | ||
+ | frame.setVisible(true); | ||
+ | |||
+ | // Swing and JavaFX threads are the same | ||
+ | Scene scene = createScene(); | ||
+ | fxPanel.setScene(scene); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | The only problem is that this change has been integrated only for [[OS X]] toolkit! I am not sure what the [[Swing]] guys were smoking? Why they didn't integrate the behavior into all AWT toolkits? | ||
+ | |||
+ | But who cares about [[JavaFX]] anymore, when the future is in [[DukeScript]], right? | ||
<comments/> | <comments/> |
Current revision
JavaFX is new, modern UI toolkit for rendering Java UIs. The idea is tempting - instead of bloated AWT with Swing on top, one can use a completely independent UI and lightweight library (which can for example be deployed to iOS) instead. However, as usual when offering AlternativeBehaviour, the problem is co-existence - there are tons of Swing applications around and they need to migrate to JavaFX in an incremental fashion. Unless such migration is smooth, people will rather stick with what they have right now.
Dispatch Threads
Up until today (e.g. May 2012) mixing Swing and JavaFX was not easy because each of these two systems used its own dispatch thread. Whenever one needed to operate with Swing one had to enter the dispatch thread by using EventQueue.invokeLater(Runnable). As soon as there was a need to manipulate with JavaFX components one had to use Platform.runLater(Runnable). As Java is not very good at this kind of actor based coding, the result was completely unreadable code full of deeply nested Runnables. Here is very simple example:
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame("FX"); final JFXPanel fxPanel = new JFXPanel(); frame.add(fxPanel); frame.setVisible(true); Platform.runLater(new Runnable() { @Override public void run() { // This method is invoked on JavaFX thread Scene scene = createScene(); fxPanel.setScene(scene); } }); } }); }
I am proud to announce that the mutual Swing and JavaFX interoperability has been greatly simplified during May 2012. No need for massive amount of asynchronous Runnables! Your Swing code can directly talk to JavaFX data structures and your JavaFX code can do the same to Swing objects. This is a small change, but huge step forward for Swing+JavaFX interoperability!
The basic idea is to share the Swing and JavaFX dispatch threads. Trivial implementation would keep the AWT-EventQueue-X and just make sure one will always use Platform.runLater to dispatch the Swing events. More advanced implementation can even eliminate the need for AWT-EventQueue-X thread completely (as the patch shows). By running the event processing in the same thread, it is safe to access Swing as well as JavaFX APIs directly which greatly simplifies the coding model.
I've send my patch to Artem (Oracle's JavaFX guru) as a sketch of what could be done and the news from Artem are really great. The basic interoperability seems to work fine. Originally I was slightly afraid whether processing of events in different thread will work seamlessly, but now (when it has been experimentally verified) I think the chances have always been high for this system to work well.
When your code is running (handling a Swing event) how can you tell in which thread it is running? Of course, there is Thread.getName(), but beyond that, there is no way for your code to see any differences between the old AWT-EventQueue-X thread and new Platform.runLater thread. All event processing remains synchronized (no code runs in parallel), so how could your code tell it is running in different thread? No chance, that is why I believe this change is completely safe.
The change has been integrated as http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/ae4683a6b860 and is available in JDK8. To greatly improve life for guys trying to mix Swing with JavaFX just do following before instantiating your AWT and FX objects:
public static void main(String... args) { System.setProperty("javafx.embed.singleThread", "true"); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame("FX"); final JFXPanel fxPanel = new JFXPanel(); frame.add(fxPanel); frame.setVisible(true); // Swing and JavaFX threads are the same Scene scene = createScene(); fxPanel.setScene(scene); } }); }
The only problem is that this change has been integrated only for OS X toolkit! I am not sure what the Swing guys were smoking? Why they didn't integrate the behavior into all AWT toolkits?
But who cares about JavaFX anymore, when the future is in DukeScript, right?
<comments/>