我有一个运行Java FX webengine的Java应用程序(所有这一切的最终目标是动态绘制D3.js图)。我希望能够在它已经运行时添加新的javascript文件,然后在javascript告诉它时理想地再次卸载它们。
这样可以使用户可以使用某些功能(绘制某些功能),而无需立即加载所有代码。它还可以帮助我避免在我的javascript中使用脆弱的if / then语句森林的未来头痛。
问题1:是否可以从正在运行的Web引擎中“卸载”文件?至少,没有重绘整个事情是可能的。我很确定使用我的新文件路径调用loadContent()会使它们以我想要的方式可用,但我没有谈到如何从HTML块中删除现有源代码。
问题2:有关如何优雅地将额外资源投入webView的任何建议?我现在的思维过程仍然停留在蛮力上,但我甚至没有能够通过一种有效的解决方案,所以也许我正在咆哮错误的树。
问题3:这是一个好主意吗?可以仅在Javascript中执行此操作,但我希望选项的外观和消失直接与java端功能相关联,后者将从类Bridge执行,我正在尝试从中加载新内容现在。
我问了很多问题,但感谢任何帮助!
现在我正在设置webengine的内容:
final ResourceExtractor RESOURCE_EXTRACTOR
= new ResourceExtractor(JavaScriptPlot.class);
// prepare the local URI for d3.js
final URI D3_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("d3.min.js")
.toUri();
// prepare the local URI for numeric.js
final URI NUMERIC_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("numeric.min.js")
.toUri();
// prepare the local URI for topsoil.js
final URI TOPSOIL_JS_URI = RESOURCE_EXTRACTOR
.extractResourceAsPath("topsoil.js")
.toUri();
// build the HTML template (comments show implicit elements/tags)
HTML_TEMPLATE = (""
+ "<!DOCTYPE html>\n"
// <html>
// <head>
+ "<style>\n"
+ "body {\n"
+ " margin: 0; padding: 0;\n"
+ "}\n"
+ "</style>\n"
// </head>
+ "<body>"
+ "<script src=\"" + D3_JS_URI + "\"></script>\n"
+ "<script src=\"" + NUMERIC_JS_URI + "\"></script>\n"
+ "<script src=\"" + TOPSOIL_JS_URI + "\"></script>\n"
+ "<script src=\"%s\"></script>\n" // JS file for plot
// </body>
// </html>
+ "").replaceAll("%20", "%%20");
此处创建了替换%s的源路径:
public class BasePlot extends JavaScriptPlot {
private static final ResourceExtractor RESOURCE_EXTRACTOR
= new ResourceExtractor(BasePlot.class);
private static final String RESOURCE_NAME = "BasePlot.js";
public BasePlot() {
super(
RESOURCE_EXTRACTOR.extractResourceAsPath(RESOURCE_NAME),
new BasePlotDefaultProperties());
}
}
然后我将已经提取的文件路径作为资源sourcePath,并将其插入到HTML块中:
String buildContent() {
return String.format(HTML_TEMPLATE, sourcePath.toUri());
}
然后我使用buildContent()
的返回值构建我的Web视图private void initializeWebView() {
runOnFxApplicationThread(() -> {
// initialize webView and associated variables
webView = new WebView();
webView.setContextMenuEnabled(false);
WebEngine webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener(
(observable, oldValue, newValue) -> {
if (newValue == SUCCEEDED) {
if (new IsBlankImage().test(screenCapture())) {
webEngine.loadContent(buildContent());
}
topsoil = (JSObject) webEngine.executeScript("topsoil");
topsoil.setMember("bridge", new Bridge());
}
});
// asynchronous
webEngine.loadContent(buildContent());
});
}
Javascript可以触发下面类中的方法来触发更改。现在它正在手动创建一个硬编码资源,但是一旦我弄错了,我会让这部分更加优雅/逻辑有序。
//loads appropriate JS files into webview based on BasePlot's isotope type
public class Bridge {
final URI ISOTOPE_URI = ISOTOPE_RESOURCE_EXTRACTOR
.extractResourceAsPath("Concordia.js")
.toUri();
String finalHtml = buildContent().concat("<script src=\""+ISOTOPE_URI.toString()+"\"></script>\n");
webView.getEngine().loadContent(finalHtml);
}
}
上面的loadContent()给我一个应用程序线程错误:“ReferenceError:找不到变量:topsoil”