摘要
在這篇文章里,來(lái)自Pro Java Programming (Apress, June 2005)專(zhuān)家Brett Spell解釋了如何一步一步的定位打印設備,創(chuàng )建打印工程,創(chuàng )建一個(gè)Doc文檔接口的實(shí)例來(lái)描述你想要打印的數據并且初始化打印。(4500字,2005年7月25日)
Java自從問(wèn)世以來(lái)在各方面發(fā)展迅速,但是一直以來(lái),打印輸出是java最弱的方面。事實(shí)上,java1.0不支持任何打印功能。Java1.1在java.awt包里包含了一個(gè)叫做PrintJob的類(lèi),但是這個(gè)類(lèi)提供的打印功能十分粗糙和不可靠。當java1.2問(wèn)世,它圍繞PrinterJob設計了一個(gè)完整獨立的打印機制(叫做java2D printing API),并且在java.awt.print包里定義了一些新的類(lèi)和接口。這些使得基于PrintJob打印機制(就是AWT printing)基本荒廢,雖然PrintJob從未被抨擊而且至少在這篇文章里仍然是一個(gè)提供技術(shù)的類(lèi)。
在J2SE1.3里當PrintJob的功能擴展到可以通過(guò)在java.awt包里的JobAttributes 和PageAttributes兩個(gè)類(lèi)設定工程和頁(yè)面的屬性時(shí)發(fā)生了一些額外的改變。隨著(zhù)J2SE1.3的發(fā)布,打印功能相應的得到了完善;但是在混合使用這兩種完全不同的打印機制的時(shí)候仍然存在一些問(wèn)題。比如,這兩種機制使用java.awt.Graphics這個(gè)類(lèi)的一個(gè)接口來(lái)展現打印內容,意味著(zhù)所有要打印的東西都必須用一張圖片表示。另外,完善的PrintJob提供了很有限的工程相關(guān)屬性的設置;這兩種機制都沒(méi)有辦法通過(guò)程序來(lái)選擇目標打印機。
Java打印最大的改變來(lái)自于J2SE的發(fā)布帶來(lái)的Java打印服務(wù)API。這個(gè)第三代Java打印支持接口突破了先前提到的使用javax.print包的PrintService和DocPrintJob接口的局限性。因為新的API就是以前兩種舊的打印機制定義的功能函數的一個(gè)父集,它是目前我們常用的方法并且是這篇文章的焦點(diǎn)。
更深入來(lái)說(shuō),以下的步驟包含了怎么使用這個(gè)新的Java打印服務(wù)API:
1.定義打印機,限制那些返回到提供你要實(shí)現功能的函數的列表。打印服務(wù)實(shí)現了PrintService接口.
2.通過(guò)調用接口中定義的createPrintJob()方法創(chuàng )建一個(gè)打印事件,作為DocPrintJob的一個(gè)實(shí)例。
3.創(chuàng )建一個(gè)實(shí)現Doc接口的類(lèi)來(lái)描述你想要打印的數據 , 你也可以創(chuàng )建一個(gè)PrintRequestAttributeSet的實(shí)例來(lái)定義你想要的打印選項。
4.通過(guò)DocPrintJob接口定義的printv()方法來(lái)初始化打印,指定你先前創(chuàng )建的Doc,指定PrintRequestAttributeSet或者設為空值。
現在你可以檢查每一步并且試著(zhù)完成它們。
注意在這篇文章里,我將交替使用打印機和打印服務(wù),因為在大部分情況下,打印服務(wù)不亞于一臺真實(shí)的打印機。 一般的打印服務(wù)反映了理論上可以發(fā)送到不僅僅是打印機的的輸出。舉例來(lái)說(shuō),打印服務(wù)也許根本不能打印東西但是可以往磁盤(pán)上的文件寫(xiě)數據。換句話(huà)說(shuō),所有的打印機可以看成是特殊的打印服務(wù),但是并不是所有打印服務(wù)和打印機有聯(lián)系。就像你一般把你的文本送到打印機那里一樣,我有時(shí)候使用更為簡(jiǎn)便的打印機這個(gè)名詞來(lái)代替技術(shù)上更精確的打印服務(wù)。
定義打印服務(wù)你可以使用在PrintServiceLookup類(lèi)中定義的三種靜態(tài)方法中的一種來(lái)定義。最簡(jiǎn)單的一種就是lookupDefaultPrintService(),正如它的名字一樣,它返回一個(gè)你默認的打印機:
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
雖然用這個(gè)辦法很簡(jiǎn)單也很方便,用它來(lái)選擇你的打印機意味著(zhù)用戶(hù)的打印機一直都支持你的程序所要精確傳輸的數據輸出。實(shí)際上,你真正想要的是那種可以處理你想要的數據的類(lèi)型并且可以支持你要的特征例如顏色或者兩邊打印。為了從列表中中返回你所要求的特殊功能支持的打印機,你可以使用剩下兩個(gè)方法中的lookupPrintServices() 或者lookupMultiDocPrintServices()。
lookupPrintServices()方法有兩個(gè)參數:一個(gè)DocFlavor的實(shí)例和實(shí)現AttributeSet接口的實(shí)例。
你馬上將看到,你可以使用兩者中任意一個(gè)來(lái)限制返回的打印機,但是lookupPrintServices()允許你指定這兩個(gè)參數為空值。如果把兩者都設為空,那么你得到的返回值將是任意一個(gè)可用的打印機。在這種情況下,你并不需要查看PrintService中定義的方法,其中一個(gè)getName()方法返回了一個(gè)字符串,代表打印機的名字。你可以編譯下面的代碼來(lái)列出你的系統現有的打印機:
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (int i = 0; i < services.length; i++) {
System.out.println(services[i].getName());
}
例如你的系統名為PrintServer,下面有Alpha, Beta, 和Gamma 打印機,用以上代碼可以得到以下輸出:
\\PrintServer\Alpha
\\PrintServer\Beta
\\PrintServer\Gamma
現在查看那些你可以傳給lookupPrintServices()方法的參數來(lái)看看如何返回擁有特殊功能的打印機。
DocFlavor第一個(gè)你可以指定的參數是一個(gè)DocFlavor類(lèi)的實(shí)例,它描述了將要打印的數據的類(lèi)型和數據如何存儲。在大部分情況下,并不需要去創(chuàng )建一個(gè)新的實(shí)例因為Java包含了很多預先定義的實(shí)例,使得你可以用它們來(lái)傳給lookupPrintServices()。然而,我們還是來(lái)看一下DocFlavor的結構和方法來(lái)探討打印服務(wù)如何使用這個(gè)實(shí)例。
創(chuàng )建DocFlavor實(shí)例需要的兩個(gè)參數都是字符串,一個(gè)是MIME (Multipurpose Internet Mail Extensions)類(lèi)型另一個(gè)是類(lèi)的名字。MIME類(lèi)型被用于描述數據類(lèi)型。例如,你要打印一個(gè)gif文件,你需要使用MIME類(lèi)型是image/gif的DocFlavor。相類(lèi)似,如果你要打印HTML文件里的文本信息要使用MIME類(lèi)型似text/plain或者text/html。
表現類(lèi)MIME類(lèi)型描述將要打印的數據的類(lèi)型,表現的類(lèi)則表示如何讓打印服務(wù)得到這些數據。DocFlavor包含了幾個(gè)靜態(tài)的內部類(lèi),每一個(gè)相對應一個(gè)表現類(lèi)和如何裝載要打印得數據。
表1中列出了上面提到的內部類(lèi)和表現類(lèi)。注意在SERVICE_FORMATTED(一會(huì )我會(huì )更詳細地解釋?zhuān)┡赃?,每一個(gè)和"binary"或者 "character"相對應。事實(shí)上,這些差別是人為的,因為"character"數據類(lèi)型本身就是一種特殊的binary類(lèi)型。這種情況下,我們說(shuō)的二進(jìn)制(binary)數據包括人們可以看懂的字符和一些格式化的字符比如tabs,換行回車(chē)等。當然,這些差別很重要,反映出面向字符的表現類(lèi)并不適合存儲二進(jìn)制數據。
例如,你不會(huì )用字符隊列或者字符串來(lái)保存一個(gè)gif文件,你也不能通過(guò)Reader接口來(lái)訪(fǎng)問(wèn)它。另一方面,因為字符也是一種特殊的二進(jìn)制數據,它完全適合儲存文本信息到字節數組里或者通過(guò)InputStream或者一個(gè)URL來(lái)訪(fǎng)問(wèn)它。
Table 1. DocFlavor的表現類(lèi)上面定義的任何一個(gè)靜態(tài)內部類(lèi)相對應一個(gè)表現類(lèi),但是請記住我說(shuō)過(guò)每一個(gè)DocFlavor的實(shí)例通過(guò)一個(gè)表現類(lèi)和一個(gè)MIME來(lái)確認要打印的數據的類(lèi)型。
要訪(fǎng)問(wèn)這樣一個(gè)實(shí)例,你要通過(guò)表1總列出的內部類(lèi)。例如,我們假設你要打印一個(gè)在網(wǎng)上通過(guò)URL訪(fǎng)問(wèn)的gif文件,這樣的話(huà),就選擇表現類(lèi)是javav.net.url,對應的在DocFlavor中的靜態(tài)類(lèi)就是URL類(lèi)。如果你打開(kāi)那個(gè)內部類(lèi)的文檔,你會(huì )發(fā)現其實(shí)它定義了一系列靜態(tài)的內部類(lèi),每一個(gè)對應一種打印機支持的MIME類(lèi)型。表2描述了在DocFlavor.URL里的內部類(lèi)和MIME
Table 2. The DocFlavor.URL inner classes 因為要通過(guò)URL打印gif圖片,你可以用一下代碼來(lái)獲得實(shí)例
DocFlavor flavor = DocFlavor.URL.GIF;
這個(gè)代碼創(chuàng )建了一個(gè)DocFlavor實(shí)例,代表類(lèi)是java.net.URL,MIME是image/gif。
表2列出的了DocFlavor.URL的類(lèi),那么其他六個(gè)內部類(lèi)呢?我們等下來(lái)討論一下SERVICE_FORMATTED,這之前,看看與二進(jìn)制數據聯(lián)系的所有三種類(lèi)型(BYTE_ARRAY, INPUT_STREAM, and URL)相關(guān)的內部類(lèi)。例如,如果你把gif儲存到了一個(gè)字節數組里,那么你可以用以下代碼:
DocFlavor flavor = DocFlavor.BYTE_ARRAY.GIF;
正如有三個(gè)與二進(jìn)制類(lèi)型關(guān)聯(lián)的內部類(lèi)一樣,與字符類(lèi)型相關(guān)的另外三個(gè)類(lèi)列在表3里
Table 3. CHAR_ARRAY, READER, and STRING 所以,如果你想打印儲存在字符串中的文本數據,用以下代碼:
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
類(lèi)似,如果文本來(lái)自于網(wǎng)頁(yè)上的HTML文檔,用以下代碼:
DocFlavor flavor = DocFlavor.STRING.TEXT_HTML;
選擇正確的打印機還記得我們在開(kāi)始關(guān)于討論DocFlavor之前關(guān)于打印機的那個(gè)精確支持你想要打印的數據類(lèi)型的假設嗎?這似乎看起來(lái)沒(méi)有必要。實(shí)際上,你會(huì )對給你的打印機所支持的文檔類(lèi)型感到吃驚。例如,剛提到文本類(lèi)型看起來(lái)似乎是最容易支持的,所以,如果你的程序要打印一個(gè)普通文本或者HTML文本,你可以隨便選擇一個(gè)打印服務(wù)并把它送到打印機那去。然而大部分打印機不支持基于文本的表現類(lèi),如果你試圖向打印機發(fā)送它不支持的DocFlavor,會(huì )產(chǎn)生下面的異常:
Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor
at sun.print.Win32PrintJob.print(Win32PrintJob.java:290)
at PrintTest.main(PrintTest.java:11)
現在你已經(jīng)知道了如何得到一個(gè)DocFlavor的引用而且我們也討論了選擇支持這個(gè)flavor的打印機重要性,接下來(lái)我來(lái)告訴你如何確定你使用的打印機支持它。我先前說(shuō)過(guò)lookupPrintServices()允許你指定一個(gè)DocFlavor作為第一個(gè)參數,如果你指定的參數非空,那么方法會(huì )返回相應支持這個(gè)的打印機的實(shí)例。例如以下代碼將返回可以通過(guò)URL來(lái)打印gif文件的打印機的列表:
DocFlavor flavor = DocFlavor.URL.GIF;
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
另外,如果你的程序已經(jīng)獲得了打印服務(wù)的實(shí)例,而你想知道它是否支持另一種特定的flavor,你可以調用isDocFlavorSupported()方法。在下面的代碼里,將得到一個(gè)默認打印機的引用,如果不能打印gif就會(huì )出現錯誤信息:
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocFlavor flavor = DocFlavor.URL.GIF;
if (!service.isDocFlavorSupported(flavor)) {
System.err.println("The printer does not support the appropriate DocFlavor");
}
AttributeSet正如你看到的,DocFlavor描述打印數據而且可以用來(lái)確定打印服務(wù)是否支持這種數據。然而,你的程序需要選擇一個(gè)基于那些支持的元素的打印機。例如,你要打印圖片用不同的顏色來(lái)描述不同的信息,你想知道提供的服務(wù)是否支持彩色打印,如果不,那么要么禁止它使用或者要求提供一個(gè)黑白圖片。
類(lèi)似彩色打印,兩邊打印或者使用不同的定位取決于打印機本身的屬性,而javax.print.attribute包包含了許多你可以用于描述這些屬性的包和接口。其中一個(gè)接口是前面提到的lookupPrintServices()中第二個(gè)參數AttributeSet。正如你愿,它返回屬性的集合,在調用lookupPrintServices()指定一個(gè)不為空的值將返回支持這些屬性的打印服務(wù)。換句話(huà)說(shuō),如果DocFlavor和 AttributeSet都不為空,那么方法將返回那些這兩種屬性都支持的打印機
AttributeAttributeSet 是屬性的集合,一個(gè)顯而易見(jiàn)的問(wèn)題是如何指定屬性的值呢? javax.print.attribute包里同時(shí)含有一個(gè)叫Attribute的接口,你馬上可以看到通過(guò)調用add方法來(lái)給AttributeSet創(chuàng )建一個(gè)Attribute實(shí)例來(lái)獲得這個(gè)集合。在javax.print.attribute.standard包里定義了大量你將要用到的接口。在之前,你可以查看javax.print.attribute這個(gè)包里的其他接口。
屬性模塊目前為止,我們把屬性描述成打印服務(wù)的功能,而實(shí)際上在java支持的屬性中算很簡(jiǎn)單的。對應每個(gè)屬性,java都有相應的模塊。只有遵循這些模塊屬性才有效。在不同的java打印服務(wù)位置使用不同的屬性,而不是所有的屬性在任何地方都適用。
為了更好的理解這個(gè),來(lái)看一下javax.print.attribute.standard 包里定義的
OrientationRequested和 ColorSupported接口。創(chuàng )建一個(gè)新的打印文檔時(shí)可以指定OrientationRequested屬性和用于打印的定位。ColorSupported在你調用PrintService接口的getAttributes方法時(shí)返回。OrientationRequested是一個(gè)你用來(lái)傳給打印機的屬性,而ColorSupported是打印服務(wù)用來(lái)提供給你關(guān)于打印機能力信息的工具。你可以在創(chuàng )建打印文檔時(shí)把ColorSupported作為屬性指定,因為打印機是否支持彩色打印是你的程序不能控制的。
接口和繼承你第一次查看javax.print.attribute包里的接口和類(lèi)時(shí)你也許會(huì )感到選擇那些列表里的接口和類(lèi)很麻煩。除了Attribute 和AttributeSet和繼承AttributeSet的HashAttributeSet,javax.print.attribute包里有4個(gè)子接口和類(lèi),列出在表4和圖1中。
Table 4. javax.print.attribute 里定義的接口和類(lèi)
Figure 1. javax.print.attribute 包的一部分類(lèi)的層次結構.
那么有了Attribute, AttributeSet, 和 HashAttributeSet為什么需要使用這些不同的接口和繼承類(lèi)呢?是因為這些特殊的類(lèi)是為那些特殊的屬性量身定做的。比方說(shuō),我提到過(guò)當你創(chuàng )建打印文檔的時(shí)候有個(gè)地方可以使用的屬性例如ColorSupported在那里不能使用。當創(chuàng )建這樣的文檔,你可以使用DocAttributeSet接口(或者更專(zhuān)業(yè)一點(diǎn),HashDocAttributeSet這個(gè)繼承的類(lèi)),這個(gè)繼承類(lèi)只允許你添加繼承DocAttribute這個(gè)接口的屬性。這四種不同的模塊如下:
 Doc: 在創(chuàng )建文檔時(shí)指 定如何打印文檔
 PrintJob: 打印任務(wù)的屬性描述任務(wù)的狀態(tài)
 PrintRequest: 初始化打印時(shí)傳給任務(wù)的請求
 PrintService:由打印服 務(wù)返回來(lái)描述打印機的功能
要知道如何工作,我們來(lái)創(chuàng )建一個(gè)DocAttributeSet的實(shí)例然后為AttributeSet設置DocAttributeSet和OrientationRequested屬性。HashDocAttributeSet定義了很好的結構,所有你可以很簡(jiǎn)便的如下創(chuàng )建實(shí)例:
DocAttributeSet attrs = new HashDocAttributeSet();
現在你已經(jīng)創(chuàng )建了AttributeSet,你可以調用add方法并把它傳給Attribute的繼承實(shí)例去。如果你看了OrientationRequested這個(gè)類(lèi)的文檔,你會(huì )發(fā)現它包含了一系列靜態(tài)的OrientationRequest實(shí)例,每一個(gè)對應一種文檔定位方式。要指定你想要的類(lèi)型,你所要做的只是按下面的方法傳給add方法一個(gè)靜態(tài)的實(shí)例的引用:
DocAttributeSet attrs = new HashDocAttributeSet();
attrs.add(OrientationRequested.PORTRAIT);
ColorSupported類(lèi)有一點(diǎn)不同但一樣很簡(jiǎn)單,它定義了兩種靜態(tài)實(shí)例:一個(gè)表示支持彩色打印另一個(gè)不是。你可以試著(zhù)增加一個(gè)ColorSupported屬性到DocAttributeSet去,代碼如下:
DocAttributeSet attrs = new HashDocAttributeSet();
attrs.add(OrientationRequested.PORTRAIT);
attrs.add(ColorSupported.SUPPORTED);
早先提過(guò),去指定是否支持彩色打印不恰當因為這不是程序所能控制的內容。換句話(huà)說(shuō),ColorSupported這個(gè)屬性放到一系列文檔屬性中并不合適,所以,運行先前的代碼當添加ColorSupported屬性時(shí)會(huì )拋出一個(gè)ClassCastException異常。
要學(xué)習怎么運行,記住每一個(gè)AttributeSet子接口都有一個(gè)相應Attribute子接口和繼承子類(lèi)。當添加一個(gè)屬性時(shí),繼承的子類(lèi)試圖把Attribute作為參數給相應的子接口,這樣來(lái)確保只有當前適當的屬性會(huì )成功添加。
這樣的話(huà),HashDocAttributeSet 的add方法第一次和OrientationRequested的一個(gè)實(shí)例一起調用,并成功的把它作為一個(gè)object傳給DocAttribute。因為如圖2所示,OrientationRequested繼承了那個(gè)接口。與之相對應,傳ColorSupported實(shí)例的時(shí)候因為沒(méi)有繼承DocAttribute所以失敗了。
Figure 2. javax.print.attribute 包的一部分類(lèi)的層次結構
這個(gè)例子舉例說(shuō)明,表4里的四個(gè)接口和類(lèi)組來(lái)保證使用正確的屬性。注意模塊和不同的屬性之間有大量的交互,所以很多屬性與不止一個(gè)模塊關(guān)聯(lián)。例如,許多屬性繼承了PrintJobAttribute 和 PrintRequestAttribute因為大部分是通過(guò)一個(gè)相關(guān)的打印任務(wù)獲得提供給你的。你可以在初始化時(shí)指定它們。舉個(gè)例子,你可以把它加到PrintRequestAttributeSet中去來(lái)指定任務(wù)名,并且在打印的時(shí)候通過(guò)PrintJobAttributeSet來(lái)返回它。因此,JobName屬性類(lèi)同時(shí)繼承
PrintRequestAttribute 和 PrintJobAttribute。
AttributeSet and HashAttributeSet
你已經(jīng)知道了為什么會(huì )有四個(gè)子類(lèi),但是AttributeSet接口和HashAttributeSet父類(lèi)又是什么呢?AttributeSet/HashAttributeSet在你不能確定要存儲在這個(gè)集合中的那些僅僅和一個(gè)模塊相關(guān)的屬性時(shí)使用。記得我以前提到的lookupPrintServices()方法允許你指定AttributeSet參數來(lái)限制返回的打印服務(wù)。表面上看來(lái)最好指定PrintServiceAttributeSet的實(shí)例,但是很多你可能用到的屬性并不繼承PrintServiceAttribute。
我們假設你想要讓lookupPrintServices()方法返回支持彩色打印和風(fēng)景畫(huà)打印的打印機。這些屬性與ColorSupported和OrientationRequested屬性關(guān)聯(lián),但是請注意這些類(lèi)并不共享模塊,前者是一個(gè)PrintServiceAttribute而OrientationRequested與另外三個(gè)模塊(Doc, PrintRequest,和 PrintJob)關(guān)聯(lián)。這意味著(zhù)不存在單個(gè)的AttributeSet接口或類(lèi)來(lái)同時(shí)包含ColorSupported和Sides屬性。
創(chuàng )建AttributeSet的方法使用一個(gè)HashAttributeSet實(shí)例同時(shí)包含一個(gè)OrientationRequested 和 ColorSupported太簡(jiǎn)單了。不像它的子類(lèi),它并不限制你往上加特殊的屬性,所以可以用以下代碼成功執行:
AttributeSet attrs = new HashAttributeSet();
attrs.add(ColorSupported.SUPPORTED);
attrs.add(OrientationRequested.LANDSCAPE);
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, attrs);
通過(guò)用戶(hù)界面的打印機選擇就此觀(guān)點(diǎn)而言,我認為使用的打印機應該由應用程序計劃選擇。但操作過(guò)程中,打印輸出內容時(shí)往往會(huì )顯示一個(gè)對話(huà)框讓用戶(hù)選擇。幸運的是,Java通過(guò)使用ServiceUI類(lèi)(在javax.print包中定義)中的靜態(tài)printDialog()方法使得這些操作簡(jiǎn)單化。
在顯示的對話(huà)框旁邊,僅在調用printDialog()時(shí)必須指定的參數值如下:
用戶(hù)可選用的PrintService實(shí)例數組。
默認的PrintService。
PrintRequestAttributeSet實(shí)例。這用來(lái)彈出顯示的對話(huà)框,并在對話(huà)框消失之前返回用戶(hù)所作的任何更改。
要解釋這些如何運作,可使用下列簡(jiǎn)單的代碼段來(lái)顯示打印對話(huà):
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
PrintService svc = PrintServiceLookup.lookupDefaultPrintService();
PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
PrintService selection = ServiceUI.printDialog(
null, 100, 100, services, svc, null, attrs);
運行時(shí),代碼產(chǎn)生如圖例3中所示的對話(huà)框
Figure 3. The printer dialog
隨著(zhù)代碼的說(shuō)明,從printDialog()方法返回的值是一個(gè)PrintService實(shí)例,識別用戶(hù)所選的打印機,或在用戶(hù)取消打印機對話(huà)時(shí)識別為空。此外,PrintRequestAttributeSet已更新到可通過(guò)對話(huà)框來(lái)反映用戶(hù)作出的更改,比如要打印的份數。
通過(guò)使用printDialog()方法,可讓用戶(hù)選擇其輸出要發(fā)往的打印機,提供用戶(hù)對于專(zhuān)業(yè)應用程序的期望功能。
創(chuàng )建打印任務(wù)這是打印中的一個(gè)簡(jiǎn)單步驟;因為一旦獲得PrintService的一個(gè)參考,你需要做的就是調用createPrintJob()方法,如:
PrintService service;
.
.
.
DocPrintJob job = service.createPrintJob();
代碼中顯示,從createPrintJob()返回的值是一個(gè)DocPrintJob實(shí)例,可讓您控制并監控打印操作的狀態(tài)。要啟動(dòng)打印,您會(huì )調用DocPrintJob對象的print()方法,但是,這之前,您需要定義待打印的文檔或選用PrintRequestAttributeSe。您已經(jīng)知道如何構造并彈出AttributeSet,這個(gè)步驟不再重復,接下來(lái),您將了解定義待打印的文檔。
定義要打印的文檔接下來(lái)這一步是定義要打印的文檔,用一個(gè)在javax.print包里的Doc的接口實(shí)例來(lái)創(chuàng )建。每一個(gè)Doc的實(shí)例有兩個(gè)必須定義的屬性和一個(gè)可選擇的屬性:
 Object 代表要打印的內容
 DocFlavor的一個(gè)實(shí)例描述數據類(lèi)型
 可選的DocAttributeSet 包含打印時(shí)的屬性
復習Doc接口的文檔可以看出javax.print包里包含了一個(gè)叫SimpleDoc 的接口的繼承,它的構造函數包含了上面三個(gè)參數。要知道如何構建SimpleDoc 的實(shí)例,我們假設你要打印兩份存在http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif的gif文件拷貝。
我們要做的就是構建一個(gè)SimpleDoc實(shí)例來(lái)描述這個(gè)文檔創(chuàng )建了一個(gè)URL來(lái)指向圖片,并且引用了DocFlavor,并把這兩個(gè)傳給SimpleDoc構造函數:
URL url = new URL(
"http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif");
DocFlavor flavor = DocFlavor.URL.GIF;
SimpleDoc doc = new SimpleDoc(url, flavor, null);
啟動(dòng)打印打印的最后一個(gè)步驟就是調用DocPrintJob的 print()方法,傳遞待打印數據的Doc對象,或選用PrintRequestAttributeSet實(shí)例。為簡(jiǎn)單起見(jiàn),假設默認打印機支持你所需要的flavor和屬性,在此情況下要使用下列代碼將上一個(gè)例子提及的gif文件打印兩份:
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = service.createPrintJob();
URL url = new URL(
"http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif ");
DocFlavor flavor = DocFlavor.URL.GIF;
Doc doc = new SimpleDoc(url, flavor, null);
PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
attrs.add(new Copies(2));
job.print(doc, attrs)
;
注意,一些情況下,打印不同步執行,這可能會(huì )在實(shí)際打印完成之前返回對print()的調用。
關(guān)于作者
Brett Spell是一個(gè)Frito-Lay的高級程序開(kāi)發(fā)者并寫(xiě)了Pro Java Programming 的初始版本。
資源
這是Pro Java Programming, Second Edition, Brett Spell (Apress, June 2005; ISBN: 1590594746):第十章“打印”的一部分 http://www.apress.com/book/bookDisplay.html?bID=421
要得到更多關(guān)于java API的文章,點(diǎn)擊以下鏈接
http://www.javaworld.com/channel_content/jw-apis-index.shtml