John Zukowski(jaz@zukowski.net) 总裁,JZ Ventures 公司 2002 年 3 月
从版本 1.1 以后,好像 Java 平台的每个新发行版都更改了平台的打印支持框架。Merlin 也不例外。在这个月的
Merlin 的魔力中,John Zukowski 开始分两部分对最新功能进行讨论。请单击文章顶部或底部的
讨论在
讨论论坛与作者和其他读者分享您对本文的心得。
如果您已经使用过一段时间 Java 平台,您可能会象我一样因打印 API 的无休止更改而感到沮丧。Merlin 已经为 Java 平台带来了另一套打印功能和技术。这个被称为“Java 打印服务 API”(Java Print Service API)的最新的再版从 1999 起就已经应用于 Java Community Process 了。幸运的是,新 API 是积极的补充,应该在一段时间里代表对打印支持的最终重要修改。 使用新的“打印服务 API”进行打印的过程包括三部分:发现、规范和打印。第四部分是当打印任务有进展时进行通知,这部分是可选的。本文中将用到的所有类和接口都在 javax.print 包,或者它的其中一个子包中(请参阅参考资料)。 定位一台打印机 执行打印作业的第一步是识别您想用来打印的一个或一组打印机。打印机对象被称为打印服务,识别过程被称为查找。支持查找任务的类被恰如其分地命名为 PrintServiceLookup 。要查找打印服务,您需要使用清单 1 中所示的三个方法的其中之一。 清单 1. 查找一个打印服务
public static final PrintService
lookupDefaultPrintService()
public static final PrintService[]
lookupPrintServices(DocFlavor flavor, AttributeSet attributes)
public static final MultiDocPrintService[]
lookupMultiDocPrintServices(DocFlavor[] flavors,
AttributeSet attributes)
| 清单 1 中所示的这三个方法中的每一个都被用于不同的任务:
lookupDefaultPrintService() 返回缺省的打印服务。
lookupPrintServices() 返回支持打印特定文档类型(比如 GIF)的打印机集,和一个特定的属性集(比如双面打印)。
lookupMultiDocPrintServices() 支持一次打印多个文档。 定位了自己想使用的打印服务后,您需要创建一个打印作业。 稍后,您将向这个作业发送输出。查找过程返回的 PrintService 可以用其 createPrintJob() 方法创建作业,如下所示:
PrintService printService =
PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = printService.createPrintJob();
| 指定输出格式 除了指定要打印到什么地方之外,您还必须指定打印文档的格式。这时,使用 DocFlavor 类(或它的其中一个子类)就很方便。DocFlavor 类被用于识别您要打印的对象的 MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)类型。MIME 类型描述应该如何解释电子数据。在处理电子邮件和附件时,您可能已经遇到过 MIME 类型,但 MIME 规范描述了识别数据格式的更通用的机制。 Merlin 提供了 DocFlavor 的七个子类,作为它自身用来定义格式的内部类。这些类可以分为三个 MIME 类型子集:面向字节的、面向字符的和面向服务的。面向字节的风格有:
BYTE_ARRAY INPUT_STREAM URL 面向字符的有:
面向服务的内部类是 SERVICE_FORMATTED 。 内部类中的内部类 每种风格类型支持它自己的 MIME 类型集。这些 MIME 类型也被定义为内部类。有 19 种面向字节的风格,如下所示:
AUTOSENSE GIF JPEG PCL PDF PNG POSTSCRIPT TEXT_HTML_HOST TEXT_HTML_US_ASCII TEXT_HTML_UTF_16 TEXT_HTML_UTF_16BE TEXT_HTML_UTF_16LE TEXT_HTML_UTF_8 TEXT_PLAIN_HOST TEXT_PLAIN_US_ASCII TEXT_PLAIN_UTF_16 TEXT_PLAIN_UTF_16BE TEXT_PLAIN_UTF_16LE TEXT_PLAIN_UTF_8 面向字符的流比较单调,只提供两种格式:
面向服务的流包含三种格式:
PAGEABLE PRINTABLE RENDERABLE_IMAGE 您可以象下面这样配置风格(在这个示例中,将其配置为 PNG 图像):
DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
| 指定打印属性 打印时,您可以指定一些属性来描述您想如何打印文档。示例属性包括副本数目、要打印哪一页和文档图像类型(例如横向和纵向)。要指定属性,您需要使用下面两个类的其中之一:
DocAttributeSet 为单个文档指定特性。 PrintRequestAttributeSet 指定单个打印作业的特性。 要为打印运行指定属性,您需要创建一个适当的属性集(DocAttributeSet 或 PrintRequestAttributeSet )的实例并用您期望的打印运行属性填充它。对于未指定的那些属性,还要为其配置合理的缺省值。javax.print.attribute 包拥有大约 70 个不同的属性,每个属性都被定义为单独的类。每个属性都使用一个或多个属性集。除本文中描述的两个属性集外,另外还有两个属性集可用于查询信息。javax.print.attribute 包提供一个公共空间用来查找所有的类型。 下面我们将看到一个打印运行,它使用 PrintRequestAttributeSet 并把对象打印五份:
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new Copies(5));
| 请务必看一下 javax.print.attribute 包中所有可用属性的列表。 设置内容
Doc 接口为打印作业提供数据。该接口的实现者是 SimpleDoc 类。使用一个构造函数,提供内容作为第一个参数,风格作为第二个参数,属性作为第三个参数。该构造函数如下所示:
public SimpleDoc(Object printData, DocFlavor flavor,
DocAttributeSet attributes)
| 这就为我们留下了数据问题。答案取决于 DocFlavor。如果您指定了 DocFlavor.INPUT_STREAM 这种风格,那么数据将由它的 InputStream 识别。如果您的风格是 DocFlavor.BYTE_ARRAY ,那么数据就是一个字节数组(byte [ ] )。 所以,要打印 PNG 图像文件,您需要使用清单 2 中所示的语法。 清单 2. 设置内容
DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
String filename = ...;
FileInputStream fis = new FileInputSteam(filename);
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
| 打印 一旦您识别了打印机,并指定了输出格式、属性和内容,那么只要打印一下就行了。实际的打印作业是通过 DocPrintJob (是从 PrintService 检索到的)的 print() 来执行,如清单 3 所示。 清单 3. 一个打印作业
DocPrintJob job = ...;
PrintRequestAttributeSet pras = ...;
Doc doc = ...;
job.print(doc, pras);
| 通过调用 print() ,您触发了一个机制,该机制在一个单独的线程中向打印服务发送内容。 打印机对话框 很明显,目前为止我们还没有提到打印对话框。该对话框是由系统弹出的,允许您通过图形方式配置打印机属性。图 1 显示新“Java 打印服务 API”的打印对话框。 图 1. 打印机对话框
有趣的是,打印机对话框的缺省行为已经用新的 API 更改了:缺省情况下对话框不显示。所以我们必须使用 ServiceUI 类创建如上面所示的打印对话框。 ServiceUI 类提供一个单独的方法来显示打印机选择对话框:
printDialog(GraphicsConfiguration gc, int x, int y,
PrintService[] services, PrintService defaultService,
DocFlavor flavor, PrintRequestAttributeSet attributes)
| 然后您使用返回的 PrintService 获取打印要用的 DocPrintJob ,如清单 4 所示。 清单 4. 使用对话框打印
String filename = ...;
PrintRequestAttributeSet pras = ...;
DocFlavor flavor = ...;
PrintService printService[] =
PrintServiceLookup.lookupPrintServices(flavor, pras);
PrintService defaultService =
PrintServiceLookup.lookupDefaultPrintService();
PrintService service = ServiceUI.printDialog(null, 200, 200,
printService, defaultService, flavor, pras);
if (service != null) {
DocPrintJob job = service.createPrintJob();
FileInputStream fis = new FileInputStream(filename);
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
job.print(doc, pras);
}
| 一个可运行的示例 我们将以一个可运行的示例结束本文,该示例将让您试验新的“打印服务 API”的功能。下面的代码本质上是由先前所有的代码示例组合而成的一个可运行程序。运行该程序时,请确保在命令行上输入了 PNG 图像文件的名称。如果您更倾向于打印一种不同的格式,只需更改 DocFlavor 即可。 清单 5. 一个打印示例
import javax.print.*;
import javax.print.attribute.*;
import java.io.*;
public class Printing {
public static void main(String args[]) throws Exception {
String filename = args[0];
PrintRequestAttributeSet pras =
new HashPrintRequestAttributeSet();
DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
PrintService printService[] =
PrintServiceLookup.lookupPrintServices(flavor, pras);
PrintService defaultService =
PrintServiceLookup.lookupDefaultPrintService();
PrintService service = ServiceUI.printDialog(null, 200, 200,
printService, defaultService, flavor, pras);
if (service != null) {
DocPrintJob job = service.createPrintJob();
FileInputStream fis = new FileInputStream(filename);
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
job.print(doc, pras);
Thread.sleep(10000);
}
System.exit(0);
}
}
| 在 Merlin 的魔力的下一部分,您将了解如何打印屏幕或组件的内容。我们还将讨论与打印相关的事件处理任务,并且,我还将向您展示如何从打印操作中除去 sleep() 调用。 参考资料
|