Module  java.desktop

Package javax.print.attribute

提供描述Java“打印服务”属性类型以及如何将其集合到属性集中的类和接口。

什么是属性?

设置打印作业时,客户端会指定两项内容: 打印数据处理指令。 打印数据是要打印的实际内容。 处理指令告诉打印机如何打印打印数据,例如:要使用什么媒体,要打印的副本以及是否在纸张的一面或两面进行打印。 客户端使用Java Print Service API的属性定义指定这些处理指令。

打印数据和处理指令是分开的实体。 这意味着:

  • 您可以使用不同的处理指令在不同时间打印相同的打印数据。
    例如,您可以在美国信件大小的白皮书,双面,装订,20份副本上打印幻灯片演示,以进行演讲; 并且您可以在美国信件尺寸的投影胶片上打印相同的幻灯片演示文稿,单面,一个副本,以实际演示幻灯片。
  • 您可以在不同时间使用相同的处理指令来打印不同的数据。 例如,您可以将默认处理指令设置为:美国信纸尺寸的纸张,双面,装订。 无论何时打印作业,都会使用这些设置进行打印,除非您明确地覆盖它们。

处理指令没有指定打印作业如何处理请求; 每个处理指令只是打印作业结果的描述。 打印作业确定其实现由处理指令指定的结果的方式。 将处理指令表示为描述性项目为实现打印作业提供了更多的灵活性。

属性类别和值

每个打印机都有一组功能,例如能够以不同的纸张尺寸打印,或者能够打印多个副本。 每个功能都有一系列的值。 例如,打印机的方向功能可能具有以下值的范围:[横向,纵向]。 对于每个打印请求,该功能被设置为这些值之一。 Java Print Service API使用术语属性类别来引用打印机功能和术语属性值来引用该功能的值。

在Java Print Service API中,属性类别由实现Attribute接口的Java类来表示。 属性值是这种类或其子类之一的实例。 例如,要指定份数,应用程序将构建具有所需副本数的Copies类的实例,并将Copies实例用作打印请求的一部分。 在这种情况下, Copies类表示属性类别, Copies实例表示属性值。

属性角色

当向打印机提交打印作业时,客户端提供描述打印数据特征的属性,例如文档名称以及如何打印打印数据,如双面,五份。 如果打印作业由多个打印数据组成,则不同的部分可能具有不同的处理指令,例如第一个文档的8 x 11英寸的介质,另一个文档的11 x 17英寸的介质。

一旦打印机开始处理打印作业,有关作业的其他信息就可用,其中可能包括:作业状态(如完成排队 )以及目前打印的页数。 这些信息也是属性。 属性还可以描述打印机本身,例如:打印机名称,打印机位置和排队的作业数。

Java Print Service API定义了这些不同类型的属性,其中五个子接口为Attribute

每个属性类都实现了这些标记子接口中的一个或多个,以指示API可以在哪里使用该属性。 如果属性类实现多个标记子接口,则该属性可以在多个上下文中使用。 例如,媒体属性可以应用到一个文档中的打印作业作为DocAttribute或整个打印作业为PrintRequestAttribute 某些低级属性不会自动使用,但始终会聚合到更高级别的属性中。 这些低级属性类只实现接口Attribute ,而不是任何标记子接口。

Java打印服务API定义了一组基于Internet打印协议(IPP)版本1.1中的属性建模的标准属性类。 标准属性类在子包javax.print.attribute.standard的子包中,以使实际属性类在概念上与包javax.print.attribute中定义的通用设备分开。

属性集

客户端在提交打印作业时通常需要提供多个处理指令。 例如,客户端可能需要指定A4的介质尺寸和横向。 要发送多个处理指令,客户端将属性收集到属性集中,Java Print Service API使用AttributeSet接口表示。

AttributeSet接口类似于Map接口:它提供了一个键到值的映射,其中每个键是唯一的,并且可以包含不超过一个值。 但是, AttributeSet接口旨在专门支持Java Print Service API的需求。 一个AttributeSet要求:

  1. AttributeSet每个密钥对应于一个类别,密钥的值只能是属于由密钥表示的类别的属性值之一。 因此,与Map不同, AttributeSet限制键的可能值:不能将属性类别设置为不属于该类别的属性值。
  2. 同一集合中不存在同一类别的两个属性。 例如,属性集合不能同时包含“单面”属性和“双面”属性,因为这两个属性给出打印机冲突的指令。
  3. 只有实现Attribute接口的属性才能添加到集合中。

javax.print.attribute包包含HashAttributeSet作为属性集接口的具体实现。 HashAttributeSet提供了一个基于哈希映射的属性集。 您可以使用此实现或提供您自己实现的接口AttributeSet

Java Print Service API提供了一个属性集的四个专门化,这些属性集被限制为仅包含四种属性之一,如Attribute Roles部分所述:

请注意,这里只列出了四种属性集,但有五种属性。 接口SupportedValuesAttribute表示给出另一个属性的支持值的属性。 支持值属性永远不会聚合到属性集中,因此没有为它们定义属性集子接口。

在某些情况下,属性集是只读的,这意味着只允许客户端检查属性集的内容,但不能更改它们。 在其他上下文中,属性集是读写,这意味着允许客户端检查和更改属性集的内容。 对于只读属性集,调用UnmodifiableSetException操作会引发一个UnmodifiableSetException

包javax.print.attribute包括每个属性集子接口的一个具体实现:

所有这些类都扩展了HashAttributeSet,并强制限制了属性集只允许包含相应类型的属性。

属性类设计

属性值是一个小的原子数据项,例如整数或枚举值。 由于以下原因,Java Print Service API不使用原始数据类型(如int)来表示属性值:
  • 原始数据类型不是类型安全的。 例如,编译器不应该允许“副本”属性值用于“sides”属性。
  • 某些属性必须表示为几个值的记录。 一个例子是打印机分辨率,需要两个数字,例如600和300代表600 x 300 dpi。
对于类型的安全性和均匀地表示所有属性,Java的打印服务API每个属性类别,定义为一类如类Copies ,类Sides ,和类PrinterResolution 每个属性类都包装一个或多个包含属性值的原始数据项。 属性集合操作在添加属性时,在属性类别对象之间执行频繁的比较,在同一类别中查找现有属性,并查找给定其类别的属性。 由于属性类别由类表示,所以可以使用Class.equals方法执行快速属性值比较。

即使Java Print Service API包含大量不同的属性类别,只有几种不同类型的属性值。 大多数属性可以由少量数据类型表示,例如:整数值,整数范围,文本或整数值的枚举。 类别接受的属性值的类型称为属性的抽象语法。 为了提供一致性和减少代码重复,Java Print Service API定义了抽象语法类来表示每个抽象语法,并且尽可能将这些类用作标准属性的父级。 抽象语法类是:

  • EnumSyntax提供了类型安全的枚举,枚举值被表示为单例对象。 每个枚举单例是枚举类的一个实例,它包含一个隐藏的int值。
  • IntegerSyntax是整数值属性的抽象语法。
  • TextSyntax是文本值属性的抽象语法,包括给出文本字符串自然语言的语言环境。
  • SetOfIntegerSyntax是表示范围或整数集的属性的抽象语法
  • ResolutionSyntax是表示分辨率值(例如600x300 dpi)的属性的抽象语法。
  • Size2DSyntax是表示二维尺寸的属性的抽象语法,例如纸张尺寸为8.5 x 11英寸。
  • DateTimeSyntax是值为日期和时间的属性的抽象语法。
  • URISyntax是其值为统一资源指示符的属性的抽象语法。
抽象语法类与使用它们的属性无关。 实际上,与打印无关的应用程序可以使用抽象语法类。 虽然大多数标准属性类都扩展了一个抽象语法类,但是不需要属性类来扩展这些类之一。 抽象语法类仅提供可由许多属性类共享的方便的实现。

每个属性类直接或间接地实现Attribute接口,将其标记为打印属性。 在某些上下文中可以出现在受限属性集中的属性类也实现了一个或多个子接口Attribute 大多数属性类还扩展了适当的抽象语法类来实现。 考虑Sides属性类:


 public class Sides
     extends EnumSyntax
     implements DocAttribute, PrintRequestAttribute, PrintJobAttribute
 {
     public final Object getCategory()
     {
         return Sides.class;
     }
 ...
 }
 

由于每个属性类都实现了Attribute ,所以每个属性类必须为getCategory方法提供一个实现,该方法返回属性类别。 Sides的情况下, getCategory方法返回Sides.class getCategory方法是最终确保标准属性类的任何供应商定义的子类出现在同一类别中。 每个属性对象一旦构造就是不可变的,以便可以自由地传递属性对象引用。 要获取不同的属性值,请构造不同的属性对象。

属性供应商

Java Print Service API的设计使得供应商可以:
  • javax.print.attribute.standard中定义的任何标准属性定义新的供应商特定值。
  • 定义新的属性类别,表示供应商打印机的标准属性尚未支持的专有功能。
要为属性定义新值,客户端可以在运行时使用任意值构造此类属性的实例。 然而,使用EnumSyntax的抽象语法类的枚举属性将编译时的所有可能的属性值指定为属性类的单例实例。 这意味着在运行时不能构造新的枚举值。 要为标准枚举属性定义新的供应商特定值,供应商必须定义新的属性类,指定新的单例实例。 为了确保新属性值与标准属性值属于相同的类别,新属性类必须是标准属性类的子类。

要定义一个新的属性类别,供应商定义一个新的属性类。 该属性类与标准属性类一样,实现了Attribute或其子接口之一,并扩展了一个抽象语法类。 供应商可以使用现有的抽象语法类或定义新的抽象语法类。 新的供应商定义的属性可以在使用Attribute地方使用,例如在AttributeSet

使用属性

典型的打印应用程序使用PrintRequestAttributeSet因为打印请求属性是客户端通常指定的属性类型。 此示例演示如何创建一个打印请求属性集,并定位可以根据指定的属性打印文档的打印机:

 FileInputStream psStream;
 try {
     psstream = new FileInputStream("file.ps");
 } catch (FileNotFoundException ffne) {
 }
 if (psstream == null) {
     return;
 }
 //Set the document type. See the DocFlavor documentation for
 //more information.
 DocFlavor psInFormat = DocFlavor.INPUT_STREAM.POSTSCRIPT;
 Doc myDoc = new SimpleDoc(pstream, psInFormat, null);
 PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
 aset.add(new Copies(5));
 aset.add(MediaSize.A4);
 aset.add(Sides.DUPLEX);
 PrintService[] services =
     PrintServiceLookup.lookupPrintServices(psInFormat, aset);
 if (services.length > 0) {
     DocPrintJob job = services[0].createPrintJob();
     try {
         job.print(myDoc, aset);
     } catch (PrintException pe) {}
 }
 

请注意:在javax.print API中,方法的空参考参数是不正确的,除非在方法中明确记录为具有有意义的解释。 使用相反的是错误的编码,可能会立即或稍后导致运行时异常。 IllegalArgumentException和NullPointerException是这种情况的典型和可接受的运行时间异常的示例。

从以下版本开始:
1.4