0

I have a JavaFX program that displays a WebView. This is in Java but I think its really a Javascript question. Here is the complete code:

Main.java:

package main;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

public class Main extends Application {
    

    int viewsToLoad = 1;
    int viewsLoaded = 0;
        
    VBox vBoxOuter;
    
    
    @Override
    public void start(Stage _primaryStage) {
        
        // the scene root is a VBox
        vBoxOuter = new VBox();
        vBoxOuter.setPrefWidth(400);
        vBoxOuter.setPrefHeight(400);
        
        // this adds the inner VBox which contains the webview
        addInnerVBox();
        
        Scene scene = new Scene(vBoxOuter);
        scene.getStylesheets().add("/main/styles.css");
        _primaryStage.setTitle("Notes Program");
        _primaryStage.setScene(scene);
        _primaryStage.show();
    }

    public void addInnerVBox() {
        
        // label accros the top of the vbox
        // LABEL -> RED BACKGROUND
        HBox hBox = new HBox();
        Label label = new Label("This is a label");
        hBox.getChildren().add(label);
        vBoxOuter.getChildren().add(hBox);
        
        
        // then the webview
        // WEBVIEW -> WHITE BACKGROUND
        WebView webView;
        WebEngine webEngine;
        
        String textString = "";
        textString += "It's the end of the world as we know it and I feel fine. ";
        textString += textString;
        textString += textString;
        textString += textString;
        
        // add a webview
        webView = new WebView();
        webEngine = webView.getEngine();
        
        // ini height of webView to 0 so that it doesnt stretch to fill the VBox before determining
        // the ideal height to wrap contents
        webView.setMinHeight(0);
        webView.setMaxHeight(0);
        webView.setPrefHeight(0);
        vBoxOuter.getChildren().add(webView);
        
        
        // resizing width of the webView
        // need to dynamically resize height
        webView.widthProperty().addListener((obs, oldVal, newVal) -> {

            setWebViewHeight(webView);
        });
        
        
        // this will fire after every time we load content into the editor
        webEngine.getLoadWorker().stateProperty().addListener(
            
            new ChangeListener<Object>() {              
                @Override
                public void changed(ObservableValue<?> observableValue, Object oldValue, Object newValue) {
        
                    // ok mamke sure loading the content ws successful, apparently this gets called a few times?
                    if (newValue != Worker.State.SUCCEEDED) { 
                        return; 
                    }
                    viewsLoaded++;
                    setWebViewHeight(webView);
                };
            }
        );

        webEngine.loadContent(textString);
    }
    
    
    // sets the height of the webview based on the height of its content
    // only if all webviews have finished loading their contents, very important
    public void setWebViewHeight(WebView webView) {
        
        if (viewsLoaded < viewsToLoad) {
            return;
        }
        
        WebEngine webEngine = webView.getEngine();
        
        // this works great as you decrease the width of the webview, causing the document/body to increase
        // in height. But as you expand the width of the webview, the document/body height doesnt change
        String heightText = webEngine.executeScript(  
                "var body = document.body,"
                        + "html = document.documentElement;"
                        + "Math.max( body.scrollHeight , body.offsetHeight, "
                        + "html.clientHeight, html.scrollHeight , html.offsetHeight );"
        ).toString();
        System.out.println("heightText=" + heightText);

        double height = Double.valueOf(heightText.replace("px", "")); 

        webView.setMinHeight(height);
        webView.setMaxHeight(height);
        webView.setPrefHeight(height);
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

In the layout, I always want the WebView dimensions to fit its HTML contents perfectly, with no scroll and no extra space. I try to accomplish this with Javascript on the WebView contents. Here is an example on program load, where the height of the WebView is set to match the HTML contents, given the width of the WebView

enter image description here

Fine so far. So when the width of the Webview changes, I need to calculate what the height of the WebView should be, then set the height manually. Here's what it looks like when we shrink the width:

enter image description here

Perfect. The height of the WebView increases to continue to fit its contents perfectly. The problem is if I shrink the width, then expand the width. This is what happens

enter image description here:

As the width expands, it seems that the the Document and Body height don't decrease. So as it expands, the value returned from reading the body height is constant, and you can't figure the ideal height to set. So you just keep setting the same height as it expands.

If someone could help me with a way to continue to resize the WebView as the width expands this would be greatly appreciated. Maybe some Javascript could tell the document to fit its contents somehow but I can't find anything that does this. It's possible I could loop through every node in the HTML, get its height, add that all up, then set the body height that way, but this feels like a horrible hack. Furthermore, I could have many WebViews with unpredictable contents on the same page. Some native method would be much preferred.

I did read the post here: Correct sizing of Webview embedded in Tabelcell as recommended by another member but I don't believe it's what I'm looking for.

Thanks in advance for your help.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Geoff L
  • 765
  • 5
  • 22
  • Didn’t I [already answer this](https://stackoverflow.com/questions/69245865/javafx-make-webview-behave-like-label-in-vbox/69276406#69276406)? – jewelsea Sep 24 '21 at 23:14
  • Uh that was a different question asking if you could make a WebView function like a label. Your opinion was it could only be done using javascript in some way. You provided a great answer in the previous question thank you, and your suggestion was this could be done with Javascript. So I got halfway there with script but I can't get past the finish line. The link you provided helped a little bit but doesn't quite get there. I'm following your advice, using script, but have run into a new problem. – Geoff L Sep 24 '21 at 23:28
  • They say in stackoverflow your questions should be specific to a single problem. If i added this to the previous question you get accused of "not sticking to single question" – Geoff L Sep 24 '21 at 23:32
  • Thanks for clarifying. – jewelsea Sep 24 '21 at 23:43

0 Answers0