SHOEISHA iD

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

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

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

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

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

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


用紙の向きと余白の関係を確認するプログラム

 前項で説明したことを確認するプログラムです。引数で向きを変えることができます。引数がなければ、PORTRAITです。0:LANDSCAPE、1:PORTRAIT、2:REVERSE_LANDSCAPE、3:REVERSE_PORTRAITです。

 print()メソッドの中で、引数として与えられるPageFormatクラスのインスタンスから余白などの情報を得て書き出しています。実行しているOSや使用したプリンタ、年月日なども書かせていますが、テストのための工夫であって、実際の帳票印刷では使うことはないでしょう。

 このプログラムでは印字位置をわざわざ余白の値を使って合わせていますが、用紙の辺からの長さで指定すれば余白からは影響を受けません。

OriTest.java
import java.awt.*;
import java.awt.geom.*;
import java.awt.print.*;
import static java.awt.Font.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import java.time.*;
import java.time.format.*;

/** OriTest.java 
    Orientation と 余白の関係の調査
    2019-05-21 adachi
*/
public class OriTest implements Printable {
    String PRINTER = "unknown";  //printername
    @Override
    public int print(Graphics g, PageFormat pf, int pageIndex) {
        if (pageIndex != 0) return NO_SUCH_PAGE;
        Graphics2D g2 = (Graphics2D)g;
        Font fs12 = new Font(SANS_SERIF, PLAIN, 12);
        g2.setFont(fs12);
        g2.setStroke(new BasicStroke(0.0f));
        float mm2pt = 72/25.4f;

        double ix = pf.getImageableX();
        double iy = pf.getImageableY();
        double iw = pf.getImageableWidth();
        double ih = pf.getImageableHeight();
        Rectangle2D.Double rectg = new Rectangle2D.Double(ix, iy, iw, ih);
        g2.draw(rectg);
        g2.setPaint(Color.RED);
        rectg = new Rectangle2D.Double(ix+1, iy+1, iw-2, ih-2);
        g2.draw(rectg);
        g2.setPaint(Color.BLACK);

        float yptch = 6.0f*mm2pt;
        float xp = (float)ix + 2f*mm2pt;
        float yp = (float)iy + yptch;
        int ct = 1;
        g2.drawString(System.getProperty("os.name"), xp, yp);  //osname
        g2.drawString(PRINTER, xp, yp+yptch*ct++);  //printer name

        double pt2mm = 25.4/72;
        String sfmt = "%s:%5.1f %s:%5.1f";
        double pwmm = pf.getWidth()*pt2mm;
        double phmm = pf.getHeight()*pt2mm;
        double ixmm = ix*pt2mm;
        double iymm = iy*pt2mm;
        double iwmm = iw*pt2mm;
        double ihmm = ih*pt2mm;
        String whx = String.format(sfmt,"W",pwmm,"H",phmm);
        g2.drawString(whx, xp, yp+yptch*ct++);
        whx = String.format(sfmt,"L",ixmm,"R",pwmm-ixmm-iwmm);
        g2.drawString(whx, xp, yp+yptch*ct++);
        whx = String.format(sfmt,"T",iymm,"B",phmm-iymm-ihmm);
        g2.drawString(whx, xp, yp+yptch*ct++);
        int ori = pf.getOrientation();
        g2.drawString("0:LAND 1:PORT 2:RevL =[ "+ori+" ]", xp, yp+yptch*ct++);
        String muki = "Unknown";
        if (ori==PageFormat.LANDSCAPE) muki = "LANDSCAPE";
        if (ori==PageFormat.PORTRAIT) muki = "PORTRAIT";
        if (ori==PageFormat.REVERSE_LANDSCAPE) muki = "REVERSE_LANDSCAPE";
        g2.drawString(muki , xp, yp+yptch*ct++);
        LocalDateTime d = LocalDateTime.now();
        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        g2.drawString(d.format(f), xp, yp+yptch*ct++);
        return PAGE_EXISTS;
        }

    public static void main(String[] args) {
        PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
        MediaSizeName msname = MediaSizeName.JAPANESE_POSTCARD;
        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 = 20.2f;
        float T = 10.3f;
        float B = 20.4f;
        rqset.add(new MediaPrintableArea(
            L, T, (mwidth - L - R), (mheight - T - B),
            MediaPrintableArea.MM));
        if(args.length==0){
            rqset.add(OrientationRequested.PORTRAIT);
            System.out.println("0:LAND. 1:PORT. 2:RevL. 3:RevP. none:PORT.");
        }else if(args[0].equals("0")){
            rqset.add(OrientationRequested.LANDSCAPE);
        }else if(args[0].equals("1")){
            rqset.add(OrientationRequested.PORTRAIT);
        }else if(args[0].equals("2")){
            rqset.add(OrientationRequested.REVERSE_LANDSCAPE);
        }else if(args[0].equals("3")){
            rqset.add(OrientationRequested.REVERSE_PORTRAIT);
        }
        OriTest pable = new OriTest();
        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(pable);

        if (pj.printDialog(rqset)) {
            pable.PRINTER=pj.getPrintService().toString();  //printername
            try { 
                pj.print(rqset); 
            }
            catch (PrinterException e) {
                System.err.println(e);
            }
        }
    }
}

PrinterJobで用紙サイズや余白を指定する印刷の実例

 より正確にはプリンタ選択をせずに、PrinterJobを使って用紙サイズや向き、余白を指定して印刷する段階の総まとめ的な実例です。あまり使いそうもないCopiesの代わりにOrientationRequestedを入れました。

 メインはmainの部分ですが、描画内容も「SomethingPrintable00.java」とは変えて、余白や向きの指定と印刷位置の指定が独立していることと、余白が画像をクリップする様子を確認できるようにしました。

 また、色の指定と一点鎖線の例も入れました。

SomethingPrintable01.java
import java.awt.*;
import java.awt.geom.*;
import java.awt.print.*;
import static java.awt.Font.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import java.time.*;
import java.time.format.*;

/** SomethingPrintable01.java 
    PrintRequestAttributeSet と PrinterJobを使い
    Service を使わない帳票印刷の典型例
    プログラム中のコメント行の変更だけで
    A3,A4,葉書のどれかと縦置き、横置きの組み合わせで印刷できます
    2019-05-26 adachi
*/
public class SomethingPrintable01 implements Printable {
    @Override
    public int print(Graphics g, PageFormat pf, int pageIndex) {
        if (pageIndex != 0) return NO_SUCH_PAGE;
        Graphics2D g2 = (Graphics2D)g;
        g2.setFont(new Font(SERIF, PLAIN, 12));
        float mm2pt = 72/25.4f;
        float x0 = 0.0f*mm2pt;
        float y0 = 10.5f*mm2pt;
        float p  = 1.0f*mm2pt;
        float h3 = 3.0f*mm2pt;
        float h5 = 5.0f*mm2pt;
        float h7 = 7.0f*mm2pt;
        float h10 = 10.0f*mm2pt;
        g2.setStroke(new BasicStroke(0f));
        Line2D line = new Line2D.Float();
        line.setLine(x0, y0, x0+50.0f*mm2pt, y0);
        g2.draw(line);
        float x,ye;
        for(int i=0;50>=i;i++){
            x  = x0 + p*i;
            ye = (i%5==0) ?h5:h3;
            ye = (i%10==0)?h7:ye;
            line.setLine(x, y0, x, y0+ye);
            g2.draw(line);
        }
        g2.setFont(new Font(SANS_SERIF, PLAIN, 9));
        g2.drawString("PrintableAreaの外側は印字されないことの確認", p*12, y0+h10);

        x0 = 20.5f*mm2pt;
        y0 = 30.5f*mm2pt;
        g2.setColor(Color.RED);
        line.setLine(x0, y0, x0+h5, y0);
        g2.draw(line);
        g2.setColor(new Color(0xff6600));
        line.setLine(x0, y0, x0, y0+h5);
        g2.draw(line);
        g2.setColor(Color.GREEN);
        line.setLine(x0, y0, x0-h5, y0);
        g2.draw(line);
        g2.setColor(Color.BLUE);
        line.setLine(x0, y0, x0, y0-h5);
        g2.draw(line);
        String sfmt = "交点の座標は X:%5.1f Y:%5.1f";
        String whx = String.format(sfmt,x0/mm2pt,y0/mm2pt);
        g2.drawString(whx, x0+h7, y0);
        g2.setColor(Color.BLACK);

        x0 = 15.2f*mm2pt;
        y0 = 40.5f*mm2pt;
        g2.drawString("一点鎖線を描いておきます", x0, y0);
        float[] dash = {12.0f, 2.0f, 1.0f, 2.0f};
        BasicStroke hasen = new BasicStroke(
            0.5f,
            BasicStroke.CAP_BUTT,
            BasicStroke.JOIN_MITER,
            10f, dash, 0f);
        g2.setStroke(hasen);
        line.setLine(x0, y0+h3, x0+40*mm2pt, y0+h3);
        g2.draw(line);

        y0 = 50.5f*mm2pt;
        g2.drawString(System.getProperty("os.name"), x0, y0); 
        LocalDateTime d = LocalDateTime.now();
        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        g2.drawString(d.format(f), x0, y0+h5);
        return PAGE_EXISTS;
    }

    public static void main(String[] args) {
        Printable pable = new SomethingPrintable01();
        PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
        //MediaSizeName msname = MediaSizeName.ISO_A3; //A3用紙
        //MediaSizeName msname = MediaSizeName.ISO_A4; //A4用紙
        MediaSizeName msname = MediaSizeName.JAPANESE_POSTCARD; //葉書
        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));
        rqset.add(OrientationRequested.LANDSCAPE);
        //rqset.add(OrientationRequested.REVERSE_LANDSCAPE);
        //rqset.add(OrientationRequested.PORTRAIT);//縦の場合
        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(pable);
        if (pj.printDialog(rqset)) {
            try { pj.print(rqset); }
            catch (PrinterException e) {
                System.err.println(e);
            }
        }
    }
}

 余白は小さめに固定するということにしました。なんなら、L,R,T,B別々の指定ををやめ、共通のMにして、

float M = 10.0f;
rqset.add(new MediaPrintableArea(
    M, M, (mwidth - 2*M), (mheight - 2*M),
    MediaPrintableArea.MM));

とするのもいいかもしれません。

次のページ
実行結果:PrinterJobでの印刷の評価

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

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

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

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

イベント

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

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

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

メールバックナンバー