Java高級編程:使用打印服務API – JAVA編程語言程序開發技術文章

Java自從問世以來在各方面發展迅速,但是一直以來,打印輸出是java最弱的方面。事實上,java1.0不支持任何打印功能。Java1.1在java.awt包裡包含瞭一個叫做PrintJob的類,但是這個類提供的打印功能十分粗糙和不可靠。當java1.2問世,它圍繞PrinterJob設計瞭一個完整獨立的打印機制(叫做java2D printing API),並且在java.awt.print包裡定義瞭一些新的類和接口。這些使得基於PrintJob打印機制(就是AWT printing)基本荒廢,雖然PrintJob從未被抨擊而且至少在這篇文章裡仍然是一個提供技術的類。
  在J2SE1.3裡當PrintJob的功能擴展到可以通過在java.awt包裡的JobAttributes 和PageAttributes兩個類設定工程和頁面的屬性時發生瞭一些額外的改變。隨著J2SE1.3的發佈,打印功能相應的得到瞭完善;但是在混合使用這兩種完全不同的打印機制的時候仍然存在一些問題。比如,這兩種機制使用java.awt.Graphics這個類的一個接口來展現打印內容,意味著所有要打印的東西都必須用一張圖片表示。另外,完善的PrintJob提供瞭很有限的工程相關屬性的設置;這兩種機制都沒有辦法通過程序來選擇目標打印機。
  Java打印最大的改變來自於J2SE的發佈帶來的Java打印服務API。這個第三代Java打印支持接口突破瞭先前提到的使用javax.print包的PrintService和DocPrintJob接口的局限性。因為新的API就是以前兩種舊的打印機制定義的功能函數的一個父集,它是目前我們常用的方法並且是這篇文章的焦點。
  更深入來說,以下的步驟包含瞭怎麼使用這個新的Java打印服務API:
  1.定義打印機,限制那些返回到提供你要實現功能的函數的列表。打印服務實現瞭PrintService接口.
  2.通過調用接口中定義的createPrintJob()方法創建一個打印事件,作為DocPrintJob的一個實例。
  3.創建一個實現Doc接口的類來描述你想要打印的數據 , 你也可以創建一個PrintRequestAttributeSet的實例來定義你想要的打印選項。
  4.通過DocPrintJob接口定義的printv()方法來初始化打印,指定你先前創建的Doc,指定PrintRequestAttributeSet或者設為空值。
  現在你可以檢查每一步並且試著完成它們。
  定義打印服務
  你可以使用在PrintServiceLookup類中定義的三種靜態方法中的一種來定義。最簡單的一種就是lookupDefaultPrintService(),正如它的名字一樣,它返回一個你默認的打印機:
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
  雖然用這個辦法很簡單也很方便,用它來選擇你的打印機意味著用戶的打印機一直都支持你的程序所要精確傳輸的數據輸出。實際上,你真正想要的是那種可以處理你想要的數據的類型並且可以支持你要的特征例如顏色或者兩邊打印。為瞭從列表中中返回你所要求的特殊功能支持的打印機,你可以使用剩下兩個方法中的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());
}

  例如你的系統名為PrintServer,下面有Alpha, Beta, 和
Gamma打印機,用以上代碼可以得到以下輸出:
\PrintServerAlpha
\PrintServerBeta
\PrintServerGamma

  現在查看那些你可以傳給lookupPrintServices()方法的參數來看看如何返回擁有特殊功能的打印機。
  DocFlavor
  第一個你可以指定的參數是一個DocFlavor類的實例,它描述瞭將要打印的數據的類型和數據如何存儲。在大部分情況下,並不需要去創建一個新的實例因為Java包含瞭很多預先定義的實例,使得你可以用它們來傳給lookupPrintServices()。然而,我們還是來看一下DocFlavor的結構和方法來探討打印服務如何使用這個實例。
  創建DocFlavor實例需要的兩個參數都是字符串,一個是
MIME(Multipurpose Internet Mail Extensions)類型另一個是類的名字。MIME類型被用於描述數據類型。例如,你要打印一個gif文件,你需要使用MIME類型是image/gif的DocFlavor。相類似,如果你要打印HTML文件裡的文本信息要使用MIME類型似text/plain或者text/html。

表現類
  MIME類型描述將要打印的數據的類型,表現的類則表示如何讓打印服務得到這些數據。DocFlavor包含瞭幾個靜態的內部類,每一個相對應一個表現類和如何裝載要打印得數據。
  表1中列出瞭上面提到的內部類和表現類。註意在SERVICE_FORMATTED(一會我會更詳細地解釋)旁邊,每一個和”binary”或者 “character”相對應。事實上,這些差別是人為的,因為”character”數據類型本身就是一種特殊的binary類型。這種情況下,我們說的二進制(binary)數據包括人們可以看懂的字符和一些格式化的字符比如tabs,換行回車等。當然,這些差別很重要,反映出面向字符的表現類並不適合存儲二進制數據。
  例如,你不會用字符隊列或者字符串來保存一個gif文件,你也不能通過Reader接口來訪問它。另一方面,因為字符也是一種特殊的二進制數據,它完全適合儲存文本信息到字節數組裡或者通過InputStream或者一個URL來訪問它。

image
Table 1. DocFlavor的表現類
  

上面定義的任何一個靜態內部類相對應一個表現類,但是請記住我說過每一個DocFlavor的實例通過一個表現類和一個MIME來確認要打印的數據的類型。
  要訪問這樣一個實例,你要通過表1總列出的內部類。例如,我們假設你要打印一個在網上通過URL訪問的gif文件,這樣的話,就選擇表現類是javav.net.url,對應的在DocFlavor中的靜態類就是URL類。如果你打開那個內部類的文檔,你會發現其實它定義瞭一系列靜態的內部類,每一個對應一種打印機支持的MIME類型。表2描述瞭在DocFlavor.URL裡的內部類和MIME

image
Table 2. The DocFlavor.URL inner classes

  
  因為要通過URL打印gif圖片,你可以用一下代碼來獲得實例
DocFlavor flavor = DocFlavor.URL.GIF;
  這個代碼創建瞭一個DocFlavor實例,代表類是java.net.URL,MIME是image/gif。
表2列出的瞭DocFlavor.URL的類,那麼其他六個內部類呢?我們等下來討論一下SERVICE_FORMATTED,這之前,看看與二進制數據聯系的所有三種類型(BYTE_ARRAY, INPUT_STREAM, and URL)相關的內部類。例如,如果你把gif儲存到瞭一個字節數組裡,那麼你可以用以下代碼:
DocFlavor flavor = DocFlavor.BYTE_ARRAY.GIF;
  正如有三個與二進制類型關聯的內部類一樣,與字符類型相關的另外三個類列在表3裡

image
Table 3. CHAR_ARRAY, READER, and STRING


所以,如果你想打印儲存在字符串中的文本數據,用以下代碼: DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;類似的,如果文本來自於網頁上的HTML文檔,用以下代碼:
DocFlavor flavor = DocFlavor.STRING.TEXT_HTML;
  選擇正確的打印機
  還記得我們在開始關於討論DocFlavor之前關於打印機的那個精確支持你想要打印的數據類型的假設嗎?這似乎看起來沒有必要。實際上,你會對給你的打印機所支持的文檔類型感到吃驚。例如,剛提到文本類型看起來似乎是最容易支持的,所以,如果你的程序要打印一個普通文本或者HTML文本,你可以隨便選擇一個打印服務並把它送到打印機那去。然而大部分打印機不支持基於文本的表現類,如果你試圖向打印機發送它不支持的DocFlavor,會產生下面的異常:
Exception in thread “main”
sun.print.PrintJobFlavorException: invalid flavor at sun.print.Win32PrintJob.print(Win32PrintJob.java:290) at PrintTest.main(PrintTest.java:11)

  現在你已經知道瞭如何得到一個DocFlavor的引用而且我們也討論瞭選擇支持這個flavor的打印機重要性,接下來我來告訴你如何確定你使用的打印機支持它。我先前說過lookupPrintServices()允許你指定一個DocFlavor作為第一個參數,如果你指定的參數非空,那麼方法會返回相應支持這個的打印機的實例。例如以下代碼將返回可以通過URL來打印gif文件的打印機的列表:
DocFlavor flavor = DocFlavor.URL.GIF;
PrintService[] services = PrintSer

發佈留言