AWT Print
AWT Printを使って印刷機能を実現する場合、Printableインタフェースの実装クラス作成が肝となります。まずは以下にサンプルコードを示します。
/**
* Printable,Pageableインターフェースの実装。
*/ public class MyPrintable implements Printable, Pageable{ //・・・省略・・・ public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException { if (pageIndex < 2){ RoundDraw roundDraw = new RoundDraw(); //描画領域の設定 roundDraw.setWidth((int)pf.getImageableWidth()); roundDraw.setHeight((int)pf.getImageableHeight()); //余白を加味して平行移動 g.translate((int)pf.getImageableX(), (int)pf.getImageableY()); roundDraw.draw(g); //ページ番号の描画 g.drawString("Page:" + (pageIndex + 1), 20, 20); return Printable.PAGE_EXISTS; } else { return Printable.NO_SUCH_PAGE; } } //・・・省略・・・ }
Printableインタフェースはprint
メソッドを提供します。このメソッドは印刷実行時に後述のPrinterJobのprintメソッド内からコールバックの形で使用されます。
引数で渡されるGraphicsを使用して描画を行うと、その内容が印刷物に出力されます。また、引数pageIndex
には印刷しようとしているページのインデックスが(0から)セットされます。pageIndex
の値を判断して、指示されたページの描画を行うことがprint
メソッドの役割になります。
呼び出し元には処理の成否を返す必要があります。pageIndex
で指定されたページが存在し、正常に描画ができた場合にはPrintable.PAGE_EXISTS
を、ページが存在しない場合にはPrintable.NO_SUCH_PAGE
を戻り値に設定します。print
メソッドはNO_SUCH_PAGE
が返されるまで繰り返し呼び出されます。印刷ページの終了を判断してNO_SUCH_PAGE
を返却する必要があります。今回のサンプルコードは3ページ目(pageIndex
が2になった時)にNO_SUCH_PAGE
となるので2ページの印刷となります。
なお、print
メソッドはpageIndex
を1ずつ増やしながら1回ずつ呼び出されるとは限らない点に注意してください。例えば「3ページ目を10枚」といった具合で、pageIndex
に同じ値が設定されたまま繰り返し呼び出されることもあり得ます。印刷状況に関する情報をクラス変数などに留保せず、引数で与えられたpageIndex
の値のみを判断基準として処理を行うようにしてください。
ここでは最初のサンプルコードで登場したRoundDrawオブジェクトを使って描画処理を実装しています。プリンタで印刷する場合は余白についても考慮した方が良いでしょう。用紙内にきれいに収めるために、下図の要領で平行移動とサイズ指定を行います。
印刷の処理の手順ですが、まずPrinterJobオブジェクトを取得します。これに先程のPrintableオブジェクトを設定します。最後にPrinterJobのprint
メソッドを実行すると印刷が実行されます。
PrinterJobオブジェクトは、印刷ジョブをあらわす抽象的なオブジェクトです。 getPrinterJob()
で取得した時点では「どのプリンタに印刷するか?」「どのように印刷するか?」などの情報はまだ決定しておらず、抽象的な印刷ジョブとして生成されます。このジョブに対して、Printableを設定したり、印刷ダイアログから設定を行うことで明確な印刷ジョブの指定として完成されます。
public class AWTPrint { public static void main(String[] args) throws PrinterException { //PrintaerJobの取得 PrinterJob job = PrinterJob.getPrinterJob(); MyPrintable printable = new MyPrintable(job.defaultPage()); //Printable, Pageableの設定 job.setPrintable(printable); job.setPageable(printable); //印刷ダイアログの表示と印刷 if (job.printDialog()){ job.print(); } } }
PrinterJobのprintDialog
メソッドを実行すると、OS標準の印刷ダイアログが表示されます。printDialog
メソッドは「OK」や「キャンセル」などのユーザ選択をboolean値で返します。printDialog
メソッドがtrueを返却する時にだけ印刷を実行します。なお、AWT Printではダイアログを表示しなければ印刷オプション設定ができないという欠点があります。
MyPrintableクラスではPageableインターフェースも実装しています。Pageableインターフェースは印刷物が何ページあるかといった情報を管理します。ページごとにPrintableオブジェクトを切り替えたりすることができます。
今回のサンプルコードは、1つのPrintableオブジェクトが、ページ1、2の両方を印刷する実装になっています。全く異なるレイアウトを印刷する場合、例えば「1ページ目が表紙用のPrintableオブジェクト」「2ページ目以降が明細データのPrintableオブジェクト」のように、2つのPrintableオブジェクトを別々に作成し、getPrintable
メソッドで対応するPritableオブジェクトを返却する構成にすることができます。
/**
* Printable,Pageableインターフェースの実装。
*/ public class MyPrintable implements Printable, Pageable{ private PageFormat pf; public MyPrintable(){ } public MyPrintable(PageFormat pf) { this.pf = pf; } public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException { //・・・省略(前述したソースコード)・・・ } /**
* この印刷物の総ページ数を返却する。
* 印刷ダイアログでのページ数指定になる。
*/ public int getNumberOfPages() { return 2; //2ページあるとする } /**
* ページごとのページ書式を返却する。
* 今回のサンプルでは印刷ダイアログで指定したページ書式を
* 全ページで使用。
* 例えば、ページ1は縦置きでページ2は横置きなど、
* ページ書式の切り替えが実装できる。
*/ public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException { return pf; } /**
* ページごとのPritableを返却する。
* 例えば1ページ目の表紙用のPrintableと、
* 2ページ目以降の明細用のPrintableを切り替えたりすることができる。
*/ public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException { return this; } }
実は、Pageableインターフェースがなくても印刷はできます。ただしその場合は、下図のようにダイアログの印刷範囲欄に表示されるページの値が適切に設定されません。
印刷ダイアログのページ指定の最大値は、getNumberOfPages
メソッドで返される値になります。今回はPrintableオブジェクトが2ページの印刷を行うオブジェクトになっているので、固定値の2になっています。
例えば、明細形式の印刷物で、全50明細、1ページあたりに20明細印刷するような場合は、50/20=2.5 となるのでページ数としては、getNumberOfPages
メソッドが3を返すような実装になります。
さて、プログラムを実行してみましょう。印刷ダイアログが表示されるので、「OK」ボタンを押します。プリンタから紙面一杯に楕円が印刷されて出てくるはずです。