gpt4 book ai didi

java - 即使在另一个选项卡中不可见时,如何使 JavaFX 的 webview 呈现?

转载 作者:搜寻专家 更新时间:2023-10-30 21:12:34 25 4
gpt4 key购买 nike

我正在 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()为假(返回语句中的所有其他因素都为真)。该方法在 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 已升级,但没有,它是一样的。

最佳答案

在这里重现 Pablo 的问题:https://github.com/johanwitters/stackoverflow-javafx-webview .

Pablo 建议重写 WebView 并调整一些方法。这是行不通的,因为它是最后一个类和私有(private)成员。作为替代方案,我使用 javassist 重命名方法并将代码替换为我希望它执行的代码。我已经“替换”了方法 handleStagePulse 的内容,如下所示。

public class WebViewChanges {
// public static String MY_WEBVIEW_CLASSNAME = WebView.class.getName();

public WebView newWebView() {
createSubclass();
return new WebView();
}

// https://www.ibm.com/developerworks/library/j-dyn0916/index.html
boolean created = false;
private void createSubclass() {
if (created) return;
created = true;
try
{
String methodName = "handleStagePulse";

// get the super class
CtClass webViewClass = ClassPool.getDefault().get("javafx.scene.web.WebView");

// get the method you want to override
CtMethod handleStagePulseMethod = webViewClass.getDeclaredMethod(methodName);

// Rename the previous handleStagePulse method
String newName = methodName+"Old";
handleStagePulseMethod.setName(newName);

// mnew.setBody(body.toString());
CtMethod newMethod = CtNewMethod.copy(handleStagePulseMethod, methodName, webViewClass, null);
String body = "{" +
" " + Scene.class.getName() + ".impl_setAllowPGAccess(true);\n" +
" " + "final " + NGWebView.class.getName() + " peer = impl_getPeer();\n" +
" " + "peer.update(); // creates new render queues\n" +
// " " + "if (page.isRepaintPending()) {\n" +
" " + " impl_markDirty(" + DirtyBits.class.getName() + ".WEBVIEW_VIEW);\n" +
// " " + "}\n" +
" " + Scene.class.getName() + ".impl_setAllowPGAccess(false);\n" +
"}\n";
System.out.println(body);
newMethod.setBody(body);
webViewClass.addMethod(newMethod);


CtMethod isTreeReallyVisibleMethod = webViewClass.getDeclaredMethod("isTreeReallyVisible");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

此代码段是从打开 2 个选项卡的 WebViewSample 调用的。一个带有“快照”按钮,另一个带有 WebView。正如 Pablo 指出的那样,带有 WebView 的选项卡需要是第二个选项卡才能重现。

package com.johanw.stackoverflow;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

import javax.imageio.ImageIO;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;


public class WebViewSample extends Application {
private Scene scene;
private TheBrowser theBrowser;

private void setLabel(Label label) {
label.setText("" + theBrowser.browser.isVisible());
}

@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);

TabPane tabPane = new TabPane();

BorderPane borderPane = new BorderPane();

theBrowser = new TheBrowser();
{
Tab tab = new Tab();
tab.setText("Other tab");

HBox hbox0 = new HBox();
{
Button button = new Button("Screenshot");
button.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
WritableImage image = theBrowser.getBrowser().snapshot(null, null);
File file = new File("test.png");
RenderedImage renderedImage = SwingFXUtils.fromFXImage(image, null);
try {
ImageIO.write(
renderedImage,
"png",
file);
} catch (IOException e1) {
e1.printStackTrace();
}

}
});
hbox0.getChildren().add(button);
hbox0.setAlignment(Pos.CENTER);
}

HBox hbox1 = new HBox();
Label visibleLabel = new Label("");
{
hbox1.getChildren().add(new Label("webView.isVisible() = "));
hbox1.getChildren().add(visibleLabel);
hbox1.setAlignment(Pos.CENTER);
setLabel(visibleLabel);
}
HBox hbox2 = new HBox();
{
Button button = new Button("Refresh");
button.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
setLabel(visibleLabel);
}
});
hbox2.getChildren().add(button);
hbox2.setAlignment(Pos.CENTER);
}
VBox vbox = new VBox();
vbox.getChildren().addAll(hbox0);
vbox.getChildren().addAll(hbox1);
vbox.getChildren().addAll(hbox2);
tab.setContent(vbox);
tabPane.getTabs().add(tab);
}
{
Tab tab = new Tab();
tab.setText("Browser tab");
HBox hbox = new HBox();
hbox.getChildren().add(theBrowser);
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}

// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());

borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}

public static void main(String[] args){
launch(args);
}
}

class TheBrowser extends Region {

final WebView browser;
final WebEngine webEngine;

public TheBrowser() {
browser = new WebViewChanges().newWebView();
webEngine = browser.getEngine();
getStyleClass().add("browser");
webEngine.load("http://www.google.com");
getChildren().add(browser);

}
private Node createSpacer() {
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
return spacer;
}

@Override protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser,0,0,w,h,0, HPos.CENTER, VPos.CENTER);
}

@Override protected double computePrefWidth(double height) {
return 750;
}

@Override protected double computePrefHeight(double width) {
return 500;
}

public WebView getBrowser() {
return browser;
}

public WebEngine getWebEngine() {
return webEngine;
}
}

我没有成功解决 Pablo 的问题,但希望使用 javassist 的建议可能有所帮助。

我确定:待续...

关于java - 即使在另一个选项卡中不可见时,如何使 JavaFX 的 webview 呈现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47914516/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com