Моя цель - разместить html-содержимое в объекте WebView в документе fxml, используя класс контроллера. У моего документа FXML есть другие объекты в нем, как кнопки и изображения, я хочу, чтобы WebView просто был частью графического интерфейса. Я могу разместить контент внутри TextArea в документе FXML, используя класс контроллера. Сделать это для WebView немного сложнее, потому что для этого требуется, чтобы WebEngine согласился с этим. Я знаю, как запустить WebView самостоятельно без документа FXML, но кто-нибудь знает, возможна ли моя цель?
Это моя попытка в классе контроллера, но я получаю исключение целевой задачи:
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();
}
}
Это своего рода аккуратная концепция (по крайней мере, если я понял, о чем вы спрашиваете :-). Мне это нравится. Престижность за это.
Перечитывая свой вопрос, я, возможно, совершенно не понял его... если так, я думаю, вы можете игнорировать мой ответ.
Указание HTML-контента в формате FXML
К сожалению, WebView является окончательным, поэтому вы не можете просто расширить WebView, чтобы добавить методы загрузки контента к элементу, который может быть указан в FXML.
Решение состоит в том, чтобы обеспечить небольшой класс оболочки вокруг WebView, который FXML может создавать и устанавливать в контент. Я решил, что класс оболочки наследует StackPane, так что оболочка является узлом и может быть создана в FXML везде, где вы, возможно, захотите использовать узел.
Возможно, вы сможете использовать класс Builder, а не класс-оболочку, как я, но документация по этому поводу для FXML довольно скудна до несуществующей, поэтому я не пробовал.
Для удобства оберните встроенный контент html в конструкцию CDATA. Тогда вам не нужно избегать всех символов html и оставить <
, >
и другие, а не перекодировать эти символы как <
, >
, и т.д.
embeddedwebview/погруженного 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-документ.
Замените элемент EmbeddedWebView в приведенном выше файле fxml следующим образом:
<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>
Таким образом, функция setUrl задает глобальный переменный url, который возвращает getUrl?
Элемент url является локальным для EmbeddedWebView, а не глобальным - это область приложения, но да, у вас есть общая идея, setURL()
- это сеттер, и FXML ищет его отражением для установки URL-адреса в EmbeddedWebView, и вы можете извлеките url из EmbeddedWebView из любого класса, используя общедоступную функцию getURL()
.