如何使 WebView 的背景透明?

问题描述

我在 IntelliJ IDEA 中有一个 Maven 项目,使用 JDK 15 和 JavaFX 15。

我试过了:

  1. 为 WebEngine 设置样式
  2. 为 WebView 设置混合模式
  3. 尝试过的网页

没有成功。如何使 WebView 的背景透明?

我的模块信息.java:

module project {
    requires javafx.controls;
    requires javafx.web;
    requires javafx.graphics;
    requires uk.co.caprica.vlcj;
    requires uk.co.caprica.vlcj.javafx;

    exports project;
}

我的 pom.xml 依赖项:

<dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>15</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>15</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-graphics</artifactId>
            <version>15</version>
        </dependency>
        <dependency>
            <groupId>uk.co.caprica</groupId>
            <artifactId>vlcj</artifactId>
            <version>4.7.0</version>
        </dependency>
        <dependency>
            <groupId>uk.co.caprica</groupId>
            <artifactId>vlcj-javafx</artifactId>
            <version>1.0.2</version>
        </dependency>
</dependencies>

我创建了一个新项目并尝试实现答案中的示例。发生了。不幸的是,单击按钮后背景颜色不会变得透明。你知道为什么这个例子不起作用吗?

Main.java:

import javafx.application.Application;
import javafx.stage.Stage;

import com.sun.webkit.dom.HTMLDocumentImpl;
import java.lang.reflect.Field;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.web.WebView;

public class Main extends Application {

    @Override
    public void start(final Stage stage) {
        initStage(stage);
    }

    private void initStage(Stage stage){
        WebView wv = new WebView();
        wv.setStyle("-fx-background-color: transparent;");

        wv.getEngine().load("https://w3schools.com");
        VBox vb = new VBox(wv);
        vb.setBackground(new Background(new BackgroundFill(Color.ORANGERED,CornerRadii.EMPTY,Insets.EMPTY)));

        Button b = new Button("remove page background");

        b.setonAction((event) -> {
            HTMLDocumentImpl cast = (HTMLDocumentImpl) wv.getEngine().getDocument();

            try {
                Field f = wv.getEngine().getClass().getDeclaredField("page");
                f.setAccessible(true);
                com.sun.webkit.WebPage page = (com.sun.webkit.WebPage) f.get(wv.getEngine());
                page.setBackgroundColor((new java.awt.Color(1,1,1)).getRGB());
                f.setAccessible(false);
            } catch (Exception e) {
            }

        });
        vb.getChildren().add(b);

        stage.setScene(new Scene(vb));
        stage.show();
    }

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

虚拟机选项:

--module-path ${PATH_TO_FX} --add-modules javafx.controls,javafx.web --add-exports javafx.web/com.sun.webkit.dom=ALL-UNNAMED

enter image description here

解决方法

WebView 在网页中呈现 DOM CSS。如果你想要一个透明的背景,你还必须修改那里的 CSS。

编辑......以下有效,但打开了一罐蠕虫。

enter image description here

    @Override
    public void start(Stage primaryStage) throws Exception {
    WebView wv = new WebView();
    wv.setStyle("-fx-background-color: transparent;");

    wv.getEngine().load("https://w3schools.com");
    VBox vb = new VBox(wv);
    vb.setBackground(new Background(new BackgroundFill(Color.ORANGERED,CornerRadii.EMPTY,Insets.EMPTY)));

    Button b = new Button("remove page background");

    b.setOnAction((event) -> {
        HTMLDocumentImpl cast = HTMLDocumentImpl.class.cast(wv.getEngine().getDocument());
        Node item = cast.getElementsByTagName("html").item(0);

        try {
            // Use reflection to retrieve the WebEngine's private 'page' field. 
            Field f = wv.getEngine().getClass().getDeclaredField("page");
            f.setAccessible(true);
            com.sun.webkit.WebPage page = (com.sun.webkit.WebPage) f.get(wv.getEngine());
            page.setBackgroundColor((new java.awt.Color(0,0)).getRGB());
            f.setAccessible(false);
        } catch (Exception e) {
        }

    });
    vb.getChildren().add(b);

    primaryStage.setScene(new Scene(vb));
    primaryStage.show();
}

添加导入列表

import com.sun.webkit.dom.HTMLDocumentImpl;
import java.lang.reflect.Field;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.w3c.dom.Node;

您可能需要添加以下内容:

--add-exports=javafx.web/com.sun.webkit.dom=ALL-UNNAMED \

run.jvm 文件的 project.properties args 参数中。

注意...这是一种黑客行为,oracle 不鼓励这样做。

编辑 (2)

enter image description here

同样,这是一种黑客行为,充其量是不完整的。

此快照是在移除背景后立即向下滚动后拍摄的。

从技术上讲,我认为正在发生的事情是,每当 DOM 渲染引擎重新绘制框架时,都希望分层绘制所有内容,而背景永远不会是透明的。因此,它不会“清除”内容,它只是重复地在自身之上绘制前景。

此外,还有一件有趣的事情正在发生。

如果你点击 + reloadpage,或者如果你点击“接受 cookie”,页面背景会被删除......我很确定这会触发 dom 更新。

所以显然正在发生的事情是 WebView 和 WebPage 组件是 2 个不同领域的一部分。 WebView 是 DOM 操作... WebPage 是 DOM 在处理渲染的特定阶段使用的东西。

如果我就 WebPage 中的功能为何被“隐藏”发表我的看法,我可能会暂停此帐户……但根据个人经验,每当难以掌握的内容(例如 WebPage)在openJFx,这通常意味着您将浪费数月的时间来寻找解决方案,而这些解决方案很可能在未来某个时候更改,从而使您的更改过时。

我的建议是要么放弃这个问题,要么彻底改变你的心态。

我认为您应该做的基本上是在窗格之类的东西中模拟渲染。

so... new Stage... PaneX 作为场景,解析 webview 中的任何内容,并使用 css 和诸如此类的东西将节点放在 PaneX 中,这些节点的外观和感觉基本上与 webview 中的节点相同。 ...正如您所想的那样...这将是屁股中的一个窗格...

或者,您可能需要考虑获取 openjfx 代码库并使用修改后的源代码,以便通过添加额外代码使网页有效地清除自身......但这取决于您。

最后,您必须考虑这样做的原因可能与性能问题有关。

例如,不是只清除网页中的背景,而是删除页面中 CSS 中的任何和所有背景,您必须执行很多操作。这意味着性能问题,因为它本质上意味着在页面加载时解析完整的 dom 树。

,

经过多次尝试,我终于达到了预期的效果。

JDK 15、JavaFX 15。

我尝试从这里实现一个示例:https://stackoverflow.com/a/26519831/10946427

还有一个透明的背景。然后我就知道为什么了。这是由于我通过大量试验和错误添加的 VM 选项。

如果没有这些 VM 选项,示例将无法运行:

--add-exports
javafx.web / com.sun.javafx.webkit = ALL-UNNAMED
--add-exports
javafx.web / com.sun.webkit = ALL-UNNAMED
--add-opens
javafx.web / javafx.scene.web = ALL-UNNAMED

我选择的最佳答案中的示例很可能也适用于这些选项。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...