webengine example javafx webview

javafx - example - Corrección del tamaño de Webview incrustado en Tabelcell



webengine javafx (2)

Del ejemplo que vinculó (vista web de JavaFX, obtener altura del documento ) el alto del documento se calcula en un ChangeListener en el documento:

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

Salida:

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

En el código de su pregunta, no está ejecutando el control de altura basado en un ChangeListener. Por lo tanto, está consultando la altura del documento WebView antes de que se haya cargado el documento (razón por la cual devuelve cero para su código).

Como se menciona aquí y aquí, no hay una manera fácil de determinar la altura requerida de una vista web, hasta que se implemente "RT-25005 Tamaño automático preferido de WebView".

¿Hay alguna solución para este problema? No pude encontrar una solución en SO o en otro lugar. Sin embargo, como creo que este no es un problema poco común, debe haber una solución. ¿Alguna idea?

Para las Webviews en una stage , encontré la siguiente solución (ver aquí ):

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

o

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

Sin embargo, esto no parece funcionar para las vistas web integradas en una celda de árbol, como aquí . En este caso, siempre obtengo números demasiado grandes como resultado.

Ejemplo de ejecución mínima (incluida la recomendación de 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; } } }

Ahora el resultado es

heighttext: 581px heighttext: 581px

Sin embargo, estos valores parecen ser demasiado grandes. Ver screeenshot:


Se han realizado algunos progresos y las alturas de celda ahora se calculan de forma más realista. Por favor, vea el relevante el código adaptado a continuación.

Cambios relevantes:

  • Parece que es obligatorio llamar a webview.setPrefHeight(-1); antes de ejecutar el jevascript.
  • Javascript ha sido modificado No se han visto grandes cambios, pero tal vez el resultado sea más general

Puntos abiertos:

  • Por alguna razón, todavía tengo que agregar + 15.0 a la altura calculada. Esto es un truco. Parece que se debe considerar algo de longitud adicional en alguna parte.
  • La funcionalidad en el recálculo después del cambio de tamaño de la columna no es óptima. El uso de table.refresh() causa un retraso significativo en la representación.

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

La salida ahora se ve así: