Dawid
Dawid

Reputation: 563

Make WebView ignore scene CSS in JavaFX

When I load a site / html using javafx.scene.web.WebView that site seems to be affected by my scene custom styling. A minimal example to demonstrate the issue.

Main.java

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox root = new VBox();

        primaryStage.setScene(new Scene(root, 900, 900));

        String css = Main.class.getResource("/test.css").toExternalForm();
        primaryStage.getScene().getStylesheets().add(css);

        WebView webView = new WebView();

        root.getChildren().add(webView);

        webView.getEngine().load("http://google.pl");

        primaryStage.show();
    }


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

test.css

.text-area,
.text-field {
  -fx-background-color: red;
}

This results in Image representing the result of above's code

Ultimately I wish for a method like webview.getEngine().dontInheritStyles()of course there is none and I couldn't find any method of doing it otherwise. Tried:

webView.getStylesheets().clear();
webView.setStyle(null);
webView.getStyleClass().clear();

none of them worked. One way that I think could make this work (haven't tried it yet tho) would be to open the webview in a sub window which doesn't use the same scene, however I want the webview to be embeded in my existing application view so that option would be my last resort and I rather avoid it.

Upvotes: 2

Views: 513

Answers (2)

B. Thomas
B. Thomas

Reputation: 201

You can also use style classes in your CSS to manage which elements get styles applied to them. Define a 'myapplication' class in your css, and add that class to your root node.

test.css

/* any text fields inside a container with the myapplication style class */
.myapplication > .text-field{
    -fx-background-color: red;
}

/* any text areas inside a container with the myapplication style class */
.myapplication > .text-area{
    -fx-background-color: red;
}

Main.java

...
root.getStyleClass().add("myapplication");
TextField txtField = new TextField("Application text field");
root.getChildren().addAll(webView, txtField);
...

Using the '>' css selector (https://www.w3schools.com/cssref/css_selectors.asp) this way will apply the style to text fields whose parent has the style class 'myapplication'. When a WebView is created, it has the style class 'web-view' (https://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#webview)

While there is no real way to prevent style values from being inherited, style classes are not added to children.

Upvotes: 0

mrg
mrg

Reputation: 332

You can use some kind of hack, such as a combination of JavaFX and Swing.

You have two classes:

  • JFXPanel - which allows you to embed a JavaFX control into Swing
  • SwingNode - which allows you to embed a Swing control into JavaFX

You can combine the use of the JFXPanel and SwingNode classes in the wrapper class:

public class Styleless<T extends Parent> extends StackPane {
    private T root;

    public Styleless(T root) {
        this.root = root;

        JFXPanel jfxPanel = new JFXPanel();
        jfxPanel.setScene(new Scene(root));

        SwingNode swingNode = new SwingNode();
        swingNode.setContent(jfxPanel);

        getChildren().add(swingNode);
    }

    public T getRoot() {
        return root;
    }
}

And you can use it like this:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox root = new VBox();
        primaryStage.setScene(new Scene(root, 900, 900));

        String css = Main.class.getResource("/test.css").toExternalForm();
        primaryStage.getScene().getStylesheets().add(css);

        WebView webView = new WebView();
        webView.getEngine().load("http://google.pl");

        Styleless<WebView> webViewStyleless = new Styleless<>(webView);

        root.getChildren().add(webViewStyleless);
        VBox.setVgrow(webViewStyleless, Priority.ALWAYS);

        primaryStage.show();
    }

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

Upvotes: 2

Related Questions