Embedding HTML into Java Swing Applications

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:

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.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Comments

  1. Very Interesting Code

  2. “Embedding HTML into Java Swing Applications” – Not JavaFX applications.

    • There is no point in using Swing if you have JFX handy. Also, JavaFX has its immediate drawback being not integral part of JDK.

      “Swing doesn’t provide components to embed HTML” – This is wrong as several components like JLabel support HTML. Their implementation is nearly useless however (CSS problems, failing to parse if doctype declaration present, even snippets must be enclosed in tags, etc.)

      Quick-and-dirty smaple snippet:

      // NOTE: excluded pkg and imports
      class Whatever {
      public static void main(String[] args) {
      JFrame f = new JFrame(“HTML Sample”);
      f.getContentPane().add(new JLabel(“ThisisHTML”));
      f.pack();
      f.setVisible(true);
      }
      }

      Again, this feature is, in most cases, insufficient for presenting nice-looking UI’s.

Trackbacks

  1. [...] our previous post we looked at how we can embed JavaFX components into Swing applications. As Java Swing lacks [...]

  2. JavaPins says:

    Embedding HTML into Java Swing Applications…

    Thank you for submitting this cool story – Trackback from JavaPins…

Speak Your Mind

*