正如前面提到的here和here,在实施“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())
然而,这似乎不适用于嵌入在树状单元中的Web视图,例如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
然而,这些价值似乎太大了。见screeenshot:
答案 0 :(得分:3)
已经取得了一些进展,现在可以更真实地计算细胞高度。请参阅以下相关的改编代码。
相关变更:
webview.setPrefHeight(-1);
。开放点:
+ 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;
}
}
}
输出现在看起来像:
答案 1 :(得分:1)
从您链接的示例(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文档的高度(这就是为什么它为您的代码返回零)。
答案 2 :(得分: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());
如果有任何错误请告诉我。