HTML in Swing applications? Yes, you have read it right. Swing doesn’t provide components to embed HTML and I have seen lot of people asking how can we add html content in Swing applications. Your concerns have been addressed by the latest release of JavaFX which is JavaFX 2.0. You might wonder what this JavaFX is, so let me just touch upon that as well.
also read:
- Java Tutorials
- Java EE Tutorials
- Design Patterns Tutorials
- Java File IO Tutorials
JavaFX is the RIA platform envisaged by Sun Microsystems as the next UI toolkit for Java, as Swing has been around for a long time and has started to age. The initiative was good, but was not rightly implemented. The JavaFX 1, 1.2, 1.3 or in general anything before 2.0 is no longer supported. Pre JavaFX 2.0 one had to use JavaFX Script to create the applications and these could invoke the Java API. But learning a new language altogether was not appealing for a Java developer as one couldn’t easily use with existing Java code base. In 2.0 the JavaFX Script was totally removed to make way for the Java based api for creating JavaFX components. Once you have setup the JavaFX SDK, you get to use the JavaFX specific API in the javafx.* packages. There are lot of cool things underneath the JavaFX platform, but that’s out of the scope of this article.
Coming back to our main focus, JavaFX provides a component called WebView which with the help of WebEngine can be used to load web pages along with constructing the DOM and running the required JavaScript. But that’s a JavaFX component. How is it going to help us in our Swing application? Exactly, JavaFX provides another component called JFXPanel which can be used to embed JavaFX components into Swing applications and in turn the JFXPanel is added to our JFrame or other Swing containers.
JFrame myFrame = new JFrame(); JFXPanel myFXPanel = new JFXPanel(): myFrame.add(myFXPanel);
Now the required JavaFX components would be added to the JFXPanel. The JavaFX components are to be created only in the JavaFX Application thread and not in the main thread or the thread created using SwingUtilities.invokeLater. Before that lets just get familiar with a few JavaFX components which we would be using in this example:
- javafx.scene.Scene: All components in the JavaFX application are represented as a scene graph – a collection of parent and child components. The Scene component is the container for the scene graph or the components, and we define the root for all these containers when we instantiate the Scene component.
- javafx.scene.layout.BorderPane: Its the JavaFX’s version of all familiar Swing BorderLayout.
So lets try to add a WebView component to the JFXPanel.
Platform.runLater(new Runnable() { @Override public void run() { BorderPane borderPane = new BorderPane(); WebView webComponent = new WebView(); webComponent.getEngine().load("http://google.com/"); borderPane.setCenter(webComponent); Scene scene = new Scene(borderPane,450,450); myFXPanel.setScene(scene); } });
The Platform.runLater creates a JavaFX application thread, and this thread has to be used for all the JavaFX based operations (we can create multiple such threads, but yes, for any of the JavaFX related operation is carried out as part of this thread).
In the above snippet, we create an instance of BorderPane, set it as the root of scene when we create a Scene object and then add the WebView to the BorderPane. We also ask the WebEngine of the WebView to load the URL: www.google.com. The scene object is then added to the JFXPanel. Remember, that JFXPanel is alread added to the JFrame or some Swing components. So you have a Swing application loading your web pages.
Below is the complete code for loading web pages in Swing applications.
import javafx.application.Platform; import javafx.embed.swing.JFXPanel; import javafx.scene.Scene; import javafx.scene.layout.BorderPane; import javafx.scene.web.WebView; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class SwingHtmlDemo { public static void main(String [] args){ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { ApplicationFrame mainFrame = new ApplicationFrame(); mainFrame.setVisible(true); } }); } } /** * Main window used to display some HTML content. */ class ApplicationFrame extends JFrame{ JFXPanel javafxPanel; WebView webComponent; JPanel mainPanel; JTextField urlField; JButton goButton; public ApplicationFrame(){ javafxPanel = new JFXPanel(); initSwingComponents(); loadJavaFXScene(); } /** * Instantiate the Swing compoents to be used */ private void initSwingComponents(){ mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); mainPanel.add(javafxPanel, BorderLayout.CENTER); JPanel urlPanel = new JPanel(new FlowLayout()); urlField = new JTextField(); urlField.setColumns(50); urlPanel.add(urlField); goButton = new JButton("Go"); /** * Handling the loading of new URL, when the user * enters the URL and clicks on Go button. */ goButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Platform.runLater(new Runnable() { @Override public void run() { String url = urlField.getText(); if ( url != null && url.length() > 0){ webComponent.getEngine().load(url); } } }); } }); urlPanel.add(goButton); mainPanel.add(urlPanel, BorderLayout.NORTH); this.add(mainPanel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(700,600); } /** * Instantiate the JavaFX Components in * the JavaFX Application Thread. */ private void loadJavaFXScene(){ Platform.runLater(new Runnable() { @Override public void run() { BorderPane borderPane = new BorderPane(); webComponent = new WebView(); webComponent.getEngine().load("http://google.com/"); borderPane.setCenter(webComponent); Scene scene = new Scene(borderPane,450,450); javafxPanel.setScene(scene); } }); } }
I used JavaFX SDK for Linux on Ubuntu and IntelliJ to develop this sample application. One can download the JavaFX SDK from here.