Java 高级 编程: 打印
Java Pro Programming: Printing
学习如何使用打印服务 API
摘要
从较高层次上来看,使用 Java 打印服务 API 的步骤是很简单的:
1. 定位打印服务(打印机) ,可以限制返回的列表,只要那些符合您应用程序需要的打
印机。打印服务由 PrintService 的实例体现。
2. 通过调用 PrintService 接口中定义的 createPrintJob() 方法创建一个打印任务。 打印
任务由 DocPrintJob 的一个实例代表。
3. 创建一个 Doc 接口的实现,来描述你想要打印的数据。你也可以创建一个
PrintRequestAttributeSet 的实例,来定义你想要的打印选项。
4. 通过 DocPrintJob 接口定义的 print() 方法来初始化打印,指定你先前创建的 Doc,
指定 PrintRequestAttributeSet 或者空值。
现在你可以检查每一步,并试着完成它们。
3
注意
在这篇文章里,我将交替使用打印机和打印服务,因为在大部
分情况下,打印服务不亚于一台物理的打印机。 更一般意义上
的打印服务反映了理论上可以发送到打印机以外的输出。举例
来说,打印服务可能根本不打印东西,而是写入磁盘上的文件。
换句话说,所有的打印机要表示为打印服务,但是并不是所有
打印服务必须和一台物理的打印机关联。尽管如此,实际上你
通常会把你的内容到打印机,这就是我为什么有时候使用更为
简便的打印机这个词,来代替技术上更精确的打印服务。
1.定义打印服务
Locating print services
你可以使用在 PrintServiceLookup 类中定义的三种静态方法中的一种来定义。 最简单的
一种就是 lookupDefaultPrintService(),正如它的名字一样,它返回一个服务指向您默认的
打印机:
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
虽然用这个办法简单而方便,用它来选择输出所需的打印机,意味着你默认了用户缺省
的打印机的功能,总是满足正确输出您所需的程序数据。实际上,你通常想要选择的是那种
可以处理您的数据类型,并可以符合您的应用所需特性,例如彩色或者两面打印。为了从列
表中返回所有已定义的打印机序列, 或满足您需要功能的打印机序列, 您可以使用余下两个
在 PrintServiceLookup 中定义的静态方法,即 lookupPrintServices()或
lookupMultiDocPrintServices()。
lookupPrintServices()方法接受两个参数:一个 DocFlavor 的实例和一个实现
AttributeSet 接口的对象。你马上将看到,你可以使用两者中任意一个或同时来限制返回的
打印机列表,但是 lookupPrintServices()允许你指定这两个参数中的任意一个或同时空值。
如果把两者都设为空, 那么你实际要求得到的返回值将是所有可用的打印机列表。 截止目前
为止, 你还没有真正地查看过 PrintService 中定义的方法, 其中一个 getName() 方法返回了
一个代表打印机的名字的字符串。 你可以通过编译和执行下面的代码, 来列出你的系统可用
[
PrintService[ ] services = PrintServiceLookup.lookupPrintServices(null, null);
for (int i = 0; i < services.length; i++) {
;
System.out.println(services[i].getName());
}
4
例如, 你能访问到连接在名为 PrintServer 服务器上的 Alpha, Beta 和 Gamma 打印机,
用以上代码可以得到以下输出:
\PrintServerAlpha
\PrintServerBeta
\PrintServerGamma
现在让我们来查看那些你可以传给 lookupPrintServices()方法的参数,并观察如何返回拥有
特殊功能的打印机。
2.DocFlavor
在调用 lookupPrintService()方法时, 第一个你可以指定的参数是一个 DocFlavor 类的实
例,它描述了将要打印的数据的类型和如何存储。在大部分情况下,并不需要您去创建一个
新的实例因为 Java 包含了很多预先定义的实例,你只要简单地传递其中一个实例的引用给
lookupPrintServices()。尽管(事情通常都是这样地简单) ,我们还是来看一下 DocFlavor 的
构造和方法,来理解打印服务如何使用这个实例。
创建 DocFlavor 实例需要的两个参数都是字符串, 一个是 MIME (Multipurpose Internet
Mail Extensions)类型,另一个是表现类的名字。MIME 类型被 DocFlavor 用于描述数据类
型。例如,你要打印一个 gif 文件,你需要使用 MIME 类型是 image/gif 的 DocFlavor。类
似地, 如果打印文本, 你可能要用 text/plain, 或者是打印 HTML 文档, 你则要用 text/html。
3.表现类
Representation class
MIME 类型描述将要打印数据的类型,表现类则表示这些数据如何处理并交付打印服
务。DocFlavor 包含了七个静态的内部类,每一个对应一个表现类及不同的封装方法。
5
表 1 中列出了 DocFlavor 中定义的静态内部类的名称,及想对应的表现类。注意除了
SERVICE_FORMATTED(一会我会更详细地解释) ,每一个类都说明了和binary或
character相对应。事实上,这些差别是人为的,因为character数据类型本身就是一种特
殊的 binary 类型。这种情况下,我们说的二进制(binary)数据包括人们可以看懂的字符
以及一些格式化的字符比如 tabs,回车,等等。当然,这些差别很重要,反映出面向字符的
表现类并不适合存储二进制打印数据。
例如,你不会将一个表现为 gif 图片的东西存储到字符数组或者 String 对象中,同时也
不会通过实现一个 Reader 接口来访问它。另一方面,因为字符数据也是一种特殊的二进制
数据,它完全适合储存文本信息到字节数组里或者通过 InputStream 或者一个 URL 来访问
它。
Table 1. DocFlavor 的表现类
在 DocFlavor 中定义的每一个静态内部类对应一个表现类,但是请记住我说过,每一个
DocFlavor 的实例封装了一个表现类和一个 MIME 来确认要打印的数据的类型。要访问这
样一个 DocFlavor 实例,其不仅与表现类,并且与你想要打印的内容的 MIME 类型相关,
你需要参考表 1 列出的一个内部类。例如,我们假设你要打印一个能在网上通过 URL 访问
的 gif 文件。这里,显然的表现类选择是 java.net.URL,在 DocFlavor 中对应的静态类就是
URL 类。如果你查看那个内部类的文档,你会发现其实它定义了一系列静态的内部类,每
一个对应一种打印机普遍支持的 MIME 类型。表 2 描述了在 DocFlavor.URL 里的内部类极
其对应的 MIM