I am fairly new to JavaFX and am not very experienced in threading either. The project I am working on uses a WebView for all UI functions but freezes when processing data/running methods in Java. I have read about Platform.runlater() but I am unsure how to apply it to my particular situation.
Here is the code that I currently have (it is an example but replicates the issue that I am having).
Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(Main.class.getResource("Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
public class Controller implements Initializable {
@FXML
private WebView webView;
private WebEngine webEngine;
private AppInterface appInterface;
private void loadPage(String fileName) {
URL url = this.getClass().getResource(fileName);
webEngine = webView.getEngine();
webEngine.load(url.toExternalForm());
}
@Override
public void initialize(URL location, ResourceBundle resources) {
loadPage("/resources/index.html");
appInterface = new AppInterface(webEngine);
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> observableValue, State oldState, State newState) {
if (newState == State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("javaApp", appInterface);
}
}
});
}
}
AppInterface.java
import javafx.scene.web.WebEngine;
public class AppInterface {
WebEngine webEngine;
public AppInterface(WebEngine inputWebEngine) {
webEngine = inputWebEngine;
}
public void getFibN(int digit) {
System.out.println("Calculating digit " + digit + " of Fibonacci Sequence.");
int value = Fibonacci.getDigit(digit);
System.out.println("Fibonacci Sequence, digit " + digit + ": " + value);
webEngine.executeScript("displayWebView('" + value + "')");
}
}
Fibonacci.java
class Fibonacci {
static int getDigit(int n)
{
if (n <= 1)
return n;
return getDigit(n - 1) + getDigit(n - 2);
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<script>
function getMessage(){
javaApp.getFibN(47);
}
function displayWebView(message){
document.body.append(message);
}
</script>
</head>
<body onload="javascript:setTimeout(getMessage, 1000)">
</body>
</html>
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.web.WebView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller">
<children>
<!-- Given the webView ID to initiate the web page -->
<WebView fx:id="webView" prefWidth="1000.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
I have tried creating a new thread in the Fibonacci class but get an error stating that it is not the JavaFX thread. What am I doing wrong to keep the UI from freezing while the task is running?