{"id":1029,"date":"2014-03-31T22:41:42","date_gmt":"2014-03-31T20:41:42","guid":{"rendered":"http:\/\/www.jensd.de\/wordpress\/?p=1029"},"modified":"2014-03-31T22:43:06","modified_gmt":"2014-03-31T20:43:06","slug":"swing-and-javafx-working-with-jfxpanel","status":"publish","type":"post","link":"https:\/\/www.jensd.de\/wordpress\/?p=1029","title":{"rendered":"Swing and JavaFX: working with JFXPanel"},"content":{"rendered":"<p>I soon will have to deal with JavaFX in a Swing based fat client<br \/>\n&#8211; oh sorry, of course I meant &#8220;multi-layered rich-client&#8221; ;-)!<\/p>\n<p>So this brings me to have a look at the <strong>JFXPanel<\/strong>.<br \/>\nThe <strong>JFXPanel<\/strong> is a javax.swing.JComponent to embed JavaFX content into Swing-UIs. A JFXPanel can be used similar to a JPanel and can be accessed via the EDT as a generic Swing component except <strong>dealing with JavaFX component must be done via the JavaFX application thread<\/strong>.<\/p>\n<p>To play around with that stuff I created two similar Panels (Swing + JavaFX) each with a Button, a TextField and a Label and placed them in a JSplitPane and a JFrame:<\/p>\n<p><iframe loading=\"lazy\" title=\"Swing &amp; JavaFX: Usage of JFXPanel\" width=\"900\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/JgP3Qildse0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<h1>A closer look inside<\/h1>\n<p>To try Swing <-> JavaFX interoperability the buttons actions are setting the text from TextField to JLabel and vice versa.<br \/>\nThere is nothing special with the JPanel as its handles generic Swing stuff, but with the <strong>JFXPanel<\/strong> containing the JavaFX controls:<\/p>\n<p>[java]<br \/>\npublic class SwingFXPanel extends JFXPanel {<\/p>\n<p>    private Button testButton;<br \/>\n    private TextField testTextField;<br \/>\n    private Label testLabel;<br \/>\n    private VBox pane;<\/p>\n<p>    public SwingFXPanel() {<br \/>\n        init();<br \/>\n    }<\/p>\n<p>    private void init() {<br \/>\n        testButton = new Button(&#8220;I am a JavaFX Button&#8221;);<br \/>\n        testTextField = new TextField();<br \/>\n        testLabel = new Label(&#8220;empty&#8221;);<br \/>\n        pane = new VBox();<br \/>\n        pane.setAlignment(Pos.CENTER);<br \/>\n        pane.getChildren().addAll(testTextField, testButton, testLabel);<br \/>\n        Platform.runLater(this::createScene);<br \/>\n    }<\/p>\n<p>    private void createScene() {<br \/>\n        Scene scene = new Scene(pane);<br \/>\n        setScene(scene);<br \/>\n    }<\/p>\n<p>    public Button getTestButton() {<br \/>\n        return testButton;<br \/>\n    }<\/p>\n<p>    public TextField getTestTextField() {<br \/>\n        return testTextField;<br \/>\n    }<\/p>\n<p>    public Label getTestLabel() {<br \/>\n        return testLabel;<br \/>\n    }<br \/>\n}<br \/>\n[\/java]<\/p>\n<p>Important here: to add the Scene to the JFXPanel within the JavaFX Application Thread: <\/p>\n<pre>Platform.runLater(this::createScene);<\/pre>\n<p>If you call <\/p>\n<pre>createScene()<\/pre>\n<p> from another thread you get a Runtime-Exception:<\/p>\n<pre>java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0<\/pre>\n<p>Also each interaction with JavaFX related stuff must be placed on the JavaFX Application Thread:<\/p>\n<p><strong>E.g.:<\/strong><\/p>\n<pre>\r\nPlatform.runLater(() -&gt; {\r\n   swingFXPanel.getTestLabel().setText(swingPanel.getTestTextField().getText());\r\n});\r\n<\/pre>\n<p>[java]<br \/>\npublic class InteropFrame extends JFrame {<\/p>\n<p>    private JSplitPane centralSplitPane;<br \/>\n    private SwingPanel swingPanel;<br \/>\n    private SwingFXPanel swingFXPanel;<\/p>\n<p>    public InteropFrame(){<br \/>\n        init();<br \/>\n    }<\/p>\n<p>    private void init() {<br \/>\n        setTitle(&#8220;Swing <-> JavaFX Interoperatbiliy&#8221;);<br \/>\n        setSize(500, 500);<br \/>\n        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br \/>\n        setLayout(new BorderLayout());<\/p>\n<p>        centralSplitPane = new JSplitPane();<br \/>\n        centralSplitPane.setDividerLocation(0.5);<br \/>\n        centralSplitPane.setResizeWeight(0.3);<\/p>\n<p>        swingPanel = new SwingPanel();<br \/>\n        swingFXPanel = new SwingFXPanel();<\/p>\n<p>        swingPanel.getTestButton().addActionListener((ActionEvent e) -> {<br \/>\n            Platform.runLater(() -> {<br \/>\n                swingFXPanel.getTestLabel().setText(swingPanel.getTestTextField().getText());<br \/>\n            });<br \/>\n        });<\/p>\n<p>        swingFXPanel.getTestButton().setOnAction((javafx.event.ActionEvent t) -> {<br \/>\n            swingPanel.getTestLabel().setText(swingFXPanel.getTestTextField().getText());<br \/>\n        });<\/p>\n<p>        centralSplitPane.setLeftComponent(swingPanel);<br \/>\n        centralSplitPane.setRightComponent(swingFXPanel);<\/p>\n<p>        add(centralSplitPane, BorderLayout.CENTER);<br \/>\n    }<br \/>\n}<br \/>\n[\/java]<\/p>\n<h1>Alternatively also dealing with FXML is quite simple:<\/h1>\n<p>[java]<br \/>\npublic class SwingFXMLPanel extends JFXPanel {<\/p>\n<p>    @FXML<br \/>\n    private Button testButton;<br \/>\n    @FXML<br \/>\n    private TextField testTextField;<br \/>\n    @FXML<br \/>\n    private Label testLabel;<\/p>\n<p>    private VBox rootPane;<\/p>\n<p>    private URL fxmlResource;<\/p>\n<p>    public SwingFXMLPanel(URL fxmlResource){<br \/>\n        this.fxmlResource = fxmlResource;<br \/>\n        init();<br \/>\n    }<\/p>\n<p>    private void init(){<br \/>\n        rootPane = new VBox();<br \/>\n        FXMLLoader loader = new FXMLLoader(fxmlResource);<br \/>\n        loader.setController(this);<br \/>\n        loader.setRoot(rootPane);<br \/>\n        try {<br \/>\n            loader.load();<br \/>\n        } catch (IOException ex) {<br \/>\n            Logger.getLogger(SwingFXMLPanel.class.getName()).log(Level.SEVERE, null, ex);<br \/>\n        }<\/p>\n<p>        testButton.setText(&#8220;I am a JavaFX Button&#8221;);<br \/>\n        testLabel.setText(&#8220;empty&#8221;);<\/p>\n<p>        Platform.runLater(this::createScene);<br \/>\n    }<\/p>\n<p>    private void createScene() {<br \/>\n        Scene scene = new Scene(rootPane);<br \/>\n        setScene(scene);<br \/>\n    }<\/p>\n<p>    public Button getTestButton() {<br \/>\n        return testButton;<br \/>\n    }<\/p>\n<p>    public TextField getTestTextField() {<br \/>\n        return testTextField;<br \/>\n    }<\/p>\n<p>    public Label getTestLabel() {<br \/>\n        return testLabel;<br \/>\n    }<\/p>\n<p>}<br \/>\n[\/java]<\/p>\n<p><strong>For me its very important to get the most possible acceptance of my co-workers to use JavaFX in Swing.<\/strong><br \/>\nTherefore I want to simplify the specific FX application thread handling.<br \/>\nSo maybe this can be achieved if the major difference to using a JPanel is just to add <\/p>\n<pre>\r\n    private void createScene() {\r\n        Scene scene = new Scene(rootPane);\r\n        setScene(scene);\r\n    }\r\n<\/pre>\n<p>and to call <\/p>\n<pre>\r\n  Platform.runLater(this::createScene);\r\n<\/pre>\n<p>inside the <strong>JFXPanel<\/strong>.<\/p>\n<p><strong>You can find the complete example code <a href=\"https:\/\/bitbucket.org\/Jerady\/javafx-swing-interoperation\" title=\"https:\/\/bitbucket.org\/Jerady\/javafx-swing-interoperation\" target=\"_blank\">here<\/a>.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I soon will have to deal with JavaFX in a Swing based fat client &#8211; oh sorry, of course I meant &#8220;multi-layered rich-client&#8221; ;-)! So this brings me to have a look at the JFXPanel. The JFXPanel is a javax.swing.JComponent to embed JavaFX content into Swing-UIs. A JFXPanel can be used similar to a JPanel&hellip; <span class=\"clear\"><\/span><a href=\"https:\/\/www.jensd.de\/wordpress\/?p=1029\" class=\"more-link read-more\" rel=\"bookmark\">Continue Reading <span class=\"screen-reader-text\">Swing and JavaFX: working with JFXPanel<\/span><i class=\"fa fa-arrow-right\"><\/i><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false,"jetpack_publicize_message":"Swing and JavaFX: working with JFXPanel http:\/\/wp.me\/p38FCL-gB","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[4,41,8,40],"tags":[76,100,99],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p38FCL-gB","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1029"}],"collection":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1029"}],"version-history":[{"count":31,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1029\/revisions"}],"predecessor-version":[{"id":1061,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1029\/revisions\/1061"}],"wp:attachment":[{"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1029"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1029"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jensd.de\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1029"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}