我正在开发使用JavaFX 8 PrintJob和Printer API显示TableView并输出PDF文件的JavaFX应用程序。 JDK版本是1.8.0。
我希望场景中的所有文本都作为文本数据输出到PDF文件中。 但是,结果是文本被渲染为图像而不是文本数据。 我的系统要求是将所有文本存储为文本数据,以便用户可以通过PDF阅读器软件(如Adobe Reader)进行选择和复制。
问题是如何修改TabeView属性以便将文本作为文本打印。 我不想将标签放在TableView中的每个单元格上,但如果没有办法实现我的目标,我将采用这种不太智能的解决方案。
出于调查目的,我刚刚创建了一个小应用程序,如下所示。 该应用程序包括两个按钮([重新加载CSS]和[打印]按钮),一个标签和一个TableView。
[Reload CSS]按钮:为方便测试而设置。修改CSS文件后,测试人员无需重新启动应用程序。在CSS文件更改后检查行为时,请单击此按钮。
[打印]按钮:单击时,将显示打印对话框,然后请选择一个PDF创建软件作为打印机,如CubePDF。
我发现只有一件事是,当在CSS文件中使用小于1.0的值(例如0.99)设置TableView的'-fx-opacity'样式时,该标签位于TableView外部(在我的情况下) ,它显示“人员列表”)作为文本数据输出。 可以通过PDF阅读器软件选择文本“人员列表”。 但是,整个TableView呈现为一个图像。 如果提供了一些智能解决方案,我将不胜感激。
主类:PrintApp.java
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* Main class.
*/
public class PrintApp extends Application {
/**
* Start the application.
* @param stage Stage object
* @throws Exception Exception
*/
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("person_list.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXML文件:person_list.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.Pane?>
<Pane fx:id="rootPane" prefHeight="400.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.FxmlController">
<stylesheets>
<URL value="@style.css" />
</stylesheets>
<children>
<!-- Reload the CSS file -->
<!-- * User does not need to re-start the application after the CSS file is modified. -->
<Button layoutX="20.0" layoutY="10.0" onAction="#reload" prefHeight="20.0" prefWidth="80.0" text="Reload CSS" />
<!-- Print the "printBoundsPane" pane -->
<Button layoutX="120.0" layoutY="10.0" onAction="#print" prefHeight="20.0" prefWidth="80.0" text="Print" />
<!-- Target bounds which is printed out. -->
<!-- * When the [Print] button is clicked, the print dialog will be displayed. -->
<!-- Then, the following "Pane" will be printed out. -->
<Pane fx:id="printBoundsPane" layoutX="20.0" layoutY="60.0" prefHeight="300.0" prefWidth="260.0">
<children>
<Label layoutX="10.0" layoutY="10.0" text="Person List" />
<TableView fx:id="table" layoutY="40.0" prefHeight="260.0" prefWidth="260.0" visible="true">
<columns>
<TableColumn fx:id="familyNameColumn" prefWidth="120.0" text="Family Name" />
<TableColumn fx:id="givenNameColumn" prefWidth="120.0" text="Given Name" />
</columns>
</TableView>
</children>
</Pane>
</children>
</Pane>
CSS文件:style.css
/**
* Root pane.
*/
#rootPane {
-fx-background-color: white;
}
/**
* Actual bounds which is printed out.
*/
#printBoundsPane {
-fx-border-color: darkgray;
-fx-border-width: 1px;
}
/**
* Whole TableView.
*/
.table-view {
-fx-opacity: 0.99;
}
控制器类:FxmlController.java
package test;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.print.PageLayout;
import javafx.print.PageOrientation;
import javafx.print.Paper;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.Pane;
/**
* FXML Controller class.
*/
public class FxmlController implements Initializable {
@FXML private Pane rootPane;
@FXML private Pane printBoundsPane;
@FXML private TableView<Person> table;
@FXML private TableColumn<Person, String> familyNameColumn;
@FXML private TableColumn<Person, String> givenNameColumn;
/**
* Initialize the stage.
* @param location FXML file location
* @param resources resources
*/
@Override
public void initialize(URL location, ResourceBundle resources) {
// Link the data with a column.
this.familyNameColumn.setCellValueFactory(new PropertyValueFactory("familyName"));
this.givenNameColumn.setCellValueFactory(new PropertyValueFactory("givenName"));
// Add sample records to the TableView
table.getItems().add(new Person("TEST1", "test1"));
table.getItems().add(new Person("TEST2", "test2"));
}
/**
* Event listener for [Reload CSS] button.
* Reload the CSS file.
* @throws java.net.MalformedURLException
*/
public void reload() throws MalformedURLException {
// Get the stylesheet list.
ObservableList<String> styleSheets = this.rootPane.getStylesheets();
// CSS file location.
URL cssLocation = new URL(styleSheets.get(0));
// Reset the CSS file.
rootPane.getStylesheets().set(0, cssLocation.toExternalForm());
}
/**
* Event listener for [Print] button.
* Print out the pane which can be identified as "printBoundsPane".
*/
public void print() {
// Default printer object.
Printer printer = Printer.getDefaultPrinter();
// Print page layout object.
// * Set "LANDSCAPE" as the page orientation for the convenience for the test.
// If the output pdf has the text information, the output file is shown in a PORTRAIT mode.
// If not, it will be shown in a LANDSCAPE mode.
PageLayout layout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.DEFAULT);
// Create a printer job.
PrinterJob job = PrinterJob.createPrinterJob();
if (job != null) {
// Set the job name.
job.getJobSettings().setJobName("TestPrint");
if (job.showPrintDialog(this.rootPane.getScene().getWindow())) {
// Print out the specified pane.
job.printPage(layout, this.printBoundsPane);
}
else {
System.out.println("Print canceled.");
}
// Finish the print job.
job.endJob();
}
}
/**
* The class for defining a person.
*/
public static class Person {
private final StringProperty familyName = new SimpleStringProperty();
private final StringProperty givenName = new SimpleStringProperty();
/**
* Constructor.
* @param _familyName Family name of the person.
* @param _givenName Given name of the person.
*/
Person(String _familyName, String _givenName) {
this.familyName.set(_familyName);
this.givenName.set(_givenName);
}
public StringProperty familyNameProperty() {return this.familyName;}
public StringProperty givenNameProperty() {return this.givenName;}
}
}