How to insert HTML text inside a JavaFX shape?

Maulik Shah :

I want to create a tree-based algorithm visualization in JavaFx, and there are many sub scripts and super scripts in the notations. I want to add these notations to shapes like circles.

I have tried using WebView object for doing that, but it just covers up the entire screen.

public void start(Stage primaryStage) throws Exception{

        primaryStage.setTitle("Shape Text");
        Group circles = new Group();
        Circle circle = new Circle(50, Color.web("white", 0.7));
        circle.setCenterX(500.0f);
        circle.setCenterY(200.0f);
        circle.setStrokeType(StrokeType.OUTSIDE);
        circle.setStroke(Color.web("white", 0.16));
        circle.setStrokeWidth(4);
        circles.getChildren().add(circle);

        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();
        webEngine.loadContent("<h1>B<sub>0</sub></h1>");

        StackPane stack = new StackPane();
        stack.getChildren().addAll(circles, webView);

        Scene scene = new Scene(stack, 1000, 800, Color.BLACK);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

The above code replaces the entire view with HTML text. I also tried javafx.scene.text.Text class, but it does not support the HTML content.

Thank you in advance!

jewelsea :

There are three things you might want to do:

  1. Size the WebView to the HTML content (or the inner display region of the shape).
  2. Make the background of the WebView pages transparent.
  3. Center the HTML content in the WebView, with the WebView centered in the Shape.

sized webview

Code below demonstrates some of these tricks:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.StrokeType;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

import java.lang.reflect.Field;

public class ShapedHTML extends Application {
    @Override
    public void start(Stage stage) throws Exception{
        stage.setTitle("Shape Text");
        Group circles = new Group();
        Circle circle = new Circle(50, Color.web("white", 0.7));
        circle.setCenterX(500.0f);
        circle.setCenterY(200.0f);
        circle.setStrokeType(StrokeType.OUTSIDE);
        circle.setStroke(Color.web("white", 0.16));
        circle.setStrokeWidth(4);
        circles.getChildren().add(circle);

        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();
        webView.maxWidthProperty().bind(circle.radiusProperty().multiply(2));
        webView.maxHeightProperty().bind(circle.radiusProperty().multiply(2));
        webEngine.documentProperty().addListener(observable -> {                   
            try {
                // Use reflection to retrieve the WebEngine's private 'page' field.
                Field f = webEngine.getClass().getDeclaredField("page");
                f.setAccessible(true);
                com.sun.webkit.WebPage page = (com.sun.webkit.WebPage) f.get(webEngine);
                page.setBackgroundColor((new java.awt.Color(0, 0, 0, 0)).getRGB());
            } catch (Exception e) {
                System.out.println("Difficulty to make WebView background transparent");
                e.printStackTrace();
            }
        });

        webEngine.loadContent("<h1 id='root' style='background : rgba(0,0,0,0); margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);'>B<sub>0</sub></h1>");

        StackPane stack = new StackPane();
        stack.getChildren().addAll(circles, webView);

        Scene scene = new Scene(stack, 1000, 800, Color.BLACK);
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }

}

Note on com.sun class usage

The above code uses com.sun classes (which is usually not recommended as it is not publicly supported API). But, it worked for me (on Java 8) and I don't know a better way to accomplish the transparency of the WebView background.

If you are using later versions of Java (e.g. Java 11+), then you will need to provide some VM arguments to allow usage of the relevant com.sun classes to work. See, for instance, the stack overflow question Cannot access JavaFX class "WebPage" in IntelliJ-IDEA for resolving accessibility issues for com.sun.webkit.WebPage in Java 11+. An answer to that question suggests using the following VM arguments (which I haven't tried):

--add-exports javafx.web/com.sun.webkit=projectname

where the last argument is your module name as declared in the module-info.java of your project.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=143393&siteId=1