Adding HTML Content to JavaFX Applications
Beta Draft: 2013-09-17
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, new EventHandler<MouseEvent>() { @Override public void handle(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(new EventHandler<ActionEvent>() { public void handle(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.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener.Change; import javafx.concurrent.Worker.State; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.event.EventHandler; 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 javafx.util.Callback; import netscape.javascript.JSObject; public class WebViewSample extends Application { private Scene scene; @Override public void start(Stage stage) { // create scene stage.setTitle("Web View"); scene = new Scene(new Browser(), 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 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 showPrevDoc = new Button("Toggle Previous Docs"); final WebView smallView = new WebView(); final ComboBox comboBox = new ComboBox(); private boolean needDocumentationButton = false; public Browser() { //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("Documentation")); // process the event hpl.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(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 an ction for the button showPrevDoc.setOnAction(new EventHandler() { @Override public void handle(Event t) { webEngine.executeScript("toggleDisplay('PrevRel')"); } }); smallView.setPrefSize(120, 80); //handle popup windows webEngine.setCreatePopupHandler( new Callback<PopupFeatures, WebEngine>() { @Override public WebEngine call(PopupFeatures config) { smallView.setFontScale(0.8); if (!toolBar.getChildren().contains(smallView)) { toolBar.getChildren().add(smallView); } return smallView.getEngine(); } } ); //process the history final WebHistory history = webEngine.getHistory(); history.getEntries().addListener(new ListChangeListener<WebHistory.Entry>(){ @Override public void onChanged(Change<? extends Entry> c) { c.next(); for (Entry e : c.getRemoved()) { comboBox.getItems().remove(e.getUrl()); } for (Entry e : c.getAddedSubList()) { comboBox.getItems().add(e.getUrl()); } } }); //set the behavior for the history combobox comboBox.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent ev) { int offset = comboBox.getSelectionModel().getSelectedIndex() - history.getCurrentIndex(); history.go(offset); } }); // process page loading webEngine.getLoadWorker().stateProperty().addListener( new ChangeListener<State>() { @Override public void changed(ObservableValue<? extends State> ov, State oldState, State newState) { toolBar.getChildren().remove(showPrevDoc); if (newState == State.SUCCEEDED) { JSObject win = (JSObject) webEngine.executeScript("window"); win.setMember("app", new JavaApp()); if (needDocumentationButton) { toolBar.getChildren().add(showPrevDoc); } } } } ); //adding a context menu final ContextMenu cm = new ContextMenu(); MenuItem cmItem1 = new MenuItem("Print"); cm.getItems().add(cmItem1); toolBar.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { if (e.getButton() == MouseButton.SECONDARY) { cm.show(toolBar, e.getScreenX(), e.getScreenY()); } } } ); //processing a print job cmItem1.setOnAction(new EventHandler<ActionEvent>() { public void handle(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