程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在Java中輕松打印文檔

在Java中輕松打印文檔

編輯:關於JAVA

有關在Java中實現文檔打印的典型說法描述了一個復雜的過程,它要求對字 體進行測定、對文本進行解析並將結果繪制到一個Graphics對象中。這個過程似 乎執行起來相當困難,並且它和用於文檔視頻顯示的高級編程方法不一致。如果 你想要花費大量的精力來完成這個過程,那麼你就不會首先想到要在Java中編程 。

你一定不想自己完成測定、解析和繪制過程,而是希望通過簡單地將文檔發 送到一個能為你處理所有事情的對象中來完成這個任務。本文就將介紹這樣一個 對象――DocumentRenderer,它將一個文檔作為方法中的一個參數並處理指定任 務來完成打印。比如,用這個類來顯示一個HTML文檔需要兩個步驟:構造一個 DocumentRenderer類的實例並將HTML文檔作為參數發送到print(HTMLDocument) 方法中。DocumentRenderer類用於處理打印該文檔所必需的開銷,包括顯示一個 打印對話框以及格式化文本。

我們設計了這個DocumentRenderer類以便利用這個已經在Java中可用的高級 文本性能。 根據可重用和可擴展類的原則,我們使用了一些現有的對象 (Java.Swing.Text Package用它來對顯示結果進行格式化)使打印結果能夠顯 示在紙上。用這種方法設計DocumentRenderer使我們能夠用比前面討論過的方法 少寫近200行的代碼來建立這個類。

除了能少寫代碼之外,使用DocumentRenderer 實現中的現有對象還提供了一 些額外的功能使得該類更加通用。在最初設計這個類的時候,我們只是打算將 HTML文檔打印出來。而添加一些功能來打印其他類型的文檔則是後來的想法。當 我們發現只需在用於HTML 打印類的代碼中加上約6行的額外代碼就可以打印一個 Rich Text Format文檔時,便在這個項目的後期添加了這個功能。

顯示文檔

DocumentRenderer能夠用來打印幾類包含在JEditorPane中的文檔。我們用三 種類型的文檔(JEditorPane能夠缺省識別的)測試了這個printer類: HTMLDocuments、PlainDocuments和Rich Text Format文檔。只需要做一些很小 的改動,這個類就應該可以將包含在JEditorPane中的其他類型文檔打印出來了 。

DocumentRenderer類將一個文檔的打印形式從其視頻顯示中區分出來了。這 就使你能夠針對特定的打印結果進行文本格式化,而會不影響其屏幕顯示。 DocumentRenderer采用所有打印頁面的實際大小來顯示文本並計算出行間距 (line break)。當文檔的寬度不足以顯示在打印頁面上時,該類會允許使用縮 放(scaling)。

DocumentRenderer相當智能。分頁符不會將一行單一語句分放到兩個頁面上 。字符也不會被切成兩半,不會象浏覽器在處理一般打印時會在這一頁末尾顯示 一句話的上半部分而在下一頁的頂部顯示這句話的下半部分。這個類能夠處理大 量字體、顏色和小圖標。分欄文本的顯示也沒有問題。對於每一個JEditorPane 能夠顯示的文本特性,通常DocumentRenderer都可以將這種性能呈現到紙上。

你只需使用兩行代碼便可以將DocumentRenderer結合到你的程序中去了。用 一個不帶參數的構造器創建這個類的實例,再調用一個合適的打印方法來處理其 他事情。比如,以下代碼將打印這個htmlDocument,它是HTMLDocument類的一個 有效實例:

DocumentRenderer DocumentRenderer = new
DocumentRenderer();
DocumentRenderer.print(htmlDocument);

它給用戶顯示一個打印對話框,允許用戶選擇打印機、打印數量等,同時還 有一個取消打印的選項。

PlainDocuments使用了print(PlainDocument)方法,采用和HTMLDocuments相 同的方式執行打印。由於在Java中不能直接訪問Rich Text Format文檔,所以你 必須將這種類型的文檔發送到DocumentRenderer中(通過將它封裝到一個 JEditorPane裡),就象這樣:DocumentRenderer.print(jeditorPane);

這裡的jeditorPane是JEditorPane的一個有效實例,其中包含一個Rich Text Format文檔。

為了給用戶提供方便,你可以調用DocumentRenderer的pageDialog方法來顯 示一個打印對話框以便用戶可以調整頁面大小、頁邊設置和紙的打印方向 (orientation)。DocumentRenderer還提供了一種方法使開發人員可以選擇是 否對那些無法在打印寬度內完全顯示的文檔進行按比例縮放。我們認為能夠進行 縮放通常是比較好的選擇,因為它能夠防止文本在正確的頁邊處被分開,但它似 乎比較適合讓用戶去選擇。這種名為setScaleWidthToFit(boolean)的方法提供 了按比例縮放的選項。你必須確定在調用打印方法之前調用這個scaling和 pageDialog方法。

了解DocumentRenderer

DocumentRenderer用於執行顯示一個打印對話框並通過使用在Java Swing Printing API中可用的標准化工具開始打印操作。由於在使用這個 DocumentRenderer類時無需完全了解這個API,而且該API已經在很多地方被詳細 描述過,因此這裡我們就不再介紹它了。這個用於DocumentRenderer類的源代碼 中還包括了這個打印邏輯的完整文檔。

然而我們或許應該解釋一下DocumentRenderer用來在單獨打印頁面中定位文 本的過程,以便你了解這個類所提供的改進功能,這會幫你回顧這個Java打印過 程通常遵循的顯示文檔的邏輯。

文檔通常是以一種簡單的方式進行打印的。首先,文檔會被放入JEditorPane 。你可以將打印過程想象為在JEditorPane 的上面放置一個矩形框(其大小和頁 面打印區的大小相等),並對其中的內容進行打印而無需關心外面的部分。

這個矩形的上沿與JEditorPane 頂部齊平,矩形框內部的區域會被繪制 (paint)。如果矩形的下沿穿過文本,不用去管它;字符會在打印頁面的底部 被分開。打印第二頁時,矩形的上沿被向下移至前面被下沿所占據的那一行,該 過程被重復執行。由於第二頁正好在第一頁結束的地方開始,因此在第一頁底部 被分開的字符會出現在第二頁的頂部。後面幾頁也是一樣。

為了避免從行中斷開,DocumentRenderer會仔細檢側文檔以測定是否一個單 獨文本和頁面完整契合。這樣會比只是在JEditorPane中放一個矩形框並打印其 中內容的效果更佳。

繪制視圖(View)

如果將JEditorPane看作僅包含了一個文檔的方法,你就不能測定所有文本的 位置或大小了。一個文檔對於這個任務來說太大了,文檔或許會契合於一個單一 頁面,或許不會。為了使文檔能夠完整契合於打印紙,你必須將它分成一些小的 部分以便對每個部分的位置進行檢測。

幸運的是,Java Swing Text Package提供了一個View類,它能使你將文檔分 成單一的、適於繪制的部分。你可以將JEditorPane想象成是由幾個視圖部分組 成的;現在你就可以完全基於這些小部分的大小和位置來打印文檔了。

View類的子類用於處理可視性組件(visual component)中的顯示和打印文 本的任務。然而,處理打印文本的許多程序員沒有意識到的是視圖可以在顯示到 紙上時提供這些相同的功能。盡管對視圖問題進行詳細討論是本文以外的話題, 但在討論文檔打印時對它有一個大致的了解還是很有必要的。

在Swing中,視圖被當作處理文本顯示的容器。在樹型目錄中一個根視圖可以 有多個視圖分支。在這些分支的端部會顯示代表真實文本的葉視圖(leaf view )。

將這個視圖的樹型結構當作一個由單一的、大的、包含整個文本的視圖來考 慮。這個文檔視圖被分成幾個段落視圖,它被依次分成幾個單獨的行。盡管真實 工作中的視圖情況要比這個簡單的描述復雜的多,但該例子中顯示了如何通過視 圖來將一個文檔分成契合於打印紙的小的部分。通過查看每一行,你可以測定它 是否完全契合於打印紙而不會在底部被分開。如果行數契合,就執行打印,如果 不契合,則將它記錄下來以便在下一頁中執行打印。

包含在JEditorPane中的視圖采取了一種和在JPanel中的組件行為相類似的操 作。一個主要區別在於視圖不要求布局管理器(layout managers)來進行位置 處理;它們會自己參與布局。這樣一來,在JEditorPane中的視圖就會象一個真 實的組件和布局管理器一樣進行操作。視圖知道如何查看、如何繪制自己以及在 哪裡顯示其子文檔。

視圖並不是被直接建立的。更確切地說,它們是由ViewFactory子類的工廠( factory)來生成的。一個ViewFactory生成一個文檔並將它們分成根視圖以及所 需的分支視圖和葉視圖。工廠會按照這種方式來處理這些乏味的解析文檔和計算 布局的工作。

你很少能夠直接和這些工廠打交道。對很多部分來說,它們是被自動調用的 。在JEditorPane中設置文檔並調用JEditorPane.validate()方法來將文檔發送 的適合的工廠中,該工廠則會返回所需的視圖。然後這些視圖會被用在組件的布 局上。

打印視圖

DocumentRenderer類能夠將需要打印的文檔放入jeditorPane中,它是 JEditorPane的一個實例。jeditorPane的寬度決定了打印頁面的大小而且它會調 用一個驗證方法來執行布局。DocumentRenderer不會顯示這個JEditorPane,因 此屏幕顯示不會生效。需要被打印的根視圖是通過一個有點復雜的jeditorPane 用戶界面調用來獲得的:

View rootView =jeditorPane.getUI().getRootView(jeditorPane);

這個rootView及其子視圖可能會對所需信息進行查詢以便對打印文檔進行布 局。這些視圖在每部分文本的繪制環境(graphical context)中提供了坐標和 大小。通過這些信息你就能夠測定這部分文本是否和打印頁面相契合。如果契合 ,則DocumentRenderer將執行打印;如果不契合,該類將對這個用來打印這部分 文本而不將其分開的分頁符進行測定。

由於視圖知道如何自行繪制,因此你無需自己設置字體或顏色。 DocumentRenderer以多種字體和顏色通過調用一個簡單視圖的paint方法來處理 式樣文本(styled text)。

然而這個視圖的樹型結構也存在一個問題。你不能確定在一個代表打印文本 的葉視圖結束之前分支視圖從根視圖中被分出了幾次。你可以通過使用 DocumentRenderer 類中的一個簡單的循環方法來解決這個問題。

printView方法循環經過視圖的分支結構來查找可打印的葉視圖。這種方法將 一個視圖作為其中一個參數。它從根視圖開始對每個視圖進行檢查以測定它是否 有相關的子視圖。如果有,則printView會依次調用每個子視圖將其作為其視圖 參數。這樣一來,這個方法最終會運行至整個樹型結構。當該方法發現一個不帶 子視圖的葉視圖時,它會在用於打印的繪制環境中檢測它的位置。這個方法只用 於繪制那些完全契合於該環境的可打印部分的葉視圖。當一個葉視圖分跨 (straddle)頁面的底部時,這個方法就會記錄該頁面上沿的位置以便使下一頁 從這個位置開始。因此分頁符就不會從文本的行當中斷開了。

如果你想要更深入地了解打印視圖的用法,你可以查找DocumentRenderer類 的源代碼。我們對它進行了注釋講解。由於它只有不到200行的代碼,因此我們 有充足的時間來給它加上注釋。

該類的局限

我們在Java SDK 1.3和1.4版本中對DocumentRenderer進行過測試,盡管它應 該是適用於實現Swing的所有Java版本的。DocumentRenderer是通過標准的Java 技術來運行的,因此它不能實現比Java本身更好或更糟的文本繪制。在 JEditorPane中不能顯示的字符也將無法顯示在紙上。

Java在Windows環境下對文本進行測定時有一個小問題。由於文本沒有被精確 地測定,一些位置可能有些偏離。由於這些錯誤很小所以通常不是什麼大問題, 但它會在對文本右對齊(right-justified )時變得很麻煩。因此,要盡量避免 使用右對齊方式。DocumentRenderer類不會產生這個問題,它似乎也不會出現在 Linux環境中。

最後要說的是,大圖標是不能被打印出來的。在Java中不能將它們顯示在頁 面中,但小圖標是沒有問題的。

在Java中執行打印不再會是一個復雜的問題了。只需簡單地寫兩行代碼並通 過DocumentRenderer類來將高級的文本打印功能添加到你的程序中可以了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved