2015-03-30 109 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