Proper Webview setup built into Tabelcell

As already mentioned here and here, there is no easy way to determine the required height of the web view until the "automatic preferred calibration of the web model" RT-25005 is implemented.

Are there any workarounds for this problem? I could not find a solution in SO or anywhere else. However, since I think this is not a problem, this should be a workaround. Any idea?

For Webviews, built in stage, I found the following solution (see here ):

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

or

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

However, this is not like Webviews built into treecell, for example here . In this case, I always get too large numbers.

Minimum launch example (including recommendations 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;
        }
    }

}

Now outout

heighttext: 581px
heighttext: 581px

However, these values ​​seem too large. See screeenshot:

enter image description here

+6
source share
3 answers

Some progress has been made, and cell heights are now calculated more realistically. Please see the adapted code below.

According changes:

  • It seems like jevascript needs to be called before executing webview.setPrefHeight(-1);.
  • Javascript has been changed. No big changes are visible, but perhaps the result is more general.

Open Points:

  • For some reason, I still need to add + 15.0to the estimated height. This is a hack. It seems like some extra length should be considered somewhere.
  • . table.refresh() .

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

:

enter image description here

+2

, (- JavaFX, ) ChangeListener :

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

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

:

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

ChangeListener. , WebView , ( ).

+1

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

tableColumn.setCellFactory(new WebviewCellFactory());

- , , .

0

Source: https://habr.com/ru/post/1015824/


All Articles