DOC-04-09 打印HTML内容
本章教会你如何打印WebView组件中加载的Web页面。
使用JavaFX8中提供的打印API,你可以打印JavaFX程序的图形化内容。在javafx.print包中有对应的类和枚举。
9.1 使用打印API
要想在JavaFX程序中启用打印功能,你需要使用PrinterJob类。该类表示与系统默认打印机相关联的一个打印任务。使用Printer类来控制一个打印机来执行特定的打印任务。对于每一个打印任务,你都可以通过使用JobSetting类的属性来指定任务设置,如校对(collation)、份数(copies)、页面布局(pageLayout)、页面范围(pageRanges)、纸张来源(paperSource)、打印颜色(printColor)、打印分辨率(printResolution)、打印质量(printQuality)和单双面(printSides)。
你可以打印场景图的任何节点,包括根节点。你也可以打印那些没添加到场景中的节点。使用printPage方法job.printPage(node)来为某node初始化一个打印任务。有关打印功能的更多信息请参考JavaFX8的API说明。
在使用JavaFX的web组件时,你通常需要打印一个加载到浏览器中的HTML页面而不是程序UI本身。这就是为什么WebEngine类中添加了print方法,此方法就是为了打印与webEngine对象关联的HTML页面而生的。
9.2 添加上下文菜单启用打印功能
通常来讲,你需要把打印指令添加到程序的菜单或者工具栏中。在WebViewSample程序中,工具栏放了太多控件了,所以需要把打印功能放到点击鼠标右键弹出的菜单中。例9-1展示了如何把拥有打印功能的弹出式菜单放到程序工具栏中的代码片段。
例9-1 创建工具栏的弹出式菜单
1 2 3 4 5 6 7 8 9 |
//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()); } }); |
把上例中的代码片段加到之前的WebViewSample程序中,运行以后右键点击工具栏打印菜单即出现了,如图9-1所示。
图9-1 拥有打印功能的弹出式菜单
9.3 处理打印任务
将打印的菜单添加到程序UI中以后,就可以定义打印的动作了。首先,你需要创建一个PrinterJob对象;然后,调用WebEngine.print方法,将该printJob对象作为参数传进去。请参考例9-2。
例9-2 调用WebEngine.print方法
1 2 3 4 5 6 7 8 |
//processing print job cmItem1.setOnAction((ActionEvent e) -> { PrinterJob job = PrinterJob.createPrinterJob(); if (job != null) { webEngine.print(job); job.endJob(); } }); |
对printerJob的非空判断很重要,因为如果系统中没有可用的打印机则createPrinterJob方法会返回null。
学习例9-3中添加了打印功能的WebViewSample的完整代码。
例9-3 启用了打印功能的WebViewSample
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
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; } } |
若想扩充WebViewSample程序的打印功能,请使用javafx.print包中的类。
在你的JavaFX程序中,你可以使用TabPane类实现浏览器标签页功能,当用户添加新的标签页时创建新的WebView对象即可。
若要进一步增强该程序,你可以应用特效、变形和动画转换。你也可以添加更多的WebView实例到程序的scene中。
参考JavaFX的API文档和JavaFX CSS规范了解更多可用特性的信息。你也可以学习JavaFX in Swing tutorial来学习如何在你已有的Swing程序中添加WebView组件。
相关API文档
● WebView
● WebEngine
● WebHistory
● Region
● Hyperlink
● Worker

