Я загружаю веб-сайт в JavaFX WebView и через некоторое время снимаю скриншот с чем-то вроде:
WritableImage image = webView.snapshot(null, null);
Если я смотрю на этот WebView, который отлично работает, но если он скрыт, находясь на вкладке, которая не находится на переднем плане (я не уверен в других случаях ее скрытия), тогда снимок экрана соответствующий сайт, но полностью пустой.
Как заставить WebView отображать, даже если он не отображается?
За это время webView.isVisible()
истинно.
Я нашел там метод в WebView
, называемый isTreeReallyVisible()
, и в настоящее время он содержит:
private boolean isTreeReallyVisible() {
if (getScene() == null) {
return false;
}
final Window window = getScene().getWindow();
if (window == null) {
return false;
}
boolean iconified = (window instanceof Stage) ? ((Stage)window).isIconified() : false;
return impl_isTreeVisible()
&& window.isShowing()
&& window.getWidth() > 0
&& window.getHeight() > 0
&& !iconified;
}
Когда WebView скрыт, находясь на вкладке без переднего плана, impl_isTreeVisible()
является ложным (все остальные факторы в операторе return являются истинными). Этот метод находится на Node
и выглядит так:
/**
* @treatAsPrivate implementation detail
* @deprecated This is an internal API that is not intended for use and will be removed in the next version
*/
@Deprecated
public final boolean impl_isTreeVisible() {
return impl_treeVisibleProperty().get();
}
/**
* @treatAsPrivate implementation detail
* @deprecated This is an internal API that is not intended for use and will be removed in the next version
*/
@Deprecated
protected final BooleanExpression impl_treeVisibleProperty() {
if (treeVisibleRO == null) {
treeVisibleRO = new TreeVisiblePropertyReadOnly();
}
return treeVisibleRO;
}
Я мог бы переопределить impl_treeVisibleProperty()
, чтобы предоставить свою собственную реализацию, но WebView
является окончательным, поэтому я не могу наследовать его.
Другая совершенно другая ситуация, сводящаяся к минимуму (обозначенная) или на скрытой вкладке, должна полностью скрыть сцену (например, в панели лотка). Когда в этом режиме, даже если я могу получить рендеринг, WebView
не изменяет размер. Я вызываю webView.resize()
, а затем снимаю снимок экрана, и скриншот имеет соответствующий размер, но фактическая отображаемая страница имеет размер, который ранее был WebView
.
Отладка этого поведения размера в показанных и скрытых этапах, я обнаружил, что в итоге мы перейдем к Node.addToSceneDirtyList()
, который содержит:
private void addToSceneDirtyList() {
Scene s = getScene();
if (s != null) {
s.addToDirtyList(this);
if (getSubScene() != null) {
getSubScene().setDirty(this);
}
}
}
В скрытом режиме getScene()
возвращает null
, в отличие от того, что происходит, когда оно отображается. Это означает, что s.addToDirtyList(this)
никогда не вызывается. Я не уверен, является ли это причиной того, что он не получает должным образом измененный размер.
Здесь есть ошибка, очень старая: https://bugs.openjdk.java.net/browse/JDK-8087569, но я не думаю, что вся проблема.
Я делаю это с Java 1.8.0_151. Я попробовал 9.0.1 посмотреть, будет ли он вести себя по-другому, поскольку я понимаю, что WebKit был обновлен, но нет, это то же самое.