2015-03-30 76 views
1

我的目标是能够使用控制器类将html内容放入fxml文档中的WebView对象。我的FXML文档中包含其他对象,如按钮和图像,我希望WebView只是GUI的一部分。我可以使用控制器类将内容放入FXML文档中的TextArea内。为WebView执行此操作有点棘手,因为它需要WebEngine才能完成。我知道如何在没有FXML文件的情况下自行启动WebView,但是有谁知道我的目标是否可以实现?JavaFX在FXML文档中编辑WebView

这是我在控制类的尝试,但我得到一个调用目标异常:

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(); 
    }  

} 
+0

请从异常中发布堆栈跟踪,并确定发生异常的行。 – 2015-03-30 18:40:27

回答

1

这是一种整洁的概念(至少如果我明白你问:-)。我喜欢这个。赞叹它的想法。

在重新阅读你的问题时,我可能完全误解了它......如果是这样,我想你可以不理我的答案。

在FXML

指定的HTML内容内嵌不幸的是,WebView中是最后,所以你不能只是延长的WebView内容加载方法添加到可以在FXML指定的元素。

解决方案是提供一个围绕WebView的小包装类,FXML可以实例化和设置内容。我选择让包装类继承StackPane,以便包装器是一个Node,并且可以在FXML中实例化,无论您想要使用节点。

您或许可以像我一样使用Builder类而不是包装类,但是为FXML做文档的文档非常少见,因此我没有尝试它。

为了方便起见,将嵌入的html内容包装在CDATA construct中。然后,你就不必逃避所有的HTML字符,可以离开<>,和他人是不是重新编码的字符作为&lt;&gt;

Embedded WebView

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文档。

改为如下在上述FXML的EmbeddedWebView元件:

<EmbeddedWebView fx:id="embeddedWebView" url="/embeddedwebview/embedded.html"/> 

embeddedwebview /包埋。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功能设置全局variabe URL其中的getURL回报?

的URL成员是本地EmbeddedWebView,而不是全球的范围的应用,但是,是的,你的总体思路,setURL()是一个setter和FXML查找它通过反射设置URL中EmbeddedWebView你可以使用公共getURL()函数从任何类的EmbeddedWebView中检索URL。

+0

哇@jewelsea这是一个很棒的实现,正是我所期待的。谢谢你超越!那么setUrl函数是否会设置getUrl返回的全局变量url?这非常有创意。 – Maxwell 2015-04-08 04:51:10

+0

更新回答解决其他问题。 – jewelsea 2015-04-08 18:37:04