SHOEISHA iD

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

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

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

プリンタの検索と選択、そして特に長形3号封筒への印刷

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

  • このエントリーをはてなブックマークに追加

 本稿では、Java SEの標準機能だけを使った帳票印刷の方法を解説します。前回はJava側に用意された用紙サイズに一部不備と思われる部分があることを指摘しましたが、今回はプリンタ(ドライバ)から対応可能な用紙サイズを取得することを試みます。用紙選択の話を早く済ませて印刷プレビューや、文字の均等割付などの話に進みたいところですが、乗りかかった船ですので説明いたします。A4やA3や葉書への印刷しか必要ないという方には用のない話ですが、プリンタの検索と選択が可能になり、特に長形3号封筒への印刷ができるようになります。

  • このエントリーをはてなブックマークに追加

はじめに

 第2回の最後に書いたように、プリンタの検索と選択が必要ない状況も考えられます。Javaによるプリンタの選択にはいろいろと複雑な問題があるので、必要がなければ触らない方が良いかもしれません。ここではJISの封筒を使いたいとか、A4とA3を別のプリンタから出すようになっていて自動で切り替えるようにしたいとか、問題を抱えたときのために解説をします。OSとプリンタの機種の組み合わせで環境依存が大きいと思うので、必要なものを選択できるように段階を踏んで説明します。

  • (1)条件に合致したプリンタを選択する一般的な方法。
  • (2)JISの封筒を指定する方法。
  • (3)その手法を使って、条件に合致したプリンタを検索する実効性のある方法。
  • (4)Linuxでトレイを切り替える方法。
  • (5)プリンタのデフォルトの用紙サイズでプリンタを選ぶ方法。

(1)条件に合致したプリンタを選択する一般的な方法

 PrintServiceLookupクラスのlookupPrintServices()というstaticメソッドを使います。PrintRequestAttributeSetと、印刷データの種類を表すDocFlavorを引数をとり、それらを扱うことができるプリンタの一覧を得ることができるとAPI仕様に書いてあります。 分かりやすい例で言えばA3が使えるプリンタだけを探し出すことができるというわけです。

 Linuxの場合、A3に限定するというのはうまく働きます。しかし、Windows 10ではA3を指定してもA4までしか使えないプリンタも入ってしまいます。さらに、Windows 10ではA4を指定するとOneNoteというプリンタでないものがでてきたりします。これは検索する対象がサービスですから正当ではありますがプリンタの選択には邪魔になります。

 また、葉書を指定した場合には葉書以上の用紙サイズを印刷できるプリンタが選択されるだけで、現在葉書がカセットに入っていたり手差しに入っていたりするプリンタを探し出すところまで期待することはできません。

 というわけで、プリンタの配列が得られても、その中の一つを自動で選んでそのまま印刷するわけには行かず、得られた配列を候補としてダイアログを出し、手動で切り替えるようにすることになるでしょう。それが、ServiceUI.printDialog()です。

 つまり、lookupPrintServices()で得られた「条件を満たす」プリンタ群から、ServiceUI.printDialog()を使ってプリンタを選択します。概略はこんな感じです(実はあまり役に立ちません)。

PrinterSelectTest01.java
import java.awt.print.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;

/** 条件にあったプリンタを検索して選択する一般的なプログラム */
public class PrinterSelectTest01{
    public static void main(String[] args) {
        PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
        rqset.add(MediaSizeName.ISO_A3); 
        DocFlavor flv = DocFlavor.SERVICE_FORMATTED.PRINTABLE;

        PrintService[] svs = PrintServiceLookup.lookupPrintServices(flv,rqset);
        for(PrintService sv:svs){
            System.out.println(sv.getName());
        }
        PrintService service = ServiceUI.printDialog(
            null, 200, 200, svs, svs[0], flv, rqset);
        PrinterJob pj = PrinterJob.getPrinterJob();
        if (service != null) {
            try{
                pj.setPrintService(service);
            }catch (PrinterException e) {
                System.err.println(e);
            }
        }
        PrintService selectedprnter = pj.getPrintService();
        System.out.println("---> "+selectedprnter.getName());
    }
}

 DocFlavorは帳票印刷の場合DocFlavor.SERVICE_FORMATTED.PRINTABLEを指定します。これは2Dグラフィクスで直接描く文書であることを意味します。

 PrintRequestAttributeSetには必要な印刷属性を加えます。ここではA3を指定しています。

 この2つのインスタンス、flv, rqsetを引数にして、lookupPrintServices()は条件に合致したプリンタを検索し、結果を配列svsとして返しています。確認のためsvs内のプリンタ名を書き出しています。

 この中から使用するプリンタを選択するためにServiceUI.printDialog()を使います。引数は次のとおりです。

  • null,200,200 : デフォルトのスクリーンのx=200,y=200の位置に表示する。
  • svs : 選択候補となるPrintServiceの配列。空の配列でもよいが、nullは不可。
  • svs[0] : 選択候補の初期値。nullは不可。
  • flv, rqset : 検索に使ったものと同様。ダイアログにサイズと余白を表示するために加える。

実行結果(Windows 10)

 実行した環境ではA3の使えるプリンタは EPSON PX-1700F と Canon Inkjet iP9910 だけですが、たくさん出てくることが確認できます。GUIからMP493を選択したので、最終行に「---> Canon MP493 series Printer」と表示されています。

実行時の端末表示(Windows)
PS Z:\java\print03> java PrinterSelectTest01
Microsoft XPS Document Writer
Microsoft Print to PDF
EPSON PX-1700F
Canon MP493 series Printer
Canon Inkjet iP9910
---> Canon MP493 series Printer

実行結果(Linux)

 LinuxではA3プリンタのEPSON PX-1700Fだけが選択肢になります。Linuxには Canon Inkjet iP9910 のドライバがなく、そもそも接続していません。 GUIからPX-1700Fを選択したので、「---> EPSON_EPSON_PX-1700F」と表示されています。

実行時の端末表示(Linux)
adachi@debian64:~$ java PrinterSelectTest01
EPSON_EPSON_PX-1700F
---> EPSON_EPSON_PX-1700F

一般的な方法の問題点

 この概略に沿って解説したものを、あちらこちらで目にしますが、いろいろな問題が残っていることに言及しているものに出会ったことがありません。筆者の使い方が悪くて問題が出るということではないと思っていますがどうでしょう。

 第一に、先に示したとおり、WindowsではAttributeSetの制約に従わず全部のプリンタを拾ってしまいます。実はこれはA4プリンタでもA3をプリンタ(ドライバ)側で縮小して印刷する機能があって、A3印刷ができると答えているのが原因のようです。

 第二に、これもWindowsだけですが、AttributeSetにMediaPrintableAreaの指定が入っていると、lookupPrintServices()はしばらく考え込んで、空の配列を返します。よく目にする解説では、lookupPrintServices()の引数のAttributeSetを、nullにしたり、生成しただけで何もadd()していないものを使っているので、これに遭遇することはありません。しかし、MediaPrintableAreaを指定しないとダイアログで余白がデフォルトのままです。これには回避策があって、lookupのAttributeにMediaPrintableAreaを指定しないで、ServiceUI.printDialogの時のAttributeに追加指定すれば、選択もうまく行って(制約は効きませんが)、ダイアログに余白が正しく入ります。

 第三は、不具合ではありませんが、ServiceUI.printDialogのプリンタの初期値に何を持ってくるかの問題です。Windowsの場合にプリンタでないサービスも候補の配列に入るので、それがsvs[0]に入ってしまうと結局変更しなければならなくなります。この対策からか、svs[0]の代わりにPrintServiceLookup.lookupDefaultPrintService()で得るデフォルトプリンタを指定している例をよく見ますが、A3が使えるプリンタを探している時に、デフォルトのプリンタがA3を使えない物だったら必ず変更しなければならなくなって不合理です。

 とにかくここまでの使い方では、使用できるプリンタを検索して選択の候補を絞り込むという機能はないに等しいということになります。OSやプリンタ機種、ドライバに依るかもしれませんし、今後改良があるかもしれませんので、再検証のためにこのプログラムを残しておきます。

プリンタが分かっている場合

 「様式Aの帳票はプリンタAから印刷する、様式Bの帳票はプリンタBから印刷する」などとプリンタを固定できる場合には自動で切り替えることも可能です。帳票印刷の設計では、こちらのほうが役に立つかもしれません。

 次に示すのは、あらかじめ調べておいた"Canon_MP493_series"という名前のプリンタを指定するというプログラムです。Windowsでは"Canon MP493 series"とアンダースコアでなくスペースで区切るという違いがありますから、共通の文字列である"MP493"で探しています。これで見つからなければデフォルトのプリンタになります。

PrinterSelectTest02.java
import java.awt.print.*;
import javax.print.*;
/**接続されたプリンタから MP493 という名前のものを使う*/
public class PrinterSelectTest02{
   public static void main(String[] args) {
        String pname = "MP493";
        PrinterJob pj = PrinterJob.getPrinterJob();
        PrintService foundprn = getServiceByName(pname);
        if(foundprn!=null){
            try{
                pj.setPrintService(foundprn);
            }catch (PrinterException e) {
                    System.err.println(e);
            }
        }
        PrintService prnter = pj.getPrintService();
        System.out.println("---> "+prnter.getName());
    }
    public static PrintService getServiceByName(String name){
        PrintService prnter = null;
        PrintService[] svs = PrinterJob.lookupPrintServices();
        for(PrintService sv:svs){
            System.out.println(sv.getName());
            if(sv.getName().contains(name)) prnter = sv;
        }
        return prnter;
    }
}

実行結果(Windows 10)

 プリンタサービスの一覧を表示してから、自動でMP493を選択しています。A3限定のときに比べて一覧のサービスの数が増えています。

実行時の端末表示(Windows)
PS Z:\java\print03> java PrinterSelectTest02
OneNote
Microsoft XPS Document Writer
Microsoft Print to PDF
Fax
EPSON5AE8BC (PX-1700F)
EPSON PX-1700F
Canon MP493 series Printer
Canon Inkjet iP9910
---> Canon MP493 series Printer

実行結果(Linux)

 同じプリンタでも、プリンタ名は環境ごとに異なるものです。

実行時の端末表示(Linux)
adachi@debian64:~$ java PrinterSelectTest02
Canon_MP493_series
EPSON_EPSON_PX-1700F
---> Canon_MP493_series

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
(2)JISの封筒を指定する方法

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

  • このエントリーをはてなブックマークに追加
Javaの標準機能だけで実現する帳票印刷連載記事一覧

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11671 2020/06/22 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング