简体   繁体   中英

Execute script Webview JavaFx

Here is my Browser JFrame:

public class Browser extends JFrame {

private final JFXPanel jfxPanel = new JFXPanel();
private WebEngine engine;

private final JPanel panel = new JPanel(new BorderLayout());
private final JLabel lblStatus = new JLabel();

private final JButton btnGo = new JButton("Go");
private final JTextField txtURL = new JTextField();
private final JProgressBar progressBar = new JProgressBar();

public Browser() {
    super();
    initComponents();
}

private void initComponents() {
    createScene();

    ActionListener al = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            loadURL(txtURL.getText());
        }
    };

    btnGo.addActionListener(al);
    txtURL.addActionListener(al);

    progressBar.setPreferredSize(new Dimension(150, 18));
    progressBar.setStringPainted(true);

    JPanel topBar = new JPanel(new BorderLayout(5, 0));
    topBar.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
    topBar.add(txtURL, BorderLayout.CENTER);
    topBar.add(btnGo, BorderLayout.EAST);

    JPanel statusBar = new JPanel(new BorderLayout(5, 0));
    statusBar.setBorder(BorderFactory.createEmptyBorder(3, 5, 3, 5));
    statusBar.add(lblStatus, BorderLayout.CENTER);
    statusBar.add(progressBar, BorderLayout.EAST);

    panel.add(topBar, BorderLayout.NORTH);
    panel.add(jfxPanel, BorderLayout.CENTER);
    panel.add(statusBar, BorderLayout.SOUTH);

    getContentPane().add(panel);

    setPreferredSize(new Dimension(1024, 600));
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    pack();

}

private void createScene() {

    Platform.runLater(new Runnable() {
        @Override
        public void run() {

            WebView view = new WebView();
            engine = view.getEngine();

            engine.titleProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, final String newValue) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            Browser.this.setTitle(newValue);
                        }
                    });
                }
            });

            engine.setOnStatusChanged(new EventHandler<WebEvent<String>>() {
                @Override
                public void handle(final WebEvent<String> event) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            lblStatus.setText(event.getData());
                        }
                    });
                }
            });

            engine.locationProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> ov, String oldValue, final String newValue) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            txtURL.setText(newValue);
                        }
                    });
                }
            });

            engine.getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, final Number newValue) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            progressBar.setValue(newValue.intValue());
                        }
                    });
                }
            });

            engine.getLoadWorker()
                    .exceptionProperty()
                    .addListener(new ChangeListener<Throwable>() {

                        public void changed(ObservableValue<? extends Throwable> o, Throwable old, final Throwable value) {
                            if (engine.getLoadWorker().getState() == FAILED) {
                                SwingUtilities.invokeLater(new Runnable() {
                                    @Override
                                    public void run() {
                                        JOptionPane.showMessageDialog(
                                                panel,
                                                (value != null)
                                                        ? engine.getLocation() + "\n" + value.getMessage()
                                                        : engine.getLocation() + "\nUnexpected error.",
                                                "Loading error...",
                                                JOptionPane.ERROR_MESSAGE);
                                    }
                                });
                            }
                        }
                    });

            jfxPanel.setScene(new Scene(view));
        }
    });
}

public void loadURL(final String url) {
    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            File file = new File(url);
            URL url;
            try {
                url = file.toURI().toURL();

                engine.getLoadWorker().stateProperty().addListener(
                        new ChangeListener<State>() {
                    public void changed(ObservableValue ov, State oldState, State newState) {
                        if (newState == State.SUCCEEDED) {
                            engine.executeScript("addPoint(0,-26.487000,151.984000)");
                        }
                    }
                });
                engine.load(url.toString());
            } catch (MalformedURLException ex) {
                Logger.getLogger(Browser.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });
}
}

Here is my HTML:

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">

<title>Heatmaps</title>
<style>
    html, body {
        height: 100%;
        margin: 0;
        padding: 0;
    }

    #map {
        height: 100%;
    }
</style>
</head>

<body>
<div id="map"></div>
<script>
    var map;
    var points = [];
    var markers = [];

    function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
            zoom: 13,
            center: new google.maps.LatLng(-27.487000, 152.984000),
        });
    }

    function addPoint(id, latitude, longitude) {
        markers[id] = new google.maps.Marker({
            draggable: false,
            animation: google.maps.Animation.DROP,
            position: new google.maps.LatLng(latitude, longitude),
            map: map
        });
        var bounds = new google.maps.LatLngBounds();
        markers.forEach(x => {
            bounds.extend(x.getPosition());
        })
        map.fitBounds(bounds);
    }
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBp0GrBi5GE3OPPgEm7WdStGH7A2tGuaHk&libraries=visualization&callback=initMap">
</script>

I am implementing a program which has a button to load data and display them as markers in Google Maps.

I use the constructor of Brower to pass the URL in

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    Browser browser = new Browser();
    browser.setVisible(true);
    browser.loadURL("C:/Users/User/Desktop/test.html");
}   

and use the function addPoint to add markers but then i got this error:

Exception in thread "JavaFX Application Thread" netscape.javascript.JSException: ReferenceError: Can't find variable: addPoint

Is there any way to call the function addPoint in method loadUrl from my java code and then load the browser?

The short answer is "you have a timing problem". JavaFx WebEngine is misleading you. The problem is that you load the google maps api async. JavaFx loaded the htmlpage, but the maps-object is not not loaded at this moment.

So you have two options. The first is, that java is loading google maps and the marker. The second is, that javascript call java, when the map is loaded.

Example for 1 java call all:

engine.getLoadWorker().stateProperty().addListener(
        new ChangeListener<State>() {
            public void changed(ObservableValue ov, State oldState, State newState) {
                if (newState == State.SUCCEEDED) {
                    //engine.executeScript("addPoint(0,-26.487000,151.984000)");
                    JSObject win = (JSObject) engine.executeScript("window");
                    win.setMember("javaObj", new Bridge(engine));
                    engine.executeScript("javaObj.start()");                                    }
            }
        });
engine.load(url.toString());

new Bridge.java import javafx.scene.web.WebEngine;

public class Bridge {

    private WebEngine engine;

    public Bridge(WebEngine engine) {
        this.engine = engine;
    }

    public void addPoint(String id, String latitude, String longitude) {
        System.out.println("adding value");
        engine.executeScript(""
                + "var id=\"" + id + "\";"
                + "var latitude=\"" + latitude + "\";"
                + "var longitude=\"" + longitude + "\";"
                + "var markers=[];"
                + "markers[id] = new google.maps.Marker({\n"
                + "            draggable: false,\n"
                + "            animation: google.maps.Animation.DROP,\n"
                + "            position: new google.maps.LatLng(latitude, longitude),\n"
                + "            map: map\n"
                + "        });\n"
                + "        var bounds = new google.maps.LatLngBounds();\n"
                + "         var index;\n"
                + "         for (index = 0; index < markers.length; ++index) {\n"
                + "             bounds.extend(markers[index].getPosition());\n"
                + "         } "
                + "        map.fitBounds(bounds);");
    }

    public void doAddPoint() {
        addPoint("0", "-26.487000", "151.984000");
    }

    public void call() {
        engine.executeScript("addPoint(0,-26.487000,151.984000)");
    }

    public void log(String text) {
        System.out.println("log: " + text);
    }

    public void initMap() {
        engine.executeScript(""
                + "var map;"
                //                + "javaObj.log(\"hier0\");"
                + "map = new google.maps.Map(document.getElementById('map'), {\n"
                + "            zoom: 13,\n"
                + "            center: new google.maps.LatLng(-27.487000, 152.984000),\n"
                + "        });\n"
                //                + "javaObj.log(\"hier\");"
                + "javaObj.doAddPoint();"
        );
    }

    public void start() {
        engine.executeScript("var s = document.createElement(\"script\");\n"
                + "                          s.type = \"text/javascript\";\n"
                + "                            s.src = \"https://maps.googleapis.com/maps/api/js?key=AIzaSyBp0GrBi5GE3OPPgEm7WdStGH7A2tGuaHk&libraries=visualization&callback=javaObj.initMap\";\n"
                + "                            $(\"head\").append(s);");

    }
}

Basic Htmlpage:

<!DOCTYPE html>
<html>
<head id="test">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<script
  src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous"></script>
<title>Heatmaps</title>
<style>
    html, body {
        height: 100%;
        margin: 0;
        padding: 0;
    }

    #map {
        height: 100%;
    }
</style>
</head>
<body>
<p><b>test</b></p>
<div id="map"></div>
</body>
</html>

Example for 2: changes to Browser.java

engine.getLoadWorker().stateProperty().addListener(
    new ChangeListener<State>() {
        public void changed(ObservableValue ov, State oldState, State newState) {
            if (newState == State.SUCCEEDED) {
                //engine.executeScript("addPoint(0,-26.487000,151.984000)");
                JSObject win = (JSObject) engine.executeScript("window");
                win.setMember("javaObj", new Bridge(engine));
             }
        }
    });
engine.load(url.toString());

new Bridge.java

public class Bridge {

    private WebEngine engine;

    public Bridge(WebEngine engine) {
        this.engine = engine;
    }
    public void call() {
        //System.out.println("do call");
        engine.executeScript("addPoint(0,-26.487000,151.984000)");
    }
}

changes to html page:

var initMap =function() {
    map = new google.maps.Map(document.getElementById('map'), {
        zoom: 13,
        center: new google.maps.LatLng(-27.487000, 152.984000),
    });
    javaObj.call();
}

PS: JQuery is only to load the google maps script and for debugging. I don't know the google maps api, so I have no idea, why the map zoom in that much, but that is another question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM