对于 2020 年在这里处理此问题的任何人,我发现了一种非常巧妙的打印 PDF 文件的方法,同时能够在不使用 JavaFX 的情况下监控打印作业——因为人们似乎不太喜欢使用 JavaFX 打印 PDF 文件,而且我并不热衷于对象节点打印,因为在我看来,要让打印出来看起来像一个普通的文档真的很困难...... JavaFX 似乎喜欢 - 基本上 - 屏幕截图的一部分的想法您的表单,然后将该快照呈现为图形,然后您必须为打印机缩放它,它最终看起来有点奇怪......而采用格式良好的 HTML 之类的东西,并通过 PDF 库打印它真的很干净,而且真的很快。所以这是我发现的:
首先,我使用这个免费的库将我的 HTML 字符串呈现为 PDF 文件。这是该库的 Maven 源代码:
<dependency>
<groupId>org.icepdf.os</groupId>
<artifactId>icepdf-core</artifactId>
<version>6.2.2</version>
</dependency>
这是我渲染 PDF 的代码:
String docPath = "/Users/michael/Documents/JavaFile.pdf";
String html = "<html>Any HTML Code you want, including embedded CSS for a really clean look</html>
OutputStream outputStream = new FileOutputStream(docPath);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
outputStream.close();
这是我打印 PDF 的课程......它有点冗长,但非常简单,它使用了很好的原生 Java API(我使用的是 1.8):
import javafx.application.Platform;
import javafx.scene.control.Label;
import java.io.*;
import javax.print.*;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;
public class PrintHandler {
private void delay(int msec) {
try {
Thread.sleep(msec);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public PrintHandler (FileInputStream fis, Label statusLabel) {
this.statusLabel = statusLabel;
this.fis = fis;
}
private FileInputStream fis;
private Label statusLabel;
private String state;
public void startPrintJob () {
try {
Platform.runLater(()->statusLabel.setText("PRINTING"));
delay(5000);
InputStream is = new BufferedInputStream(this.fis);
DocFlavor flavor = DocFlavor.INPUT_STREAM.PDF;
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob printJob = service.createPrintJob();
JobMonitor monitor = new JobMonitor();
printJob.addPrintJobListener(monitor);
Doc doc = new SimpleDoc(is, flavor, null);
printJob.print(doc, null);
monitor.waitForJobCompletion();
is.close();
} catch (PrintException | IOException e) {
e.printStackTrace();
}
}
private class JobMonitor extends PrintJobAdapter {
private boolean notify = false;
final int DATA_TRANSFERRED = 10;
final int JOB_COMPLETE = 11;
final int JOB_FAILED = 12;
final int JOB_CANCELED = 13;
final int JOB_NO_MORE_EVENTS = 14;
final int JOB_NEEDS_ATTENTION = 15;
private int status;
@Override
public void printDataTransferCompleted(PrintJobEvent pje) {
status = DATA_TRANSFERRED;
markAction();
}
@Override
public void printJobCompleted(PrintJobEvent pje) {
status = JOB_COMPLETE;
markAction();
}
@Override
public void printJobFailed(PrintJobEvent pje) {
status = JOB_FAILED;
markAction();
}
@Override
public void printJobCanceled(PrintJobEvent pje) {
status = JOB_CANCELED;
markAction();
}
@Override
public void printJobNoMoreEvents(PrintJobEvent pje) {
status = JOB_NO_MORE_EVENTS;
markAction();
}
@Override
public void printJobRequiresAttention(PrintJobEvent pje) {
status = JOB_NEEDS_ATTENTION;
markAction();
}
private void markAction() {
synchronized (JobMonitor.this) {
notify = true;
JobMonitor.this.notify();
}
}
public synchronized void waitForJobCompletion() {
Runnable runner = ()->{
boolean keepRunning = true;
while (keepRunning) {
try {
while (!notify) {
wait();
}
switch(this.status){
case DATA_TRANSFERRED:
state = "DATA_TRANSFERRED";
break;
case JOB_COMPLETE:
state = "JOB_FINISHED";
keepRunning = false;
break;
case JOB_FAILED:
state = "JOB_FAILED";
keepRunning = false;
break;
case JOB_CANCELED:
state = "JOB_CANCELED";
keepRunning = false;
break;
case JOB_NO_MORE_EVENTS:
state = "JOB_COMPLETE";
keepRunning = false;
break;
case JOB_NEEDS_ATTENTION:
state = "JOB_NEEDS_ATTENTION";
break;
}
Platform.runLater(()->statusLabel.setText(state));
delay(5000);
notify = false;
}
catch (InterruptedException e) {}
}
delay(5000);
Platform.runLater(()->statusLabel.setText(""));
};
Thread monitor = new Thread(runner);
monitor.start();
}
}
}
下面是我如何调用该类来打印和监视作业:
FileInputStream fis = new FileInputStream(docPath);
Label jobStatus = new Label(); //Already in my AnchorPane but included here for clarity
new PrintHandler(fis,jobStatus).startPrintJob();