JavaFX 编辑 FXML 文档中的 WebView
JavaFX edit WebView in FXML document
我的目标是能够使用控制器 class 将 html 内容放入 fxml 文档中的 WebView 对象中。我的 FXML 文档中有其他对象,如按钮和图像,我希望 WebView 只是 GUI 的一部分。我可以使用控制器 class 将内容放入 FXML 文档的 TextArea 中。为 WebView 做这个有点棘手,因为它需要一个 WebEngine 来配合它。我知道如何在没有 FXML 文档的情况下自行启动 WebView,但有人知道我的目标是否可以实现吗?
这是我在控制器中的尝试 class,但我得到一个调用目标异常:
public class FXMLDocumentController implements Initializable {
@FXML
private Label label;
WebEngine engine;
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
//access WebView in FXML document
@FXML WebView mywebview; //mywebview is the fxid
public void displayWeb() {
engine = mywebview.getEngine();
final String hellohtml = "chang.htm"; //HTML file to view in web view
URL urlHello = getClass().getResource(hellohtml);
engine.load(urlHello.toExternalForm());
}
@Override
public void initialize(URL url, ResourceBundle rb) {
displayWeb();
}
}
这是一个巧妙的概念(至少如果我明白你在问什么的话:-)。我喜欢这个。感谢您想到它。
在重新阅读你的问题时,我可能完全误解了它......如果是这样,我想你可以无视我的回答。
在 FXML 中指定 HTML 内联内容
不幸的是,WebView 是最终的,因此您不能只扩展 WebView 以将内容加载方法添加到可以在 FXML 中指定的元素。
解决方案是围绕 WebView 提供一个小型包装器 class,FXML 可以将其实例化并设置内容。我选择让包装器 class 继承 StackPane,这样包装器就是一个节点,并且可以在任何您可能想使用节点的地方用 FXML 实例化。
您也许可以像我一样使用构建器 class 而不是包装器 class,但是关于为 FXML 执行此操作的文档非常稀少甚至不存在,所以我没有尝试它。
为方便起见,将嵌入的 html 内容包装在 CDATA construct 中。然后你不必转义所有 html 字符,可以保留 <
、>
和其他字符,而不是将这些字符重新编码为 <
、>
,等等
embeddedwebview/embedded-webview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<?import embeddedwebview.EmbeddedWebView?>
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
prefHeight="150.0" prefWidth="220.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<EmbeddedWebView fx:id="embeddedWebView">
<content>
<![CDATA[
<h3>Embedded WebView</h3>
<p>HTML content inline in FXML</p>
]]>
</content>
</EmbeddedWebView>
</VBox>
embeddedwebview/EmbeddedWebViewApp.java
package embeddedwebview;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class EmbeddedWebViewApp extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"embedded-webview.fxml"
)
);
Pane pane = loader.load();
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
embeddedwebview/EmbeddedWebView.java
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebView;
/**
* A WebView which has getters and setters for content or a document url.
*
* Usage in FXML element is:
*
* EITHER by specifying a url to a html document:
*
* <EmbeddedWebView fx:id="embeddedWebView" url="/embeddedwebview/embedded.html">
*
* OR by specifying CDATA escaped html content:
*
* <EmbeddedWebView fx:id="embeddedWebView">
* <content>
* <![CDATA[
* <h3>Embedded WebView</h3>
* <p>HTML content inline in FXML</p>
* ]]>
* </content>
* </EmbeddedWebView>
*
*/
public class EmbeddedWebView extends StackPane {
final private WebView webView;
// For space efficiency, an alternate implementation could just
// rely on the content in the WebView itself rather than
// duplicating the content here, but it was simple to implement with a duplicate.
private String content;
private String url;
public EmbeddedWebView() {
webView = new WebView();
getChildren().add(webView);
}
public String getContent() {
return content;
}
/**
* Loads html content directly into the webview.
* @param content a html content string to load into the webview.
*/
public void setContent(String content) {
this.content = content;
webView.getEngine().loadContent(content);
}
public String getUrl() {
return url;
}
/**
* Loads content into the WebView from a given url.
* The allowed url types are http, https and file.
*
* Additionally, content can be loaded from a classpath resource.
* To be loaded from the classpath, the url must start with a / character
* and specify the full resource path to the html
* (i.e., relative resource path specifiers are not allowed).
*
* @param url the location of the html document to be loaded.
*/
public void setUrl(String url) {
if ( url == null || ! (url.startsWith("/") || url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:"))) {
throw new IllegalArgumentException("url must start with one of http: file: https: or /");
}
this.url = url;
if (url.startsWith("/")) {
webView.getEngine().load(
EmbeddedWebView.class.getResource(url).toExternalForm()
);
} else {
webView.getEngine().load(
url
);
}
}
}
引用 html 文档的替代用法。
将上面的 fxml 中的 EmbeddedWebView 元素替换为以下内容:
<EmbeddedWebView fx:id="embeddedWebView" url="/embeddedwebview/embedded.html"/>
embeddedwebview/embedded.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<h3>Embedded WebView</h3>
<p>HTML content inline in FXML</p>
</body>
</html>
So does the setUrl function set the global variabe url which getUrl returns?
url 成员是 EmbeddedWebView 的本地成员,而不是应用程序范围内的全局成员,但是,是的,您有一般的想法,setURL()
是一个 setter 并且 FXML 看起来它通过反射在 EmbeddedWebView 中设置 url,您可以稍后使用 public getURL()
函数从任何 class 中检索 EmbeddedWebView 中的 url .
我的目标是能够使用控制器 class 将 html 内容放入 fxml 文档中的 WebView 对象中。我的 FXML 文档中有其他对象,如按钮和图像,我希望 WebView 只是 GUI 的一部分。我可以使用控制器 class 将内容放入 FXML 文档的 TextArea 中。为 WebView 做这个有点棘手,因为它需要一个 WebEngine 来配合它。我知道如何在没有 FXML 文档的情况下自行启动 WebView,但有人知道我的目标是否可以实现吗?
这是我在控制器中的尝试 class,但我得到一个调用目标异常:
public class FXMLDocumentController implements Initializable {
@FXML
private Label label;
WebEngine engine;
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
//access WebView in FXML document
@FXML WebView mywebview; //mywebview is the fxid
public void displayWeb() {
engine = mywebview.getEngine();
final String hellohtml = "chang.htm"; //HTML file to view in web view
URL urlHello = getClass().getResource(hellohtml);
engine.load(urlHello.toExternalForm());
}
@Override
public void initialize(URL url, ResourceBundle rb) {
displayWeb();
}
}
这是一个巧妙的概念(至少如果我明白你在问什么的话:-)。我喜欢这个。感谢您想到它。
在重新阅读你的问题时,我可能完全误解了它......如果是这样,我想你可以无视我的回答。
在 FXML 中指定 HTML 内联内容
不幸的是,WebView 是最终的,因此您不能只扩展 WebView 以将内容加载方法添加到可以在 FXML 中指定的元素。
解决方案是围绕 WebView 提供一个小型包装器 class,FXML 可以将其实例化并设置内容。我选择让包装器 class 继承 StackPane,这样包装器就是一个节点,并且可以在任何您可能想使用节点的地方用 FXML 实例化。
您也许可以像我一样使用构建器 class 而不是包装器 class,但是关于为 FXML 执行此操作的文档非常稀少甚至不存在,所以我没有尝试它。
为方便起见,将嵌入的 html 内容包装在 CDATA construct 中。然后你不必转义所有 html 字符,可以保留 <
、>
和其他字符,而不是将这些字符重新编码为 <
、>
,等等
embeddedwebview/embedded-webview.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.VBox?>
<?import embeddedwebview.EmbeddedWebView?>
<VBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
prefHeight="150.0" prefWidth="220.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<EmbeddedWebView fx:id="embeddedWebView">
<content>
<![CDATA[
<h3>Embedded WebView</h3>
<p>HTML content inline in FXML</p>
]]>
</content>
</EmbeddedWebView>
</VBox>
embeddedwebview/EmbeddedWebViewApp.java
package embeddedwebview;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class EmbeddedWebViewApp extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"embedded-webview.fxml"
)
);
Pane pane = loader.load();
stage.setScene(new Scene(pane));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
embeddedwebview/EmbeddedWebView.java
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebView;
/**
* A WebView which has getters and setters for content or a document url.
*
* Usage in FXML element is:
*
* EITHER by specifying a url to a html document:
*
* <EmbeddedWebView fx:id="embeddedWebView" url="/embeddedwebview/embedded.html">
*
* OR by specifying CDATA escaped html content:
*
* <EmbeddedWebView fx:id="embeddedWebView">
* <content>
* <![CDATA[
* <h3>Embedded WebView</h3>
* <p>HTML content inline in FXML</p>
* ]]>
* </content>
* </EmbeddedWebView>
*
*/
public class EmbeddedWebView extends StackPane {
final private WebView webView;
// For space efficiency, an alternate implementation could just
// rely on the content in the WebView itself rather than
// duplicating the content here, but it was simple to implement with a duplicate.
private String content;
private String url;
public EmbeddedWebView() {
webView = new WebView();
getChildren().add(webView);
}
public String getContent() {
return content;
}
/**
* Loads html content directly into the webview.
* @param content a html content string to load into the webview.
*/
public void setContent(String content) {
this.content = content;
webView.getEngine().loadContent(content);
}
public String getUrl() {
return url;
}
/**
* Loads content into the WebView from a given url.
* The allowed url types are http, https and file.
*
* Additionally, content can be loaded from a classpath resource.
* To be loaded from the classpath, the url must start with a / character
* and specify the full resource path to the html
* (i.e., relative resource path specifiers are not allowed).
*
* @param url the location of the html document to be loaded.
*/
public void setUrl(String url) {
if ( url == null || ! (url.startsWith("/") || url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:"))) {
throw new IllegalArgumentException("url must start with one of http: file: https: or /");
}
this.url = url;
if (url.startsWith("/")) {
webView.getEngine().load(
EmbeddedWebView.class.getResource(url).toExternalForm()
);
} else {
webView.getEngine().load(
url
);
}
}
}
引用 html 文档的替代用法。
将上面的 fxml 中的 EmbeddedWebView 元素替换为以下内容:
<EmbeddedWebView fx:id="embeddedWebView" url="/embeddedwebview/embedded.html"/>
embeddedwebview/embedded.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<h3>Embedded WebView</h3>
<p>HTML content inline in FXML</p>
</body>
</html>
So does the setUrl function set the global variabe url which getUrl returns?
url 成员是 EmbeddedWebView 的本地成员,而不是应用程序范围内的全局成员,但是,是的,您有一般的想法,setURL()
是一个 setter 并且 FXML 看起来它通过反射在 EmbeddedWebView 中设置 url,您可以稍后使用 public getURL()
函数从任何 class 中检索 EmbeddedWebView 中的 url .