9 Printing HTML Content
This chapter teaches you how to print a web page loaded in the WebView
component.
With the printing API available in JavaFX 8, you can print graphical content of JavaFX applications. The corresponding classes and enums are located in the javafx.print
package.
Using the Printing API
To enable the printing functionality in your JavaFX application, you must use the PrinterJob
class. This class represents a printer job that is associated with the default system printer. Use the Printer
class to alter a printer for a particular job. For each print job, you can specify job settings by using the properties of the JobSettings
class such as collation
, copies
, pageLayout
, pageRanges
, paperSource
, printColor
, printResolution
, printQuality
, and printSides
.
You can print any node of the scene graph including the root node. You can also print nodes that are not added to the scene. Use the printPage
method to initiate a print job for a particular node: job.printPage(node)
. See the to JavaFX 8 API specification for more information about printing capabilities.
When working with the JavaFX web component, you typically need to print an HTML page loaded into the browser rather than the application UI itself. That is why the print
method was added to the WebEngine
class. This method is geared toward printing an HTML page that is associated with the web engine.
Adding a Context Menu to Enable Printing
Typically, you add a Print command to an application menu or assign printing to one of the toolbar buttons. In the WebViewSample application, the toolbar is overloaded with controls, which is why you add the Print command to the context menu that is enabled by a right-click. Example 9-1 shows a code fragment that adds a context menu with the Print command to the application toolbar.
Example 9-1 Creating a Toolbar Context Menu
//adding context menu final ContextMenu cm = new ContextMenu(); MenuItem cmItem1 = new MenuItem("Print"); cm.getItems().add(cmItem1); toolBar.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> { if (e.getButton() == MouseButton.SECONDARY) { cm.show(toolBar, e.getScreenX(), e.getScreenY()); } });
When you add the code fragment from Example 9-1 to the WebViewSample application, run it, and right click the toolbar, the Print context menu appears, as shown in Figure 9-1.
Processing a Print Job
After the Print context menu is added to the application UI, you can define the printing action. First, you must create a PrinterJob
object. Then, you call the WebEngine.print
method passing the printer job as a parameter, as shown in Example 9-2.
Example 9-2 Calling the WebEngine.print Method
//processing print job cmItem1.setOnAction((ActionEvent e) -> { PrinterJob job = PrinterJob.createPrinterJob(); if (job != null) { webEngine.print(job); job.endJob(); } });
It is important to check for non-null printer jobs, because the createPrinterJob
method returns null
if there are no printers available in the system.
Study Example 9-3 to evaluate the complete code of the WebViewSample application with the enabled printing functionality.
Example 9-3 WebViewSample With the Enabled Printing Functionality
import javafx.application.Application; import javafx.application.Platform; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener.Change; import javafx.concurrent.Worker.State; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.geometry.HPos; import javafx.geometry.Pos; import javafx.geometry.VPos; import javafx.print.PrinterJob; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.ContextMenu; import javafx.scene.control.Hyperlink; import javafx.scene.control.MenuItem; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.paint.Color; import javafx.scene.web.PopupFeatures; import javafx.scene.web.WebEngine; import javafx.scene.web.WebHistory; import javafx.scene.web.WebHistory.Entry; import javafx.scene.web.WebView; import javafx.stage.Stage; import netscape.javascript.JSObject; public class WebViewSample extends Application { private Scene scene; @Override public void start(Stage stage) { // create scene stage.setTitle("Web View Sample"); scene = new Scene(new Browser(stage), 900, 600, Color.web("#666970")); stage.setScene(scene); // apply CSS style scene.getStylesheets().add("webviewsample/BrowserToolbar.css"); // show stage stage.show(); } public static void main(String[] args) { launch(args); } } class Browser extends Region { private final HBox toolBar; final private static String[] imageFiles = new String[]{ "product.png", "blog.png", "documentation.png", "partners.png", "help.png" }; final private static String[] captions = new String[]{ "Products", "Blogs", "Documentation", "Partners", "Help" }; final private static String[] urls = new String[]{ "http://www.oracle.com/products/index.html", "http://blogs.oracle.com/", "http://docs.oracle.com/javase/index.html", "http://www.oracle.com/partners/index.html", WebViewSample.class.getResource("help.html").toExternalForm() }; final ImageView selectedImage = new ImageView(); final Hyperlink[] hpls = new Hyperlink[captions.length]; final Image[] images = new Image[imageFiles.length]; final WebView browser = new WebView(); final WebEngine webEngine = browser.getEngine(); final Button toggleHelpTopics = new Button("Toggle Help Topics"); final WebView smallView = new WebView(); final ComboBox comboBox = new ComboBox(); private boolean needDocumentationButton = false; public Browser(final Stage stage) { //apply the styles getStyleClass().add("browser"); for (int i = 0; i < captions.length; i++) { // create hyperlinks Hyperlink hpl = hpls[i] = new Hyperlink(captions[i]); Image image = images[i] = new Image(getClass().getResourceAsStream(imageFiles[i])); hpl.setGraphic(new ImageView(image)); final String url = urls[i]; final boolean addButton = (hpl.getText().equals("Help")); // process event hpl.setOnAction((ActionEvent e) -> { needDocumentationButton = addButton; webEngine.load(url); }); } comboBox.setPrefWidth(60); // create the toolbar toolBar = new HBox(); toolBar.setAlignment(Pos.CENTER); toolBar.getStyleClass().add("browser-toolbar"); toolBar.getChildren().add(comboBox); toolBar.getChildren().addAll(hpls); toolBar.getChildren().add(createSpacer()); //set action for the button toggleHelpTopics.setOnAction((ActionEvent t) -> { webEngine.executeScript("toggle_visibility('help_topics')"); }); smallView.setPrefSize(120, 80); //handle popup windows webEngine.setCreatePopupHandler( (PopupFeatures config) -> { smallView.setFontScale(0.8); if (!toolBar.getChildren().contains(smallView)) { toolBar.getChildren().add(smallView); } return smallView.getEngine(); }); //process history final WebHistory history = webEngine.getHistory(); history.getEntries().addListener( (Change<? extends Entry> c) -> { c.next(); c.getRemoved().stream().forEach((e) -> { comboBox.getItems().remove(e.getUrl()); }); c.getAddedSubList().stream().forEach((e) -> { comboBox.getItems().add(e.getUrl()); }); }); //set the behavior for the history combobox comboBox.setOnAction((Event ev) -> { int offset = comboBox.getSelectionModel().getSelectedIndex() - history.getCurrentIndex(); history.go(offset); }); // process page loading webEngine.getLoadWorker().stateProperty().addListener( (ObservableValue<? extends State> ov, State oldState, State newState) -> { toolBar.getChildren().remove(toggleHelpTopics); if (newState == State.SUCCEEDED) { JSObject win = (JSObject) webEngine.executeScript("window"); win.setMember("app", new JavaApp()); if (needDocumentationButton) { toolBar.getChildren().add(toggleHelpTopics); } } }); //adding context menu final ContextMenu cm = new ContextMenu(); MenuItem cmItem1 = new MenuItem("Print"); cm.getItems().add(cmItem1); toolBar.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> { if (e.getButton() == MouseButton.SECONDARY) { cm.show(toolBar, e.getScreenX(), e.getScreenY()); } }); //processing print job cmItem1.setOnAction((ActionEvent e) -> { PrinterJob job = PrinterJob.createPrinterJob(); if (job != null) { webEngine.print(job); job.endJob(); } }); // load the home page webEngine.load("http://www.oracle.com/products/index.html"); //add components getChildren().add(toolBar); getChildren().add(browser); } // JavaScript interface object public class JavaApp { public void exit() { Platform.exit(); } } private Node createSpacer() { Region spacer = new Region(); HBox.setHgrow(spacer, Priority.ALWAYS); return spacer; } @Override protected void layoutChildren() { double w = getWidth(); double h = getHeight(); double tbHeight = toolBar.prefHeight(w); layoutInArea(browser,0,0,w,h-tbHeight,0,HPos.CENTER,VPos.CENTER); layoutInArea(toolBar,0,h-tbHeight,w,tbHeight,0,HPos.CENTER,VPos.CENTER); } @Override protected double computePrefWidth(double height) { return 900; } @Override protected double computePrefHeight(double width) { return 600; } }
To extend the printing capabilities of the WebViewSample application, use the classes available in the javafx.print
package.
In your JavaFX application, you can implement browser tabs by using the TabPane
class and create a new WebView
object when a user adds a new tab.
To further enhance this application, you can apply effects, transformations, and animated transitions. You can also add more WebView
instances to the application scene.
See the JavaFX API documentation and the JavaFX CSS specification for more information about available features. You can also study the JavaFX in Swing tutorial to learn how to add a WebView
component in your existing Swing application.
Related API Documentation
-
WebView
-
WebEngine
-
WebHistory
-
Region
-
Hyperlink
-
Worker