Thursday, May 31, 2012

Communication between JavaFX and JavaScript inside WebView, using JSObject

The former articles demonstrate how to "Execute JavaScript in WebView from Java code" and "implement OnAlert EventHandler of WebEngine".

In order to call JavaFX from Javascript in WebView, we can create a JSObject in JavaFX, and then calling it's setMember() method to make it known to Javascript. After that, Javascript can call it's public methods and access it's public field.

Communication between JavaFX and JavaScript inside WebView


JavaFX code:
package javafxweb;

import java.net.URL;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFXWeb extends Application {
    
    private Scene scene;
    MyBrowser myBrowser;
    
    Label labelFromJavascript;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("java-buddy.blogspot.com");
        
        myBrowser = new MyBrowser();
        scene = new Scene(myBrowser, 640, 480);
        
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    class MyBrowser extends Region{
        
        HBox toolbar;
        VBox toolbox;
        
        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();
        
        public MyBrowser(){
            
            final URL urlHello = getClass().getResource("hello.html");
            webEngine.load(urlHello.toExternalForm());
            
            webEngine.getLoadWorker().stateProperty().addListener(
                    new ChangeListener<State>(){
                        
                        @Override
                        public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
                            if(newState == State.SUCCEEDED){
                                JSObject window = (JSObject)webEngine.executeScript("window");
                                window.setMember("app", new JavaApplication());
                            }
                        }
                    });
            
            
            JSObject window = (JSObject)webEngine.executeScript("window");
            window.setMember("app", new JavaApplication());
            
            final TextField textField = new TextField ();
            textField.setPromptText("Hello! Who are?");
            
            Button buttonEnter = new Button("Enter");
            buttonEnter.setOnAction(new EventHandler<ActionEvent>(){
                
                @Override
                public void handle(ActionEvent arg0) {
                    webEngine.executeScript( " updateHello(' " + textField.getText() + " ') " );
                }
            });
            
            Button buttonClear = new Button("Clear");
            buttonClear.setOnAction(new EventHandler<ActionEvent>(){
                
                @Override
                public void handle(ActionEvent arg0) {
                    webEngine.executeScript( "clearHello()" );
                }
            });
            
            toolbar = new HBox();
            toolbar.setPadding(new Insets(10, 10, 10, 10));
            toolbar.setSpacing(10);
            toolbar.setStyle("-fx-background-color: #336699");
            toolbar.getChildren().addAll(textField, buttonEnter, buttonClear);
            
            toolbox = new VBox();
            labelFromJavascript = new Label();
            toolbox.getChildren().addAll(toolbar, labelFromJavascript);
            labelFromJavascript.setText("Wait");
            
            getChildren().add(toolbox);
            getChildren().add(webView);
            
        }
        
        @Override
        protected void layoutChildren(){
            double w = getWidth();
            double h = getHeight();
            double toolboxHeight = toolbox.prefHeight(w);
            layoutInArea(webView, 0, 0, w, h-toolboxHeight, 0, HPos.CENTER, VPos.CENTER);
            layoutInArea(toolbox, 0, h-toolboxHeight, w, toolboxHeight, 0, HPos.CENTER, VPos.CENTER);
        }
        
    }
    
    public class JavaApplication {
        public void callFromJavascript(String msg) {
            labelFromJavascript.setText("Click from Javascript: " + msg);
        }
    }
    
}


hello.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset=utf-8>
<title>Hello Java-Buddy!</title>
 
<script>

function updateHello(user){
  document.getElementById("helloprompt").innerHTML="Hello: " + user;
}
 
function clearHello(user){
  document.getElementById("helloprompt").innerHTML="Hello <a href='http://java-buddy.blogspot.com/'>Java-Buddy</a>";
}

function callJavaFX(){
    var msg = document.getElementById("textto").value;
    app.callFromJavascript(msg);
}
</script>
 
</head>
<body>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxGfYYk9MPmsy4Fb5yBONPauX59KlswhZvZL_XoWgvPMp2SwHsLorHIo4aWZJsUc9oynuzwstK5MfzjmjmNevnJFjJt1HIhcl-iRH3dnK2twWSeX6MdjSbAz4nyMzaNQE1p-Pajqfg3KKN/s150/duke_44x80.png"/>
<p id="helloprompt">Hello <a href="http://java-buddy.blogspot.com/">Java-Buddy</a></p>
<p><textarea id="textto"> </textarea></p>
<p><input type="button" value="Click to send message to Javascript" onclick="callJavaFX()"></p>
</body>
</html>


Wednesday, May 30, 2012

Embed WebView in FXML, to load OpenLayers with OpenStreetMap.

Last article demonstrate how to "Embed OpenLayers with OpenStreetMap in JavaFX WebView". This article demonstrate how to do it in FXML.

Embed WebView in FXML, to load OpenLayers with OpenStreetMap.


New a JavaFX FXML Application in NetBeans.

Copy openstreetmap.html from last article.

Create MyBrowser.java, extends Region.
package javafxml_web;

import java.net.URL;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class MyBrowser extends Region{
        HBox toolbar;

        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();
        
        public MyBrowser(){
            
            final URL urlGoogleMaps = getClass().getResource("openstreetmap.html");
            webEngine.load(urlGoogleMaps.toExternalForm());
            
            getChildren().add(webView);
        
        }
}

Modify Sample.fxml to add MyBrowser, and remove un-used elements.
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafxml_web.*?>

<AnchorPane id="AnchorPane" prefHeight="500" prefWidth="660" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxml_web.Sample">
    <children>
        <MyBrowser id="mybrowser" layoutX="10" layoutY="10" prefHeight="460" prefWidth="620" fx:id="mybrowser" />
    </children>
</AnchorPane>

Modify Sample.java to remove un-used code.
package javafxml_web;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class Sample implements Initializable {
    
    @FXML
    private MyBrowser mybrowser;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {

    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
    
}

Embed OpenLayers with OpenStreetMap in JavaFX WebView

OpenLayers makes it easy to put a dynamic map in any web page. With OpenStreetMap, it's a free replacement of Google Maps. We can embed WebView loaded with OpenLayers in JavaFX to display map.

Embed OpenLayers with OpenStreetMap in JavaFX WebView


Create a HTML file, openstreetmap.html. Actually it's a normal web page HTML file.
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="utf-8" />
 <script type="text/javascript" src="http://openlayers.org/api/2.11/OpenLayers.js"></script>
 <script type="text/javascript" >
  var myMap;
   
  function loadOpenLayers(){  
   
   myMap = new OpenLayers.Map("mymap", {});
    
   var wms = new OpenLayers.Layer.WMS(
    "OpenLayers WMS",
    "http://vmap0.tiles.osgeo.org/wms/vmap0",
    {layers: "basic"},
    {});
     
   myMap.addLayer(wms);
 
   myMap.setCenter(new OpenLayers.LonLat(-122.349243, 47.651743));
   myMap.zoomTo(6);   
  } 
  
 </script>
</head>
<body onload="loadOpenLayers();">
 <div id="mymap" style="width: 620px; height: 460px; border: 1px solid;">
 </div>
 
</body>
</html>


Java Code
package javafx_openstreetview;

import java.net.URL;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFX_OpenStreetView extends Application {
    
    private Scene scene;
    MyBrowser myBrowser;
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("java-buddy.blogspot.com");
        
        myBrowser = new MyBrowser();
        scene = new Scene(myBrowser, 640, 480);
        
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    class MyBrowser extends Region{
        
        HBox toolbar;

        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();
        
        public MyBrowser(){
            
            final URL urlGoogleMaps = getClass().getResource("openstreetmap.html");
            webEngine.load(urlGoogleMaps.toExternalForm());
            
            getChildren().add(webView);
        
        }
    }
}


Related:
- Embed Google Maps in JavaFX WebView.
- Embed WebView in FXML, to load OpenLayers with OpenStreetMap.