2017-03-17 1 views
6

Wie erwähnt here und here gibt es keinen einfachen Weg, die erforderliche Höhe einer Webansicht zu bestimmen, bis "RT-25005 Automatische bevorzugte Dimensionierung von WebView" implementiert ist.Korrekte Größe von in Tabelcell eingebettetem Webview

Gibt es Problemumgehungen für dieses Problem? Ich konnte keine Lösung in SO oder anderswo finden. Da dies jedoch kein ungewöhnliches Problem ist, muss es einen Workaround geben. Irgendeine Idee?

Für Webviews eingebettet in einem stage fand ich die folgende Lösung (siehe here):

webView.getEngine().executeScript(
    "window.getComputedStyle(document.body, null).getPropertyValue('height')" 
); 

oder

Double.parseDouble(webView.getEngine().executeScript("document.height").toString()) 

Allerdings scheint dies nicht für Webviews in einem treecell eingebettet zu arbeiten, wie here. In diesem Fall bekomme ich immer zu große Zahlen.

Minimal Lauf Beispiel (einschließlich Empfehlung von jewelsea):

import java.util.concurrent.TimeUnit; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javafx.application.Application; 
import javafx.application.Application; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.ContentDisplay; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.layout.Region; 
import javafx.scene.paint.Color; 
import javafx.scene.text.Text; 
import javafx.scene.text.TextFlow; 
import javafx.scene.web.WebEngine; 
import javafx.scene.web.WebView; 
import javafx.stage.Stage; 
import javafx.util.Callback; 
import org.w3c.dom.Document; 

public class TableViewSampleHTML extends Application { 

    private final ObservableList<MyData> data = FXCollections.observableArrayList(new MyData(1L), new MyData(3L), new MyData(2L), new MyData(4L), new MyData(1L)); 

    public static void main(final String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(final Stage stage) { 
     final Scene scene = new Scene(new Group()); 

     TableView<MyData> table = new TableView<>(); 
     table.setPrefHeight(700); 

     final TableColumn<MyData, Long> nameCol = new TableColumn("So So"); 
     nameCol.setMinWidth(200); 
     nameCol.setCellValueFactory(new PropertyValueFactory<>("i")); 

     // Allow to display Textflow in Column 
     nameCol.setCellFactory(new Callback<TableColumn<MyData, Long>, TableCell<MyData, Long>>() { 
      @Override 
      public TableCell<MyData, Long> call(TableColumn<MyData, Long> column) { 
       return new TableCell<MyData, Long>() { 
        @Override 
        protected void updateItem(Long item, boolean empty) { 
         super.updateItem(item, empty); 

         if (item == null || empty) { 

          setText(null); 
          setGraphic(null); 
          setStyle(""); 

         } else { 

          WebView webview = new WebView(); 
          webview.setPrefWidth(700.0); 
          WebEngine engine = webview.getEngine(); 

          String textHTML = new String(new char[item.intValue()]).replace("\0", " <b> bold </b> normal, "); 
         // textHTML = "<body>" 
          //   + textHTML + "</body>"; 
          engine.loadContent(textHTML); 


          setGraphic(webview); 



          engine.documentProperty().addListener((obj, prev, newv) -> { 

            String heightText = engine.executeScript(
             "window.getComputedStyle(document.body, null).getPropertyValue('height')" 
            ).toString(); 

            System.out.println("heighttext: " + heightText); 
            webview.setPrefHeight(Double.parseDouble(heightText.replace("px", ""))); 
            this.setPrefHeight(Double.parseDouble(heightText.replace("px", ""))); 
            setGraphic(webview); 

          }); 





         } 
        } 
       }; 
      } 
     }); 

     table.setItems(data); 
     table.getColumns().addAll(nameCol); 

     ((Group) scene.getRoot()).getChildren().addAll(table); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    public static class MyData { 

     private Long i; 

     public MyData(Long i) { 
      this.i = i; 
     } 

     public Long getI() { 
      return i; 
     } 
    } 

} 

Nun ist die outout ist

heighttext: 581px 
heighttext: 581px 

Allerdings sind diese Werte scheinen zu groß zu sein. Siehe screeenshot:

enter image description here

Antwort

2

Es wurden einige Fortschritte gemacht und die Zellenhöhen werden nun realistischer berechnet. Bitte beachten Sie den entsprechenden Code unten.

Relevante changens:

  • Scheint, wie es vorgeschrieben ist webview.setPrefHeight(-1); aufrufen, bevor die jevascript ausführt.
  • Javascript wurde geändert. Keine große Veränderung gesehen, aber vielleicht ist das Ergebnis allgemeiner

Offene Punkte:

  • Aus irgendeinem Grund muss ich noch + 15.0 auf die berechnete Höhe hinzuzufügen. Das ist ein Hack. Es scheint so, als müsste irgendwo eine zusätzliche Länge berücksichtigt werden.
  • Funktionalität bei Neuberechnung nach der Größenänderung der Spalte ist nicht optimal. Die Verwendung von table.refresh() verursacht eine erhebliche Verzögerung beim Rendern.

    public class TableViewSampleHTML extends Application { 
    
    private final ObservableList<MyData> data = FXCollections.observableArrayList(new MyData(1L), new MyData(14L), new MyData(2L), new MyData(3L), new MyData(15L)); 
    
    public static void main(final String[] args) { 
        launch(args); 
    } 
    
    @Override 
    public void start(final Stage stage) { 
        final Scene scene = new Scene(new Group(), 400, 800); 
    
        TableView<MyData> table = new TableView<>(); 
    
        table.setPrefWidth(400); 
        table.setPrefHeight(800); 
    
        final TableColumn<MyData, Long> nameCol = new TableColumn("So So"); 
        final TableColumn<MyData, Long> col2 = new TableColumn("la la"); 
        nameCol.setPrefWidth(200); 
        col2.setCellValueFactory(new PropertyValueFactory<>("i")); 
        nameCol.setCellValueFactory(new PropertyValueFactory<>("i")); 
        nameCol.widthProperty().addListener((ob,oldV,newV) -> {table.refresh();}); 
    
        // Allow to display Textflow in Column 
        nameCol.setCellFactory(new Callback<TableColumn<MyData, Long>, TableCell<MyData, Long>>() { 
    
         @Override 
         public TableCell<MyData, Long> call(TableColumn<MyData, Long> column) { 
    
          return new TableCell<MyData, Long>() { 
    
           @Override 
           protected void updateItem(Long item, boolean empty) { 
            super.updateItem(item, empty); 
    
            if (item == null || empty) { 
    
             setText(null); 
             setGraphic(null); 
             setStyle(""); 
    
            } else { 
             WebView webview = new WebView(); 
             WebEngine engine = webview.getEngine(); 
    
             webview.setPrefHeight(-1); // <- Absolute must at this position (before calling the Javascript) 
             setGraphic(webview); 
    
             String textHTML = new String(new char[item.intValue()]).replace("\0", " <b> bold </b> normal, "); 
             textHTML = "<body>" 
               + textHTML + "</body>"; 
             engine.loadContent(textHTML); 
    
    
             engine.documentProperty().addListener((obj, prev, newv) -> { 
    
             String heightText = engine.executeScript( // <- Some modification, which gives moreless the same result than the original 
               "var body = document.body," 
               + "html = document.documentElement;" 
               + "Math.max(body.scrollHeight , body.offsetHeight, " 
               + "html.clientHeight, html.scrollHeight , html.offsetHeight);" 
             ).toString(); 
    
             System.out.println("heighttext: " + heightText); 
             Double height = Double.parseDouble(heightText.replace("px", "")) + 15.0; // <- Why are this 15.0 required?? 
             webview.setPrefHeight(height); 
             this.setPrefHeight(height); 
             }); 
            } 
    
           } 
          }; 
         } 
        }); 
    
        table.setItems(data); 
        table.getColumns().addAll(nameCol); 
        table.getColumns().addAll(col2); 
    
        ((Group) scene.getRoot()).getChildren().addAll(table); 
    
        stage.setScene(scene); 
        stage.show(); 
    } 
    
    public static class MyData { 
    
        private Long i; 
    
        public MyData(Long i) { 
         this.i = i; 
        } 
    
        public Long getI() { 
         return i; 
        } 
    } 
    } 
    

Ausgabe sieht nun wie:

enter image description here

+0

Vielen Dank für diesen Code. HTML-Body-Tag hat standardmäßig topmargin und leftmargins Sie müssen also topmargin = 0 leftmargin = 0 setzen, um Ränder zu entfernen. () So jetzt keine vertikale Bildlaufleiste müssen Sie hinzufügen Extra 10 hier: Doppelte Höhe = Double.parseDouble (heightText.replace ("px", "")) + 10.0; –

1

Aus dem Beispiel Sie verknüpft (JavaFX webview, get document height) die Höhe des Dokuments in einem ChangeListener auf dem Dokument berechnet wird:

engine.documentProperty().addListener((prop, oldDoc, newDoc) -> { 
    String heightText = engine.executeScript(
      "window.getComputedStyle(document.body, null).getPropertyValue('height')" 
    ).toString(); 

    System.out.println("heighttext: " + heightText); 
}); 

Ausgang:

heighttext: 36px 
heighttext: 581px 
heighttext: 581px 

In dem Code in Ihrer Frage führen Sie die Höhenprüfung nicht basierend auf einem ChangeListener aus. Sie fragen also die Höhe des WebView-Dokuments ab, bevor das Dokument geladen wurde (weshalb es Null für Ihren Code zurückgibt).

+0

Danke dir jewelsea. Das macht es mir ein bisschen klarer. Jetzt sind die Zahlen nicht mehr Null. Jedoch scheinen sie jetzt zu hoch zu sein. Bitte überprüfen Sie meine Bearbeitung. – BerndGit

+0

Sorry BerndGit, ich kenne keine Möglichkeit, eine genauere Anzahl von WebView-Dokumenten zu erhalten. – jewelsea

+0

Kein Problem. Danke für die Rückmeldung. Ich denke, ich werde ein Kopfgeld ausgeben. – BerndGit

0

Antwort des basedOn BerndGirt.

public class WebviewCellFactory<S,T> implements Callback<TableColumn<S,T>, TableCell<S,T>> { 
    @Override 
    public TableCell<S, T> call(TableColumn<S, T> column) { 
     return new TableCell<S, T>() { 
      @Override 
      protected void updateItem(T item, boolean empty) { 
       super.updateItem(item, empty); 
       if (item == null || empty) { 
        setText(null); 
        setGraphic(null); 
        setStyle(""); 
       } else { 
        WebView webview = new WebView(); 
        WebEngine engine = webview.getEngine(); 
        webview.setPrefHeight(-1); // <- Absolute must at this position (before calling the Javascript) 
        webview.setBlendMode(BlendMode.DARKEN); 

        setGraphic(webview); 
        engine.loadContent("<body topmargin=0 leftmargin=0 style=\"background-color: transparent;\">"+item+"</body>"); 
        engine.documentProperty().addListener((obj, prev, newv) -> { 
         String heightText = engine.executeScript( // <- Some modification, which gives moreless the same result than the original 
           "var body = document.body," 
             + "html = document.documentElement;" 
             + "Math.max(body.scrollHeight , body.offsetHeight, " 
             + "html.clientHeight, html.scrollHeight , html.offsetHeight);" 
         ).toString(); 
         Double height = Double.parseDouble(heightText.replace("px", "")) + 10 ; // <- Why are this 15.0 required?? 
         webview.setPrefHeight(height); 
         this.setPrefHeight(height); 
        }); 
       } 
      } 
     }; 
    } 
} 

dann brauchen Sie nur

tableColumn.setCellFactory(new WebviewCellFactory()); 

zu setzen, wenn es irgendwelche Fehler sind mir bitte sagen.

Verwandte Themen