0

I am working on a JavaFX project in which I have a bunch of static HTML&JS pages and I am loading the index.html which the users can check out and click on links, etc.

Now, generally when we are using a browser like Firefox or Chromium, then calling the print command does the printing task.

BUt that is not the same thing happening in the webview . How do I enable printing in JavaFX's webpage rendering mechanism.

What is also okay is some way to call a print function and pass it the webpage or webview from JavaScript.

Here is my code so far :

public class Main extends Application {

    private Scene scene;
    MyBrowser myBrowser;

    @Override
    public void start(Stage primaryStage) throws Exception{
        primaryStage.setTitle("Test web");
        Screen screen = Screen.getPrimary();
        myBrowser = new MyBrowser();
        scene = new Scene(myBrowser, 1080, 1920);
        myBrowser.setPrefSize(1080, 1920);
        Rectangle2D bounds = screen.getVisualBounds();
        primaryStage.setX(bounds.getMinX());
        primaryStage.setY(bounds.getMinY());
        scene.setRoot(myBrowser);
        primaryStage.setScene(scene);
        primaryStage.setMaximized(false);
        primaryStage.setFullScreen(true);
        primaryStage.show();
    }


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


class MyBrowser extends Region {

    final String hellohtml = "hello.html";

    WebView webView = new WebView();
    WebEngine webEngine = webView.getEngine();

    public MyBrowser(){

        URL urlHello = getClass().getResource("hello.html");
        webEngine.load(urlHello.toExternalForm());
        webView.setPrefSize(1080, 1920);
        webView.getChildrenUnmodifiable().addListener(new ListChangeListener<Node>() {
            @Override public void onChanged(Change<? extends Node> change) {
                Set<Node> deadSeaScrolls = webView.lookupAll(".scroll-bar");
                for (Node scroll : deadSeaScrolls) {
                    scroll.setVisible(true);
                }
            }
        });
        getChildren().add(webView);
    }
}

Any suggestions or pointers would be nice. Thank you.. :-)

We are Borg
  • 5,117
  • 17
  • 102
  • 225
  • Take a look here: https://carlfx.wordpress.com/2013/07/15/introduction-by-example-javafx-8-printing/ – hotzst Jan 15 '16 at 12:32
  • @hotzst : The app is in full-screen, and I cannot add extra buttons..What is also okay is some way to call a print function and pass it the webpage or webview from JavaScript. – We are Borg Jan 15 '16 at 12:40
  • @hotzst : Any ideas? – We are Borg Jan 15 '16 at 13:00
  • In the example the button is there to trigger the printing, the functionality can basically be attached to any event. Maybe adding a context menu or automatically triggering when the page finished loading. – hotzst Jan 15 '16 at 13:06
  • @hotzst I would like to attach it via Javascript, to be honest I am neither a Javfx or JS developer. Can you please help me out a bit with this. Thank you.. – We are Borg Jan 15 '16 at 13:07

1 Answers1

1

Assuming you have something like this in the page in JS:

<script type="text/javascript">
  function printInJava() {
    ...
  }
</script>

Here is how you go about registering a bridge between your Java code and your JavaScript:

WebEngine webEngine = webView.getEngine();
    webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
        @Override
        public void changed(ObservableValue<? extends State> ov, State t, State t1) {
            if (t1 == Worker.State.SUCCEEDED) {
                JSObject window = (JSObject) webEngine.executeScript("window");
                window.setMember("app", this);
            }
        }
    });

And in the same class you have the method you want to trigger from JavaScript:

public void print() {
  print(webView);
}

The method print(Node) is the same as from this example. I must confess however, that I did not actually try that code and from the look on it you might run into some issues with scaling and printing on multiple pages.

Now you can simply complete the JavaScript:

function printInJava() {
  app.print(); // call out the Java print method defined on the register variable app
}

When putting all this together you end up with this code:

import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.concurrent.Worker;
import javafx.print.PageLayout;
import javafx.print.PageOrientation;
import javafx.print.Paper;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.transform.Scale;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

import java.net.URL;
import java.util.Set;

public class Main extends Application {

  private Scene scene;
  MyBrowser myBrowser;

  @Override
  public void start(Stage primaryStage) throws Exception{
    primaryStage.setTitle("Test web");

    myBrowser = new MyBrowser();
    scene = new Scene(myBrowser, 1080, 1920);

    primaryStage.setScene(scene);
    primaryStage.setFullScreen(true);
    primaryStage.show();

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


class MyBrowser extends Region {

  final String hellohtml = "index.html";

  WebView webView = new WebView();
  WebEngine webEngine = webView.getEngine();


  public MyBrowser(){

    URL urlHello = getClass().getResource(hellohtml);
    webEngine.load(urlHello.toExternalForm());
    webView.setPrefSize(1080, 1920);
    webView.getChildrenUnmodifiable().addListener(new ListChangeListener<Node>() {
      @Override public void onChanged(Change<? extends Node>
                                          change) {
        Set<Node> deadSeaScrolls = webView.lookupAll(".scroll-bar");
        for (Node scroll : deadSeaScrolls) {
          scroll.setVisible(true);
        }
      }
    });

  webEngine. getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue == Worker.State.SUCCEEDED) {
      JSObject window = (JSObject) webEngine.executeScript("window");
      window.setMember("app", this);
    }   });

    getChildren().add(webView);
  }

  /**
   * Callback function from the JavaScript code.
   */
  public void print() {
    print(webView);
  }

  /** Scales the node based on the standard letter, portrait paper to be printed.
   * @param node The scene node to be printed.
   */
  public void print(final Node node) {
    Printer printer = Printer.getDefaultPrinter();
    PageLayout pageLayout = printer.createPageLayout(Paper.NA_LETTER, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);
    double scaleX = pageLayout.getPrintableWidth() / node.getBoundsInParent().getWidth();
    double scaleY = pageLayout.getPrintableHeight() / node.getBoundsInParent().getHeight();
    node.getTransforms().add(new Scale(scaleX, scaleY));

    PrinterJob job = PrinterJob.createPrinterJob();
    if (job != null) {
      boolean success = job.printPage(node);
      if (success) {
        job.endJob();
      }
    }
  }
}

Further references:

Community
  • 1
  • 1
hotzst
  • 7,238
  • 9
  • 41
  • 64
  • Thank you for the prompt reply. Are you using some other version of Java, as the methods which you are using are not found. You can see the image here : http://postimg.org/image/t1fg5nj99/ . I have created a room on SO for this, can you please come, once Ihave the printer code running, that will be all : https://chat.stackoverflow.com/rooms/100769/discussion-with-hotzst – We are Borg Jan 15 '16 at 13:36
  • You probably have a wrong import. Im using Java 8 and `JSObject` is `netscape.javascript.JSObject` – hotzst Jan 15 '16 at 13:44
  • JSOObject is not the problem, webEngine.getLoadWorker and its subsequent properties. Because of that, the `changed` method is also not realized. This image is better : http://postimg.org/image/8m2kfv175/ – We are Borg Jan 15 '16 at 13:50
  • WebView and webEngine are `javafx.scene.web.WebView` and `javafx.scene.web.WebEngine`? – hotzst Jan 15 '16 at 13:55
  • Yes : import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; These are in my Main.java. – We are Borg Jan 15 '16 at 13:57
  • My apologies I had forgotten to accept your answer. Your code had worked... Thank you.. :-) – We are Borg Mar 01 '16 at 15:57