SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Javaの標準機能だけで実現する帳票印刷

Javaの標準機能だけで印刷する際の用紙のサイズや向き、余白の指定

Javaの標準機能だけで実現する帳票印刷 第2回


用紙サイズや余白を指定する方法の詳細

 用紙サイズや余白など印刷方法に関する指示をJavaでは"attribute"、日本語では「属性」と呼びます。javax.print.attributeとjavax.print.attribute.standardの2つのパッケージを使います。standardのついたパッケージの中に用紙の大きさや印刷の向きなどの属性が定義されているので、この中から選んで"attributeset"にまとめて印刷時に指示するという手順になります。

 上記のプログラム例では、次のような例を示しました。

PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
rqset.add(new Copies(3)); //3部印刷 
rqset.add(MediaSizeName.ISO_A3); //A3用紙
rqset.add(new MediaPrintableArea(
   10.1f, 10.3f, 276.7f, 399.3f,
   MediaPrintableArea.MM));//左余白,上余白,描画幅,描画高,単位

 1行目でPrintRequestAttributeSetインターフェースを持つインスタンスをHashPrintRequestAttributeSetクラスを使用して作成しています。XxxxXxxxAttributeSetというクラスやインターフェースはいくつかありますが、とりあえずこれだけで済みます。このインスタンスにadd()メソッドを使って属性値を追加していきます。

 最初に追加している印刷部数では、Copiesクラスのインスタンスを引数を3にして生成し、追加しています。もし、印刷部数を指定しなければデフォルトの値である「1部」が設定されます。どの属性も省略すればデフォルト値になりますから、必要な属性だけ追加すればよいのです。

 次のMediaSizeNameでは、MediaSizeNameクラスのstaticなフィールドであるISO_A3を追加しています。フィールド値の型はMediaSizeNameです。

 javax.print.attribute.standardパッケージの中に、CopiesやMediaSizeNameというクラスがあります。これらのクラスは「PrintRequestAttributeインターフェースを持っているので、PrintRequestAttributeSetに追加できる」という仕組みになっています。Copiesクラスなどを「属性カテゴリ」、インスタンスは「属性値」と呼ばれます。

 javax.print.attribute.standardパッケージにはたくさんのクラスがありますが、よく使うと思われるものを拾っておきます。

 以下rqsetはPrintRequestAttributeSetのインスタンスであるとします。

Copyes

 印刷部数を指定します。

rqset.add(new Copies(5));

 ページ数とは異なります。一度の印字で同じ出力が何部必要かということです。多くの場合1部なので省略します。

 属性指定の例としてよく出てくるのは、わかりやすい例であって、プリンタ側でも必ず対応できるものだからだと思います。

 newですからインスタンスで、引数の5という値が含まれている「もの」をaddする。ただの5だと何の数だかわからないけれども、Copiesクラスなので部数だと言っているわけです。PrintRequestAttributeSetの全体はSetだけれども、クラスがkeyでインスタンスがvalueのMapのSetという形です。

OrientationRequested

 用紙上の印刷方向を指定します。取りうる値は4つですが、REVERSE_PORTRAITは指定できない(無視される)場合があります。

 この値は、OrientationRequestedクラスのstaticなフィールド値で、値の型はOrientationRequestedです。

 デフォルトはPORTRAITです。

rqset.add(OrientationRequested.LANDSCAPE);
rqset.add(OrientationRequested.PORTRAIT);
rqset.add(OrientationRequested.REVERSE_LANDSCAPE);
rqset.add(OrientationRequested.REVERSE_PORTRAIT);
用紙の向きの指定(Linux)
用紙の向きの指定(Linux)

 WindowsではLANDSCAPEとREVERSE_LANDSCAPEが逆になります。

用紙の向きの指定(Windows)
用紙の向きの指定(Windows)

 後で説明しますが、どちらも間違っているわけではありません。余白の位置などは同じで、プリンタから出てくる時にどちらから出てくるかだけの問題です。

MediaSizeName

 用紙のサイズを指定します。ISO_A4とかISO_A3とかJAPANESE_POSTCARDなど、Java 8では73個の用紙サイズが登録されています。

 これらは、MediaSizeNameクラスのstaticなフィールドで、型はMediaSizeNameです。

 MediaSizeNameクラスは、Mediaのサブクラスです。Mediaクラスには他にMediaName、MediaTrayを加えて全部で3つのサブクラスがあります。MediaName、MediaTray、MediaSizeNameのどれかを使って Mediaという属性を指定するということになっています。

 MadiaNameには4つのフィールドしか定義されていません。一つはMadiaName.ISO_A4_WHITEで、これはA4の白い紙です。MediaName.ISO_A4_TRANSPARENTはA4のOHPシートです。これにA4でなくレターサイズの用紙の白い紙とOHPシートが加わって4つです。さらにサブクラスを定義して自分で拡張するように作っているようですが、このまま使えるものではありません。

 MediaTrayはプリンタの給紙トレイを指定するものです。MediaTrayにはMAIN、MANUAL、TOP、MIDDLE、BOTTOMなど8つの値が定義されています。トレイと用紙のサイズを両方を指定する方法は用意されていません。

 トレイと用紙の両方を指定しても、矛盾することがあるでしょうから、トレイを指定してプリンタにトレイ内の用紙の大きさを問い合わせるという手順を踏むか、トレイの用紙に合わせて拡大縮小して印刷するという使い方になるでしょう。帳票印刷では用紙の大きさが決まっていますから、結局MediaSizeNameだけを使って指定するということになるでしょう。

 いくつか例を挙げると、

rqset.add(MediaSizeName.ISO_A3); //A3用紙
rqset.add(MediaSizeName.ISO_A4); //A4用紙
rqset.add(MediaSizeName.JIS_B5); //JIS B5(ISO_B5とは異なる)
rqset.add(MediaSizeName.JAPANESE_POSTCARD); //葉書
rqset.add(MediaSizeName.JAPANESE_DOUBLE_POSTCARD); //往復はがき

 この他に、ISOのA0~A10、B0~B10、JISのB0~B10、北米規格の各種封筒サイズなどがあります。

 それぞれの用紙の実際のサイズはMediaSizeNameクラスではなく、MediaSizeクラスに格納されています。

 MediaSizeというクラスは直接MediaSizeはAttributeSetに加えることができません。加えられたMediaSizeNameインスタンスからMediaSizeクラスを使って用紙の縦横の長さを得るという手順を踏んでいます。

 MediaSizeクラスにはMediaSizeNameからMediaSizeを得るメソッドと、縦横の長さからMediaSizeNameを検索するためのメソッド、用紙の縦横の長さを得るメソッドが用意されています。後で説明するMediaPrintableAreaクラスで余白を指定する時に、これを使って用紙の大きさを取得します。

MediaSizeName msname = MediaSizeName.ISO_A4;
rqset.add(msname);
MediaSize msize = MediaSize.getMediaSizeForName(msname);
float mwidth  = msize.getX(MediaPrintableArea.MM);
float mheight = msize.getY(MediaPrintableArea.MM);

 MediaPrintableArea.MM はMediaPrintableAreaクラスの定数フィールドで、内実は整数1000です。MediaPrintableArea内で長さはμm単位の整数として格納されるので、MediaPrintableArea.MMの値で割り算をしてmm単位のfloatにする仕組みでしょう。MediaPrintableArea.INCHの値は25400ですから割り算するとインチになります。

MediaPrintableArea

 余白を指定するために使います。

 Javaのデフォルトの余白が上下左右それぞれ1インチ(25.4mm)なので、この範囲に印字しないのなら指定する必要はありません。

 プリンターには印刷機構や紙送りなどハードウェア上の都合で用紙の全体に印刷できないことが普通です。写真で「縁無し」という方法もありますから、これも考慮すると事情はより複雑になります。

 ハードウェア上の都合ですからプリンタに問い合わせるのが筋です。API仕様にも、PrintService.getSupportedAttributeValues()を参照せよとあります。しかし、一般的な帳票では用紙を隅々まで使うことは稀ですから、問い合わせずに5mmとか10mmあたりの余白を指定しても制限に引っかかることはないと考えられます。もし引っかかっても、その分は印刷されないだけでエラーになりませんし、レイアウトが乱れたりもしません。

 直接A4縦置きの用紙に左,右,上,下に10.1,10.2,10.3,10.4(単位はmm)の余白を指定するならば次のようにします。数値を微妙に変えているのは0.1mm単位で指定できるということをアピールと、左,右,上,下がきちんと伝わることの確認のためです。

rqset.add(new MediaPrintableArea(
   10.1f, 10.3f, 189.7f, 276.3f
   MediaPrintableArea.MM));//左余白,上余白,描画幅,描画高,単位

 A4の横は210.0mmなので、210 - 10.1 - 10.2 = 189.7と計算して、10.1と189.7を指定します。図では次のようになります。

余白と描画可能域の幅
余白と描画可能域の幅

 縦は297.0mmなので、297 - 10.3 - 10.4 = 276.3と計算して、10.3と276.3を指定します。図は省略します。

 実際のプログラムでは、用紙のサイズをMediaSizeから得て、余白をリテラルで書いて描画可能域のサイズはそこから算出するのがいいと思います。L,R,T,Bはそれぞれ左,右,上,下の余白です。

MediaSizeName msname = MediaSizeName.ISO_A4;
rqset.add(msname);
MediaSize msize = MediaSize.getMediaSizeForName(msname);
float mwidth  = msize.getX(MediaPrintableArea.MM);
float mheight = msize.getY(MediaPrintableArea.MM);
float L = 10.1f;
float R = 10.2f;
float T = 10.3f;
float B = 10.4f;
rqset.add(new MediaPrintableArea(
    L, T, (mwidth - L - R), (mheight - T - B),
    MediaPrintableArea.MM));

次のページ
用紙の向きと余白の関係

この記事は参考になりましたか?

Javaの標準機能だけで実現する帳票印刷連載記事一覧

もっと読む

この記事の著者

安達 順一(アダチ ジュンイチ)

私立高校に理科・情報の教員として勤めていました。Linuxサーバー/クライアントの授業システムを作り、移動プロファイルで運用していました。教員用にもLinuxサーバーを用意し成績処理プログラムを書きました。情報の学校設定科目ではウェブページ制作とjavaのプログラミングの初歩の授業を作りました。情報...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11670 2019/10/24 21:58

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー