Правильный размер Webview, встроенного в Tabelcell

Как уже упоминалось, здесь и здесь нет простого способа определить требуемая высота веб-просмотра, пока не будет внедрен «RT-25005 Автоматический предпочтительный размер WebView».

Есть ли обходные пути к этой проблеме? Я не мог найти решение в SO или в другом месте. Однако, поскольку я считаю, что это не редкая проблема, необходимо найти обходной путь. Есть идеи?

Для Webviews, вставленного в stage Я нашел следующее решение (см. здесь ):

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

или

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

Однако, похоже, что это не работает для веб-представлений, встроенных в древовидную ячейку, например . В этом случае я всегда получаю слишком большие числа в результате.

Пример минимального выполнения (включая рекомендацию 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

Однако эти значения кажутся слишком большими. Смотрите скриншот:

 введите описание изображения здесь

7 голосов | спросил BerndGit 17 MarpmFri, 17 Mar 2017 14:34:01 +03002017-03-17T14:34:01+03:0002 2017, 14:34:01

3 ответа


0

Был достигнут некоторый прогресс, и теперь высота ячеек рассчитывается более реалистично. Пожалуйста, смотрите соответствующий адаптированный код ниже.

Соответствующие изменения:

  • Похоже, что обязательно вызывать webview.setPrefHeight(-1); перед выполнением JavaScript.
  • 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;
        }
    }
    }
    

Вывод теперь выглядит следующим образом:

 введите описание изображения здесь

ответил BerndGit 21 MarpmTue, 21 Mar 2017 12:16:58 +03002017-03-21T12:16:58+03:0012 2017, 12:16:58
0

Из примера, который вы указали ( веб-просмотр 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 до загрузки документа (вот почему он возвращает ноль для вашего кода).

ответил jewelsea 18 MaramSat, 18 Mar 2017 01:16:18 +03002017-03-18T01:16:18+03:0001 2017, 01:16:18
0

Основано на ответе 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());

если есть ошибки, пожалуйста, сообщите мне.

ответил Nadir Novruzov 16 FebruaryEurope/MoscowbFri, 16 Feb 2018 11:32:04 +0300000000amFri, 16 Feb 2018 11:32:04 +030018 2018, 11:32:04

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132