【问题标题】:Correct sizing of Webview embedded in Tabelcell嵌入在 Tabelcell 中的 Webview 的正确大小
【发布时间】:2017-08-08 22:46:50
【问题描述】:

herehere 所述,在实施“RT-25005 自动首选大小的 WebView”之前,没有简单的方法来确定所需的 webview 高度。

这个问题有什么解决方法吗?我在 SO 或其他地方找不到解决方案。但是,由于我认为这不是不常见的问题,因此需要一种解决方法。有什么想法吗?

对于Webviews嵌入stage,我找到了以下解决方案(请参阅here):

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

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

但是,这似乎不适用于嵌入在树单元中的 Webview,例如 here。在这种情况下,我总是得到太大的数字。

最小运行示例(包括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;
        }
    }

}

现在输出是

heighttext: 581px
heighttext: 581px

但是这些值似乎太大了。见截图:

【问题讨论】:

    标签: javafx webview


    【解决方案1】:

    已经取得了一些进展,现在可以更真实地计算单元格高度。请参阅下面的相关改编代码。

    相关改动:

    • 似乎在执行 jevascript 之前必须调用 webview.setPrefHeight(-1);
    • Javascript 已被修改。没有看到大的变化,但结果可能更普遍

    开点:

    • 出于某种原因,我仍然必须将+ 15.0 添加到计算高度。这是一个黑客。似乎必须在某个地方考虑​​一些额外的长度。
    • 调整列大小后重新计算的功能不是最佳的。使用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;
          }
      }
      }
      

    现在的输出如下:

    【讨论】:

    • 感谢您提供此代码。 HTML body 标签默认有 topmargin 和 leftmargins 所以你需要设置 topmargin=0 leftmargin=0 来去掉边距。() 所以现在没有垂直滚动条你需要添加额外的 10此处:双倍高度 = Double.parseDouble(heightText.replace("px", "")) + 10.0;
    • 我发现计算出的高度在我的 Mac 上具有1.0054 的漂移系数。将在其他机器上进行测试,但想分享但只需应用此乘数即可完美调整大小。
    【解决方案2】:

    根据您链接的示例 (JavaFX webview, get document height),文档的高度是在文档上的 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 文档的高度(这就是它为您的代码返回零的原因)。

    【讨论】:

    • 谢谢珠宝海。这让我更清楚一点。现在数字不再是零了。然而,现在它们似乎太高了。请检查我的编辑。
    • 抱歉 BerndGit,我不知道如何获得更准确的 WebView 文档大小计数。
    • 没问题。感谢您的反馈。我想我会发放赏金。
    【解决方案3】:

    基于 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());
    

    如果有任何错误请告诉我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-18
      • 2013-08-25
      • 2013-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多