目次||次

第7章

印刷

アプリケーションでは、Java印刷APIを使って次の処理が可能です。

  • AWTとJava 2Dのすべてのグラフィックスを印刷する。合成されたグラフィックスおよびイメージを含む。
  • ソフト丁合い、逆順印刷、ブックレット印刷など、文書編成機能の制御。
  • 両面印刷やホッチキス留めなど、プリンタ固有の機能の実行。
  • WindowsやSolarisなど、すべてのプラットフォームでの印刷。コンピュータに直接接続されているプリンタだけでなく、ネットワーク印刷プロトコルを使ってプラットフォームのソフトウェアからアクセスできるプリンタを含む。

7.1 インタフェースとクラス

インタフェース
説明
Printable
Printableインタフェースは、ページ・ペインタごとに実装されます。ページ・ペインタは、印刷システムがページをレンダリングするために呼び出すアプリケーション・クラスです。システムは、ページ・ペインタのprintメソッドを呼び出し、ページのレンダリングを要求します。
Pageable
Pageableインタフェースは、印刷システムで印刷されるドキュメントが実装します。システムは、Pageableのメソッド群を使って、ドキュメントのページ数、各ページで使われる書式、および各ページのレンダリングに使うページ・ペインタを判断できます。
PrinterGraphics
ページをレンダリングするためにページ・ペインタが使うGraphics2Dオブジェクトは、PrinterGraphicsインタフェースを実装します。これにより、アプリケーションは、印刷を制御するPrinterJobオブジェクトを取得できます。
クラス
説明
Book
インタフェース: Pageable
ページごとに異なるページ書式とページ・ペインタを使用できるドキュメントを表します。このクラスは、Pageableインタフェースを使って、PrinterJobと対話します。
PageFormat
印刷するページのサイズと向き、および印刷に使うPaperを記述します。たとえば、用紙の向きのは、PageFormatで表されます。
Paper
1枚の用紙の物理的特性を記述します。
PrinterJob
印刷を制御する重要なクラスです。アプリケーションは、PrinterJobのメソッド群を呼び出し、ジョブのセット・アップ、ユーザーへの印刷ダイアログの表示(オプション)、ジョブの中でのページの印刷などを行います。

7.2 印刷のコンセプト

Java印刷APIは、コールバック印刷モデルに基づいています。このモデルでは、アプリケーションではなく印刷システムが、ページを印刷するときの制御を行います。アプリケーションは、印刷するドキュメントについての情報を提供し、印刷システムは、各ページのレンダリングが必要になると、それをアプリケーションに要求します。

印刷システムは、特定のページのレンダリングを2回以上要求したり、実際とは異なる順序でページのレンダリングを要求したりする場合があります。印刷システムからどのページが要求されても、アプリケーションは正しいページ・イメージを生成できなければなりません。この点、印刷システムはウィンドウ・ツールキットと似ています。ウィンドウ・ツールキットは、いつでも、どのような順序でも、コンポーネントに再描画を要求できます。

コールバック印刷モデルは、従来のアプリケーション駆動の印刷モデルよりも柔軟性があり、より広範なシステムとプリンタでの印刷に対応しています。たとえば、逆の順序で出力ページがスタックされるプリンタの場合、印刷システムはアプリケーションに逆の順序でページを生成するように要求することで最終のスタックを正しい読取り順序にすることができます。

このモデルを使用するアプリケーションは、十分なメモリーまたはディスク領域がないためページ全体のビットマップをバッファリングできないコンピュータからでも、ビットマップ・プリンタに印刷できます。この場合、ページは一連の小さなビットマップ、つまりバンドとして印刷されます。たとえば、1ページの10分の1をバッファリングできるだけのメモリーしか利用できない場合、ページは10個のバンドに分割されます。印刷システムは、アプリケーションに対し、ページごとにレンダリングを10回要求し、1回で1つのバンドを埋めます。アプリケーションは、バンドの数またはサイズを意識する必要はありません。要求されたときにそのページをレンダリングできれば十分です。

7.2.1 印刷のサポート

アプリケーションは、印刷機能をサポートするために、次の2つのタスクを行う必要があります。

  • ジョブ制御 - 印刷ジョブの起動と管理。
  • イメージング - 印刷システムから要求された各ページのレンダリング。

7.2.1.1 ジョブの制御

ユーザーは通常、アプリケーションのボタンをクリックしたりメニュー項目を選択したりして、印刷を開始します。ユーザーが印刷操作を起動すると、アプリケーションは、PrinterJobオブジェクトを作成し、それを使って印刷処理を管理します。

アプリケーションは、印刷ジョブを設定し、ユーザーに対して印刷ダイアログを表示し、印刷処理を開始します。

7.2.1.2 イメージング

ドキュメントを印刷する場合、アプリケーションは印刷システムからの要求に対して各ページをレンダリングする必要があります。このメカニズムをサポートするため、アプリケーションは、Printableインタフェースを実装したページ・ペインタを提供します。印刷システムでページのレンダリングが必要になると、印刷システムはページ・ペインタのprintメソッドを呼び出します。

ページ・ペインタのprintメソッドが呼び出されると、メソッドにはページ・イメージのレンダリングに使うGraphicsコンテキストが渡されます。また、ページの幾何学的レイアウトを指定するPageFormatオブジェクトと、印刷ジョブ内でのページの順番を示す整数のページ・インデックスも渡されます。

印刷システムは、GraphicsGraphics2Dの両方のレンダリングをサポートしています。Java 2DのShapeTextおよびImageを印刷するには、printメソッドに渡すGraphicsオブジェクトをGraphics2Dにキャストします。

ページによって異なるページ・ペインタと書式を使用するドキュメントを印刷するには、ページング可能(Pageable)ジョブを使用します。Pageableジョブを作成するには、Bookクラスを使用するか、またはPageableインタフェースの独自の実装を使用します。単純な印刷操作を実装する場合は、Pageable印刷ジョブを使用する必要はありません。すべてのページが同じページ書式とページ・ペインタを共有する場合はPrintableを使用できます。

7.2.2 ページ・ペインタ

ページ・ペインタの主要なジョブは、印刷システムから提供されるグラフィックス・コンテキストを使って、ページをレンダリングすることです。ページ・ペインタは、次のPrintable.printメソッドを実装しています。

public int print(Graphics g, PageFormat pf, int pageIndex)  

printメソッドに渡されるグラフィック・コンテキストは、GraphicsまたはGraphics2Dのインスタンスです。どちらを使用するかは、Java仮想マシンにロードされているパッケージによって決まります。Graphics2Dの機能を使用するには、GraphicsオブジェクトをGraphics2Dオブジェクトにキャストします。printに渡されるGraphicsインスタンスは、PrinterGraphicsインタフェースも実装しています。

Printableに渡されるPageFormatでは、印刷するページの幾何学的な配置(ジオメトリ)が記述されています。printに渡されるグラフィックス・コンテキストの座標系は、そのページに固定されています。座標系の原点は、用紙の左上隅です。X座標の値は右に向かって、Y座標の値は下に向かってそれぞれ増加し、単位は1/72インチです。ページの向きが縦の場合、x軸は用紙の「幅」の方向になり、y軸は用紙の「高さ」の方向になります。用紙の高さは幅より長いのが普通ですが、そうでない場合もあります。ページの向きが横の場合は、軸と用紙の関係が逆になり、x軸が用紙の「高さ」方向、y軸が用紙の「幅」方向になります。

用紙の縁まで印刷できるプリンタは少ないので、PageFormatではページのイメージング可能領域が指定されています。これは、ページの中で安全にレンダリングできる部分です。イメージング可能領域が指定されても、座標系は変わりません。イメージング可能領域は、ページの内容をレンダリングするときに、プリンタが印刷できない領域まで広がることがないようにするためのものです。

printに渡されるグラフィック・コンテキストにはクリッピング領域の情報が含まれていて、この情報では、イメージング可能領域の中で描画する必要のある部分が記述されています。印刷システムが必要なクリッピング処理を行うため、コンテキストにページ全体を描画しても常に安全です。ただし、クリッピング領域を使ってレンダリングされる範囲を制限することで、ページの中の印刷されない部分までレンダリングすることによるオーバーヘッドを除くことができます。グラフィックス・コンテキストからクリッピング領域を取得するには、Graphics.getClipを呼び出します。クリッピング領域を使ってレンダリングのオーバーヘッドを減らすことを、強くお薦めします。

ページがレンダリングされている間でもユーザーがアプリケーションと対話を続けることができるよう、印刷操作をすべて「バックグラウンド」で起動することが望ましい場合があります。そのためには、独立したスレッドでPrinterJob.printを呼び出します。

copyAreasetXOR、合成などのように、前のイメージの内容についての情報が必要なグラフィックス操作は、できるかぎり避ける必要があります。このような操作を行うと、レンダリングが遅くなり、結果の整合性が保たれない場合があります。

7.2.3 PrintableジョブとPageableジョブ

Printableジョブは、印刷を行うもっとも簡単な方法です。使うページ・ペインタは1つだけで、アプリケーションはPrintableインタフェースを実装する単一のクラスを提供します。印刷を行うときは、印刷システムがページ・ペインタのprintメソッドを呼び出して、各ページをレンダリングします。ページのインデックスは0から始まり、ページは順番どおりに要求されます。ただし、次のページに進む前に、各ページのレンダリング要求が何回もページ・ペインタに対して行われる場合があります。最後のページが印刷されると、ページ・ペインタのprintメソッドはNO_SUCH_PAGEを返します。

Printableジョブの場合:

  • すべてのページは、同じページ・ペインタとPageFormatを使います。印刷ダイアログを表示する場合、印刷システムはページ数の情報を利用できないため、ドキュメントのページ数は表示されません。
  • 印刷システムは、常に、インデックスの順番に各ページを印刷するようにページ・ペインタに要求します。ページのインデックスは0から始まります。ページが飛ぶことはありません。たとえば、ユーザーがドキュメントの2ページ目と3ページ目の印刷を要求した場合、ページ・ペインタの呼出しで指定されるインデックスは0、1および2になります。印刷システムは、次のページの印刷に移る前に、同じページのレンダリングを複数回要求する場合があります。
  • ドキュメントの末尾に達すると、ページ・ペインタはそれを印刷システムに通知します。
  • すべてのページ・ペインタは、同じスレッドで呼び出されます。
  • 印刷システムによっては、目的の出力結果が得られないことがあります。たとえば、プリンタから出力されるページ・スタックが正しい順番になっていなかったり、部数が複数の場合にページの丁合いが正しくなかったりする場合があります。

Pageableジョブは、Printableジョブより柔軟性があります。Printableジョブのページとは異なり、Pageableジョブのページはレイアウトと実装が違っていてもかまいません。Pageableジョブを管理するには、Bookクラスを使うか、または独自にPageableクラスを実装します。Pageableを使うと、印刷システムは、印刷するページ数、各ページで使うページ・ペインタ、および各ページで使うPageFormatを特定できます。決まった構造と書式を持つドキュメントを印刷する必要があるアプリケーションは、Pageableジョブを使う必要があります。

Pageableジョブの場合:

  • ページごとに異なるページ・ペインタとPageFormatsを使うことができます。
  • 印刷システムは、ページ・ペインタに任意の順番でページの印刷を要求でき、途中のページが省かれる場合があります。たとえば、ユーザーがドキュメントの2ページ目と3ページ目の印刷を要求した場合、ページ・ペインタの呼出しで指定されるインデックスは1と2だけで、ページ・インデックス0は省略されます。
  • Pageableジョブでは、ドキュメントのページ数をあらかじめ把握しておく必要はありません。ただし、Printableジョブとは異なり、どのような順序でもページをレンダリングできなければなりません。順序指定は飛んでいる場合があり、印刷システムは、次のページの印刷に移る前に、同じページのレンダリングを複数回要求することがあります。たとえば、ドキュメントの2ページ目と3ページ目の印刷を要求する場合、呼出しで要求されるページのインデックスが2、2、1、1、1という順序になることもあります。

7.2.4 PrinterJobの一般的なライフ・サイクル

アプリケーションは、印刷ジョブが完了するまでの一連の手順に沿って、PrinterJobオブジェクトを制御します。次に示すのは、アプリケーションで使用されるもっとも簡単な手順です。

  • PrinterJob.getPrinterJobを呼び出して、新しいPrinterJobオブジェクトを取得します。
  • 印刷で使用するPageFormatを決めます。デフォルトのPageFormatを取得するには、defaultPageを呼び出します。ユーザーが書式を指定できるようにダイアログ・ボックスを表示するには、pageDialogを呼び出します。
  • PrinterJobに印刷されるジョブの特性を指定します。Printableジョブの場合は、setPrintableを呼び出します。Pageableジョブの場合は、setPageableを呼び出します。setPageableに渡すにはBookオブジェクトが最善です。
  • 印刷ジョブのそのほかのプロパティを指定します。印刷する部数やバナー・ページに印刷するジョブの名前などです。
  • printDialogを呼び出し、ダイアログ・ボックスをユーザーに提示します。これはオプションです。このダイアログの内容と表示形式は、プラットフォームやプリンタの種類により異なります。大部分のプラットフォームでは、ユーザーは、このダイアログ・ボックスでプリンタの選択を変更できます。ユーザーが印刷ジョブをキャンセルすると、printDialogメソッドからFALSEが返されます。
  • Printerjob.printを呼び出して、ジョブを印刷します。このメソッドでは、適切なページ・ペインタのprintが呼び出されます。

次の場合、印刷の途中でジョブが中断することがあります。

  • PrinterExceptionのスロー - printメソッドがこの例外をキャッチすると、ジョブは停止します。ページ・ペインタは、致命的なエラーを検出すると、PrinterExceptionをスローします。
  • PrinterJob.cancelの呼び出し - 印刷処理のループが終了され、ジョブがキャンセルされます。ダイアログ・ボックスを表示し、ボックスのボタンをクリックすることでユーザーが印刷をキャンセルできるようにするには、独立したスレッドでダイアログ・ボックスを表示し、cancelメソッドを呼び出します。

印刷ジョブが停止する前に生成されたページは、印刷される場合とされない場合があります。

一般に、printメソッドから戻った時点では、印刷ジョブは完了していません。プリンタ・ドライバ、プリンタ・サーバー、またはプリンタ自体での処理がまだ行われているのが普通です。PrinterJobオブジェクトの状態は、印刷されている実際のジョブの状態を反映しない場合があります。

PrinterJobの状態はライフ・サイクル中に変化するため、特定のメソッドを特定のタイミングで呼び出すと不正になります。たとえば、printを呼び出したあとでsetPageableを呼び出しても無意味です。不正な呼出しを検出すると、PrinterJobjava.lang.IllegalStateExceptionをスローします。

7.2.5 ダイアログ

Java印刷APIでは、ユーザー・インタフェース用のダイアログをアプリケーションが明示的に呼び出すことが要求されます。このようなダイアログは、プラットフォーム(Windowsなど)またはJDKの実装で提供される場合があります。対話型アプリケーションの場合、このようなダイアログを使うのが一般的です。ただし、バッチ用印刷アプリケーションの場合は、ダイアログは必要ありません。たとえば、夜間にデータベースのレポートを自動的に生成して印刷する場合などは、ダイアログの表示は不要です。ユーザーの介入を必要としない印刷ジョブのことを、サイレント印刷ジョブと呼ぶ場合があります。

7.2.5.1 ページ設定ダイアログ

PageFormatに含まれるページ設定情報をユーザーが変更できるようにするには、ページ設定ダイアログを表示します。ページ設定ダイアログを表示するには、PrinterJob.pageDialogを呼び出します。ページ設定ダイアログは、pageDialogに渡すパラメータで初期化されます。ユーザーがダイアログの「OK」ボタンをクリックすると、PageFormatのインスタンスが複製されて、ユーザーの選択に従って変更されたあと、メソッドから返されます。ユーザーがダイアログでキャンセルを選択した場合は、変更されていない元のPageFormatpageDialogから返されます。

7.2.5.2 印刷ダイアログ

通常、メニューの印刷項目または印刷ボタンが起動されると、アプリケーションはユーザーに対して印刷ダイアログを表示します。印刷ダイアログを表示するには、PrinterJobのprintDialogメソッドを呼び出します。PrinterJobに提供されているPrintableまたはPageableのページ数とページ書式に基づいて、ダイアログでのユーザーの選択が制限されます。印刷ダイアログでユーザーが「OK」をクリックすると、printDialogからはTRUEが返されます。ユーザーが印刷ダイアログでキャンセルを選択すると、メソッドからはFALSEが返され、印刷ジョブが破棄されたとみなされます。

7.3 Printableでの印刷

基本的な印刷処理は、次の手順で行います。

  • Printableインタフェースを実装し、印刷する各ページをレンダリングできるページ・ペインタを提供する。
  • PrinterJobを作成する。
  • setPrintableを呼び出し、ドキュメントの印刷方法をPrinterJobに伝える。
  • PrinterJobオブジェクトのprintを呼び出して、ジョブを開始する。

次の例では、Printableジョブを使って5ページを印刷し、各ページに緑色でページ番号を付けます。ジョブの制御はmainメソッドで行い、このメソッドでPrinterJobを取得して制御します。レンダリングは、ページ・ペインタのprintメソッドで行われます。

import java.awt.*; import java.awt.print.*; 
public class SimplePrint implements Printable  
{    
  private static Font fnt = new Font("Helvetica",Font.PLAIN,24); 
   
  public static void main(String[] args)  
  {      
    // Get a PrinterJob      
    PrinterJob job = PrinterJob.getPrinterJob();      
    // Specify the Printable is an instance of SimplePrint 
    job.setPrintable(new SimplePrint());      
    // Put up the dialog box      
    if (job.printDialog())  
    {    
      // Print the job if the user didn't cancel printing  
      try { job.print(); } 
      catch (Exception e) 
        { /* handle exception */ } 
    }      
    System.exit(0);    
  } 
 
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  {      
    // pageIndex 0 to 4 corresponds to page numbers 1 to 5. 
    if (pageIndex >= 5) return Printable.NO_SUCH_PAGE;    
    g.setFont(fnt);      
    g.setColor(Color.green);      
    g.drawString("Page " + (pageIndex+1), 100, 100);      
    return Printable.PAGE_EXISTS;    
  }  
} 

7.3.1 Graphics2Dを使ったレンダリング

ページ・ペインタのprintメソッドの中でGraphics2Dの機能を実行するには、最初にGraphicsコンテキストをGraphics2Dにキャストします。

次の例では、ページ番号を赤と緑のグラデーションでレンダリングします。そのために、GradientPaintGraphics2Dコンテキストで設定されています。

import java.awt.*; import java.awt.print.*; 
public class SimplePrint2D implements Printable  
{    
  private static Font fnt = new Font("Helvetica",Font.PLAIN,24); 
   
  private Paint pnt = new GradientPaint(100f, 100f, Color.red,                                            136f, 100f, Color.green, true); 
   
  public static void main(String[] args)  
  {      
    // Get a PrinterJob      
    PrinterJob job = PrinterJob.getPrinterJob();      
    // Specify the Printable is an instance of SimplePrint2D 
    job.setPrintable(new SimplePrint2D());      
    // Put up the dialog box      
    if (job.printDialog())  
    {    
      // Print the job if the user didn't cancel printing  
      try { job.print(); }           
      catch (Exception e) { /* handle exception */ }      
    }      
  System.exit(0);    
  } 
 
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  {      
    // pageIndex 0 to 4 corresponds to page numbers 1 to 5. 
    if (pageIndex >= 5) return Printable.NO_SUCH_PAGE; 
    Graphics2D g2 = (Graphics2D) g; 
    // Use the font defined above 
    g2.setFont(fnt); 
    // Use the gradient color defined above 
    g2.setPaint(pnt); 
    g2.drawString("Page " + (pageIndex+1), 100f, 100f); 
    return Printable.PAGE_EXISTS;    
  }  
} 

7.3.2 ファイルの印刷

ページ・ペインタのprintメソッドが同じページに対して繰返し呼び出される場合、メソッドはそのたびに同じ出力を生成しなければなりません。

同じページに対して繰返しレンダリング要求があるたびに、常に同じ出力を生成する方法はいくつもあります。たとえば、テキスト・ファイルの特定のページを印刷システムが要求するたびに、同じ出力が生成されるようにするには、ページ・ペインタで、ページごとのファイル・ポインタを格納して再使用したり、実際のページ・データを格納したりします。

次の例では、テキスト・ファイルの「リスト表示」が印刷されています。ファイルの名前は、mainメソッドに引数として渡されています。PrintListingPainterクラスは、レンダリングを要求された新しいページの開始位置で、使われているファイル・ポインタを格納します。同じページをふたたびレンダリングするときは、ファイル・ポインタを記憶してある位置にリセットします。

import java.awt.*;  
import java.awt.print.*;  
import java.io.*; 
 
public class PrintListing  
{    
  public static void main(String[] args)  
  {      
    // Get a PrinterJob 
    PrinterJob job = PrinterJob.getPrinterJob(); 
    // Ask user for page format (e.g., portrait/landscape) 
    PageFormat pf = job.pageDialog(job.defaultPage()); 
    // Specify the Printable is an instance of 
    // PrintListingPainter; also provide given PageFormat 
    job.setPrintable(new PrintListingPainter(args[0]), pf); 
    // Print 1 copy    
    job.setCopies(1);      
    // Put up the dialog box      
    if (job.printDialog())  
    { 
      // Print the job if the user didn't cancel printing 
      try { job.print(); } 
      catch (Exception e) { /* handle exception */ }      
    }      
    System.exit(0);    
  }  
} 
 
class PrintListingPainter implements Printable  
{ 
  private RandomAccessFile raf;    
  private String fileName;    
  private Font fnt = new Font("Helvetica", Font.PLAIN, 10); 
  private int rememberedPageIndex = -1;    
  private long rememberedFilePointer = -1;    
  private boolean rememberedEOF = false; 
   
  public PrintListingPainter(String file)  
  {  
    fileName = file;      
    try 
    {  
      // Open file       
      raf = new RandomAccessFile(file, "r");      
    }  
    catch (Exception e) { rememberedEOF = true; }    
  } 
 
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  { 
  try  
  {  
    // For catching IOException      
    if (pageIndex != rememberedPageIndex)  
    {  
      // First time we've visited this page 
      rememberedPageIndex = pageIndex;   
      // If encountered EOF on previous page, done  
      if (rememberedEOF) return Printable.NO_SUCH_PAGE; 
      // Save current position in input file 
      rememberedFilePointer = raf.getFilePointer(); 
    }  
    else raf.seek(rememberedFilePointer); 
    g.setColor(Color.black);      
    g.setFont(fnt);  
        int x = (int) pf.getImageableX() + 10; 
        int y = (int) pf.getImageableY() + 12;     
    // Title line      
    g.drawString("File: " + fileName + ", page: " +                                          (pageIndex+1),  x, y); 
    // Generate as many lines as will fit in imageable area 
    y += 36; 
    while (y + 12 < pf.getImageableY()+pf.getImageableHeight()) 
    { 
      String line = raf.readLine(); 
      if (line == null) 
      {  
        rememberedEOF = true; 
        break;  
                } 
        g.drawString(line, x, y);  
        y += 12;      
      } 
      return Printable.PAGE_EXISTS;     
    }  
    catch (Exception e) { return Printable.NO_SUCH_PAGE;} 
  }  
} 

7.4 PageableとBookでの印刷

Pageableジョブは、ドキュメントの体裁を1ページずつ明示的に構成するアプリケーションに適しています。BookクラスはPageablesを手軽に使うための手段ですが、Bookが目的に合わない場合は、Pageableの構造を独自に作ることもできます。ここでは、Bookの使用方法を説明します。

いくぶん複雑にはなりますが、印刷システムの柔軟性が増すため、PrintableジョブよりもPageableジョブの方が実用に適しています。Pageablesの大きな利点は、通常はドキュメントのページ数を把握でき、印刷ダイアログ・ボックスでユーザーに対して表示できることです。これによりユーザーは、ジョブが正しく指定されているか確認したり、印刷するページの範囲を選択したりできます。

Bookは、ページの集合を表します。Bookの中のページは、同じサイズや向き、または同じページ・ペインタを共有する必要はありません。たとえば、1つのBookで、2ページは縦方向のレター・サイズ、1ページは横方向のレター・サイズであってもかまいません。

Bookの最初の作成時には、このオブジェクトは空の状態です。Bookにページを追加するには、appendメソッドを使います。このメソッドは、ページのサイズ、印刷可能領域、向きを定義するPageFormatオブジェクトと、Printableインタフェースを実装するページ・ペインタを受け取ります。

Bookの複数のページで、同じページ書式とページ・ペインタを共有できます。appendメソッドの3番目のパラメータでページ数を指定すると、appendはオーバーロードされて、同じ属性の一連のページを追加できるようになります。

Bookの総ページ数がわからない場合は、appendメソッドにUNKNOWN_NUMBER_OF_PAGESを渡すことができます。このようにすると、印刷システムは、NO_SUCH_PAGEが返されるまで、ページのインデックスを増やしながらページ・ペインタを呼び出します。

setPageメソッドを使うと、ページのページ書式またはページ・ペインタを変更できます。変更するページの識別には、Bookでのそのページの位置を示すページ・インデックスを使います。

印刷ジョブを準備するには、setPageableを呼び出してBookを渡します。setPageableメソッドとsetPrintableメソッドは、一緒には使用できません。つまり、PrinterJobを準備するときは、どちらか一方だけを呼び出すようにします。

7.4.1 Pageableジョブの使用方法

次の例では、Bookを使って、最初の簡単な印刷例と同じものを生成しています。この例はごく単純なものなので、Printableジョブの代わりにPageableジョブを使うことにそれほど利点はありませんが、Bookの基本的な使用法を示しています。この場合も、Printableインタフェースを実装し、ページ・ペインタのprintメソッドでページをレンダリングする必要があることに注意してください。

import java.awt.*;  
import java.awt.print.*; 
 
public class SimplePrintBook implements Printable  
{    
  private static Font fnt = new Font("Helvetica",Font.PLAIN,24); 
  public static void main(String[] args)  
  {      
    // Get a PrinterJob      
    PrinterJob job = PrinterJob.getPrinterJob();      
    // Set up a book      
    Book bk = new Book();      
    bk.append(new SimplePrintBook(), job.defaultPage(), 5);      
    // Pass the book to the PrinterJob      
    job.setPageable(bk);      
    // Put up the dialog box      
    if (job.printDialog())  
    { 
      // Print the job if the user didn't cancel printing  
      try { job.print(); }           
      catch (Exception e) { /* handle exception */ }      
    }      
    System.exit(0);    
  } 
 
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  {      
    g.setFont(fnt);      
    g.setColor(Color.green);      
    g.drawString("Page " + (pageIndex+1), 100, 100);      
    return Printable.PAGE_EXISTS;    
  } 
} 

7.4.2 複数のページ・ペインタの使用方法

次の例では、表紙と本文に対して、2つの異なるページ・ペインタが使われています。表紙は横置きモードで印刷し、本文は縦置きモードで印刷しています。

import java.awt.*;  
import java.awt.print.*; 
 
public class PrintBook  
{ 
  public static void main(String[] args)  
  {      
    // Get a PrinterJob      
    PrinterJob job = PrinterJob.getPrinterJob();      
    // Create a landscape page format     
    PageFormat pfl = job.defaultPage();   
    pfl.setOrientation(PageFormat.LANDSCAPE);      
    // Set up a book      
    Book bk = new Book();      
    bk.append(new PaintCover(), pfl);      
    bk.append(new PaintContent(), job.defaultPage(), 2);      
    // Pass the book to the PrinterJob      
    job.setPageable(bk);      
    // Put up the dialog box      
    if (job.printDialog())  
    {  
      // Print the job if the user didn't cancel printing 
      try { job.print(); }  
      catch (Exception e) { /* handle exception */ }      
    }      
  System.exit(0);    
  }  
} 
 
class PaintCover implements Printable  
{    
  Font fnt = new Font("Helvetica-Bold", Font.PLAIN, 72); 
  
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  {      
    g.setFont(fnt);      
    g.setColor(Color.black);      
         int yc = (int) (pf.getImageableY() +               pf.getImageableHeight()/2); 
    g.drawString("Widgets, Inc.", 72, yc+36);      
    return Printable.PAGE_EXISTS;    
  }  
} 
class PaintContent implements Printable  
{    
  public int print(Graphics g, PageFormat pf, int pageIndex) 
  throws PrinterException  
  {     
    Graphics2D g2 = (Graphics2D) g;      
    int useRed = 0;      
   int xo = (int) pf.getImageableX(); 
        int yo = (int) pf.getImageableY();  
    // Fill page with circles or squares, alternating red & green 
        for (int x = 0; x+28 < pf.getImageableWidth(); x += 36) 
    for (int y = 0; y+28 < pf.getImageableHeight(); y += 36) 
    {  
      if (useRed == 0) g.setColor(Color.red); 
      else g.setColor(Color.green); 
      useRed = 1 - useRed; 
      if (pageIndex % 2 == 0) g.drawRect(xo+x+4, yo+y+4, 28, 28); 
      else g.drawOval(xo+x+4, yo+y+4, 28, 28); 
    }      
    return   Printable.PAGE_EXISTS;    
  }  
} 

 


目次||次

Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.