javaで帳票印刷 複数ページの印刷

複数ページを印刷する戦略

java.awt.print.Pageable というインターフェースや、それを実装した java.awt.print.Book を使ってもいいのですが、どのページも同じ書式で良いので、このままPrintableで進めます。

print()というメソッドが呼ばれる時に、ページ番号(pageIndex)が与えられますから、これを使って複数ページを書き分けます。

pageIndex != 0 だったところを 3 > pageIndex とすると、pageIndex=0,1,2 と変化しながら print()メソッドが呼び出されて印刷されます。

@Override
public int print(Graphics g, PageFormat pf, int pageIndex) {
    if (3 > pageIndex) return NO_SUCH_PAGE;

    Graphics2D g2 = (Graphics2D)g;
    g2.drawString((pageIndex+1)+"ページです", 72, 120); //文字の印字
    g2.drawLine(72,140,288,160);           //線の描画

    return PAGE_EXISTS;
}

配列やリストで複数ページのデータを用意して与えればページにそった内容を選択できます。

複数ページの印刷のためのデータ

複数ページの印刷のためにデータの見直しで作成したSetHRData.javaを使って、次の様に名簿番号をキーとするマップとして氏名(namemap)、成績(seisekimap)、そして出欠(shukketsumap)も用意します。名簿番号をキーとしていないのでmapという名にしませんでしたが、単位数は科目名をキーとするマップ(tanis)としました。成績の内容はさらに科目名をキーとした配列となっています。

ここでは帳票印刷の説明のためのテストデータでが、本来はファイルなどを読み込んで再構成します。テストデータですので1学期だけ、3人分だけ用意しています。

SetHRData hrdata = new SetHRData(2017,"1A",1);
LinkedHashMap<Integer,String> namemap = hrdata.getNameMap();
LinkedHashMap<Integer,LinkedHashMap<String,int[]>> seisekimap = hrdata.getSeisekiMap();
LinkedHashMap<Integer,int[][]> shukketsumap = hrdata.getShukketsuMap();
LinkedHashMap<String,Integer> tanis = hrdata.getTanis();
namemap;番号=>氏名
seisekimap;番号=>(科目名=>成績配列[学期])
shukketsumap;番号=>出欠配列[項目][学期]
tanis;科目名=>単位数

このデータを使ってプログラムを変更していきます

プログラム名は TsuuchiHR.java と変えます。

コンストラクタ冒頭です

TsuuchiHR.javaの一部

public TsuuchiHR(
    LinkedHashMap<Integer,String> namemap,
    LinkedHashMap<Integer,LinkedHashMap<String,int[]>> seisekimap,
    LinkedHashMap<Integer,int[][]> shukketsumap,
    LinkedHashMap<String,Integer> tanis,
    int gakki
){

@Overrideのprint()では引数が決まっていますから、データはフィールドに定義して this.namemap=namemap などとする必要があります。

print()ではpageIndexが 0,1,2,...と変わりながら、NO_SUCH_PAGEと返されるまで繰り返されます。

データ数が3の時は、pageIndexが0,1,2まで印刷し3なら印刷しないということなら良いわけですから、mapにあるデータの数だけ印刷するためには、データ数より大きいか等しいときにはNO_SUCH_PAGEと答えるようにするということです。

わざわざ変数pmaxを定義する必要はないのですが、わかりやすさのため入れています。

@Override
public int print(Graphics g, PageFormat pf, int pageIndex) {
    int pmax = seisekimap.size();
    if (pageIndex >= pmax) return NO_SUCH_PAGE; //pageIndex is 0,1,2,...
    Graphics2D g2 = (Graphics2D)g;
    drawPage(g2,pageIndex);
    return PAGE_EXISTS;
}

Mapからデータを取り出す

Mapを3つに分けたので、同じキーのデータを取り出す必要があります。

1番の生徒ならnamemap.get(1), seisekimap.get(1), shukketsumap.get(1)

map内のデータはkey-valueで入っていますから、番号順でないかも知れませんし、欠番があるかも知れません。Mapですから、keyを順番に取り出して処理をするのが定番でしょう。

for (int key : map.keySet())

ですが、今回はこうやって得られるkeyの0番だけ、1番だけ...というふうにしたいのです。

map.keySet()で得られるものはSetです。これにはget(n)のようなメソッドがありません。一度配列にして、要素を持ってくるしかなさそうです。

Object[] toArray() か、<T> T[] toArray(T[] a) が使えます。

最初はint[]にしようとして失敗し、Integer[]を試します。keySet()が T[] a の要素数より多い時は新しいT[]を定義して返します。それが一行目。そのpageIndex番目の値を使います。取り出した値をintの変数に代入するのは文句を言われません(2行目)。

Integer[] narray = namemap.keySet().toArray(new Integer[0]);
int n = narray[page];

どうせ代入するなら、Object[]で受けておいて、代入時にキャストしてもよいようです。こちらがわかりやすい。

Object[] narray = namemap.keySet().toArray();
int n = (int)narray[page];

面倒なところの発想になったのはint[]に指定できると思ってしまったからです。

print01/TsuuchiHR.java:120: エラー: toArrayに適切なメソッドが見つかりません(int[])
        int[] narray = namemap.keySet().toArray(new int[0]);
                                       ^
    メソッド Set.<T#1>toArray(T#1[])は使用できません
      (推論型は宣言された境界に適合しません
        推論: int
        境界: Object)
....

番号がわかってしまえば、Mapから取り出すだけです。kamokutensmap.size()はよく使うので、int kmaxに代入しておきます

String name = namemap.get(n);
LinkedHashMap<String,int[]> kamokutensmap = seisekimap.get(n);
int kmax = kamokutensmap.size();
int[][] ks = shukketsumap.get(n);

学期の扱い

kamokutensmap.get(kamokumei) で得られるのはint[]で、[0,1,2,3]の要素が[1学期,2学期,3学期,学年]の成績になります。

初めての言及になりますが、2学期には2学期だけの成績を書くのではなく、1,2学期の成績を書きます。3学期には学年まで全部を書きます。

1学期の成績は

kamokutensmap.get(kamokumei)[0]

で得られます。学期はgakkiですが、gakkiは1,2,3と変化させます。配列の添字は、

gakki=1のとき、0
gakki=2のとき、0,1
gakki=3のとき、0,1,2,3

と変化させなければなりません。

まず無条件で 1学期を書きます。

int gk = 0;
kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点1 数値
hm = hbas+hwkm+hwtn;
kp.drawCenter(hm,vm);

2,3学期の時は追加します。

if(gakki>=2){
    gk = 1;
    kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点2 数値
    kp.drawCenter(hm+hptch,vm);
}
if(gakki>=3){
    gk = 2;
    kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点3 数値
    kp.drawCenter(hm+hptch*2,vm);
    kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk+1]), hptch);//評点5 数値
    kp.drawCenter(hm+hptch*3,vm);
}

ちなみに、2学期の時に2学期だけを書くという通知表もあるでしょう。1学期のときの紙に2学期を追加で印字するというのもあるかもしれません。そのときには、罫線を書かない、科目名を書かないなどの選択が必要になります。2学期からの転入も考えると[書く/書かない]の選択ができるようになっている必要があります。

出欠の部分

gakki>gkとして繰り返し、gakki==3のときに更に合計を加えます。forの中で足し算をしておきます。

int[] kssum = new int[6];
for (int gk = 0; gakki>gk; gk++){
    hm = hbas2+hwssk+hptch*gk;
    int zd = ks[0][gk];
    kp = new AjustString(g2,String.valueOf(zd),hptch); //授業日数
    kp.drawCenter(hm,vm+vptch);
    kp = new AjustString(g2,String.valueOf(ks[1][gk]),hptch); //1:忌引き
    kp.drawCenter(hm,vm+vptch*2);
    kp = new AjustString(g2,String.valueOf(zd-ks[1][gk]),hptch);
    kp.drawCenter(hm,vm+vptch*3);
    kp = new AjustString(g2,String.valueOf(ks[2][gk]),hptch); //2:欠席
    kp.drawCenter(hm,vm+vptch*4);
    kp = new AjustString(g2,String.valueOf(zd-ks[1][gk]-ks[2][gk]),hptch);
    kp.drawCenter(hm,vm+vptch*5);
    kp = new AjustString(g2,String.valueOf(ks[3][gk]),hptch); //3: 遅刻
    kp.drawCenter(hm,vm+vptch*6);
    kp = new AjustString(g2,String.valueOf(ks[4][gk]),hptch); //4:早退
    kp.drawCenter(hm,vm+vptch*7);
    kp = new AjustString(g2,String.valueOf(ks[5][gk]),hptch); //5:欠課時数
    kp.drawCenter(hm,vm+vptch*8);
    for(int i=0; kssum.length>i; i++) kssum[i]+=ks[i][gk];
}
if(gakki==3){
    hm = hbas2+hwssk+hptch*3;
    int zd = kssum[0];
    kp = new AjustString(g2,String.valueOf(zd),hptch); //授業日数
    kp.drawCenter(hm,vm+vptch);
    kp = new AjustString(g2,String.valueOf(kssum[1]),hptch); //1:忌引き
    kp.drawCenter(hm,vm+vptch*2);
    kp = new AjustString(g2,String.valueOf(zd-kssum[1]),hptch);
    kp.drawCenter(hm,vm+vptch*3);
    kp = new AjustString(g2,String.valueOf(kssum[2]),hptch); //2:欠席
    kp.drawCenter(hm,vm+vptch*4);
    kp = new AjustString(g2,String.valueOf(zd-kssum[1]-kssum[2]),hptch);
    kp.drawCenter(hm,vm+vptch*5);
    kp = new AjustString(g2,String.valueOf(kssum[3]),hptch); //3:遅刻
    kp.drawCenter(hm,vm+vptch*6);
    kp = new AjustString(g2,String.valueOf(kssum[4]),hptch); //4:早退
    kp.drawCenter(hm,vm+vptch*7);
    kp = new AjustString(g2,String.valueOf(kssum[5]),hptch); //5:欠課時数
    kp.drawCenter(hm,vm+vptch*8);
}

プレビュー

paintComponent()にはとりあえず drawPage(g2,0); とページ番号として0を加えておきます。

プレビューでページを切り替えるのは次の課題とします。

プログラム(TsuuchiHR.java)

package print01のメンバーとして次のクラスも必要です。

AjustString.java 均等割付
AjustStringT.java 罫線を引く
Linemm.java 罫線を引く
SetHRData.java 複数ページの印刷のためにデータの見直し

TsuuchiHR.java

package print01;
import java.awt.*;
import java.awt.print.*;
import java.awt.geom.Line2D;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.HashPrintJobAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintJobAttributeSet;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaTray;
import javax.print.attribute.Attribute;
import javax.swing.*;
import static java.awt.RenderingHints.*;
import java.util.LinkedHashMap;
import java.util.Set;

//SwingUtilities.invokeLaterを使う--2--
//paintComponent()の振動抑制(non ImageBuffer第一号 見やすく訂正) --3--
//TsuuchiPrev.java=3 +Shukketsu
//2017-5-2 multipage print. preview yet.
public class TsuuchiHR extends JPanel implements Printable {
    public static final double a4longside  = 297d*72/25.4; // 841.88;
    public static final double a4shortside = 210d*72/25.4; // 595.27;
    public static final double pwidth = a4shortside;
    public static final double pheight = a4longside;
    public static final double wZh = pwidth/pheight;
    String[] kams;
    int[] tans, tens, ks;
    Dimension prevsize;
    double scale;
    int gakki = 0;
    LinkedHashMap<Integer,String> namemap;    //番号=>氏名
    LinkedHashMap<Integer,LinkedHashMap<String,int[]>> seisekimap;    //番号=>(科目名=>成績配列[学期])
    LinkedHashMap<Integer,int[][]> shukketsumap;    //番号=>出欠配列[項目][学期]
    LinkedHashMap<String,Integer> tanis;    //科目名=>単位数
    public TsuuchiHR(
        LinkedHashMap<Integer,String> namemap,
        LinkedHashMap<Integer,LinkedHashMap<String,int[]>> seisekimap,
        LinkedHashMap<Integer,int[][]> shukketsumap,
        LinkedHashMap<String,Integer> tanis,
        int gakki
    ){
        this.namemap = namemap;
        this.seisekimap = seisekimap;
        this.shukketsumap = shukketsumap;
        this.tanis = tanis;
        this.gakki = gakki;
        setBackground(Color.white);
        prevsize = new Dimension();
        prevsize.setSize(pwidth,pheight);
        setPreferredSize(prevsize);
    }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        int viewpw = getParent().getWidth();
        int viewph = getParent().getHeight();
        JScrollPane sp = (JScrollPane) getParent().getParent();
        int hbarh = sp.getHorizontalScrollBar().getHeight();
        int vbarw = sp.getVerticalScrollBar().getWidth();
        boolean hbarAri = sp.getHorizontalScrollBar().isVisible();
        boolean vbarAri = sp.getVerticalScrollBar().isVisible(); 
        if (vbarAri) viewpw += vbarw;
        if (hbarAri) viewph += hbarh;
        if((double)(viewpw-vbarw)/viewph > wZh){
            prevsize.setSize(viewpw-vbarw, (viewpw-vbarw)/wZh);
            scale = (viewpw-vbarw)/pwidth;
        }else if( wZh > (double)viewpw / (viewph-hbarh)  ){
            prevsize.setSize((viewph-hbarh)*wZh, viewph-hbarh);
            scale = (viewph-hbarh)/pheight;
        }else{
            if ( (double)viewpw/viewph > wZh ) {
                prevsize.setSize(viewph*wZh, viewph);
                scale = viewph/pheight;
            }else{
                prevsize.setSize(viewpw, viewpw/wZh);
                scale = viewpw/pwidth;
            }
        }
        setPreferredSize(prevsize);
        //System.out.println(scale); //test
        g2.scale(scale,scale);
        drawPage(g2,0);
    }
    @Override
    public int print(Graphics g, PageFormat pf, int pageIndex) {
        int pmax = seisekimap.size();
        if (pageIndex >= pmax) return NO_SUCH_PAGE; //pageIndex is 0,1,2,...
        Graphics2D g2 = (Graphics2D)g;
        drawPage(g2,pageIndex);
        return PAGE_EXISTS;
    }

    public void drawPage(Graphics2D g2, int page){
        //2 Integer[] narray = namemap.keySet().toArray(new Integer[0]);
        //2 int n = narray[page];
        Object[] narray = namemap.keySet().toArray();
        int n = (int)narray[page];
        //x int[] narray = namemap.keySet().toArray(new int[0]);
        //x int n = narray[page];
        String name = namemap.get(n);
        LinkedHashMap<String,int[]> kamokutensmap = seisekimap.get(n);
        int kmax = kamokutensmap.size();
        int[][] ks = shukketsumap.get(n);
        //&amp use tanis for tani
        //g2.setRenderingHint(KEY_TEXT_ANTIALIASING,VALUE_TEXT_ANTIALIAS_GASP);
        g2.setRenderingHint(KEY_ANTIALIASING,VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(KEY_TEXT_ANTIALIASING,VALUE_TEXT_ANTIALIAS_ON);
        //g2.setRenderingHint(KEY_TEXT_ANTIALIASING,VALUE_TEXT_ANTIALIAS_DEFAULT);
        float hbas = 22.0f;  //左端の位置
        float hwkm = 27.5f;  //科目名の幅
        float hwtn = 7f;     //単位数の幅
        float hptch = 45f/4;  //学期などの幅
        float vthtop = 41.01f; //ヘッダ行の上の位置
        float vtdtop = 64.01f; //行データの上の位置
        float vptch  = 9.8f;  //行データの各行の高さ
        float hwall = hwkm+hwtn+hptch*4;
        float mm2pt  = 72/25.4f;
        float pt2mm  = 25.4f/72;
        Font mfont11 = new Font("Serif", Font.PLAIN, 11);
        Font font10 = new Font("Serif", Font.PLAIN, 10);
        Font font09 = new Font("Serif", Font.PLAIN, 9);
        //Font font10 = new Font("IPA P明朝", Font.PLAIN, 10);
        BasicStroke boldstroke = new BasicStroke(1.0f);
        BasicStroke medmstroke = new BasicStroke(0.7f);
        BasicStroke thinstroke = new BasicStroke(0.0f);
        g2.setStroke(boldstroke);
        Linemm line = new Linemm();
        line.setTB(vthtop, vtdtop+vptch*kmax);
        line.setX(hbas);
        g2.draw(line);
        line.setX(hbas+hwall);
        g2.draw(line);
        line.setLR(hbas, hbas+hwall);
        line.setY(vthtop);
        g2.draw(line);
        line.setY(vtdtop+vptch*kmax);
        g2.draw(line);
        g2.setStroke(medmstroke);
        line.setY(vtdtop);
        g2.draw(line);

        g2.setStroke(thinstroke);
        line.setLR(hbas, hbas+hwall);
        for (int k=1; kmax>k; k++){ //1 not 0
            line.setY(vtdtop+vptch*k);
            g2.draw(line);
        }
        line.setTB(vthtop, vtdtop+vptch*kmax);
        line.setX(hbas+hwkm);
        g2.draw(line);
        for (int i=0; 4>i; i++){
            line.setX(hbas+hwkm+hwtn+hptch*i);
            g2.draw(line);
        }
        g2.setFont(font10);
        float padbtm = (vptch-g2.getFontMetrics().getHeight()*pt2mm)/2;
        float vm,hm;
        AjustString kp;
            kp = new AjustString(g2, "科目", hwkm-11f);
            kp.drawKintou(hbas+5.5f,vthtop+(vtdtop-vthtop)/2+g2.getFontMetrics().getHeight()*pt2mm/2);

            AjustStringT kt;
            kt = new AjustStringT(g2, "単位数" ,vtdtop-vthtop-6f);
            kt.drawTtoB(hbas+hwkm+hwtn/2,vthtop+3f);
            kt = new AjustStringT(g2, "一学期" ,vtdtop-vthtop-6f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch/2,vthtop+3f);
            kt = new AjustStringT(g2, "二学期" ,vtdtop-vthtop-6f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*1.5f,vthtop+3f);
            kt = new AjustStringT(g2, "三学期" ,vtdtop-vthtop-6f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*2.5f,vthtop+3f);
            kt = new AjustStringT(g2, "学年" ,vtdtop-vthtop-6f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*3.5f,vthtop+3f);

        int kamokuichi = 0;
        //for (int k=0; kmax>k; k++){
        for (String kamokumei: kamokutensmap.keySet()) {
            kamokuichi++;
            vm = vtdtop+vptch*kamokuichi-padbtm;
            kp = new AjustString(g2, kamokumei ,hwkm-2f);
            
            if(kp.hasNext()){  //長い科目名を2行に
                
                kp.drawLeft(hbas+1f,vm+padbtm*3/4-vptch/2);
                kp = new AjustString(g2, kamokumei ,hwkm-2f, kp.getNextPt());
                kp.drawRight(hbas+1f,vm+padbtm/2);
                /* Fontを小さくする作戦
                g2.setFont(new Font("Serif", Font.PLAIN, 6));
                kp = new AjustString(g2, kams[k] ,hwkm-2f);
                kp.drawKintou(hbas+1f,vm);
                g2.setFont(font10);
                */
            }else{
            
                kp.drawKintou(hbas+1f,vm);
            }
            kp = new AjustString(g2, String.valueOf(tanis.get(kamokumei)), hwtn);//単位数 数値
            kp.drawCenter(hbas+hwkm,vm);
            g2.setFont(mfont11);
            int gk = 0;
            kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点1 数値
            hm = hbas+hwkm+hwtn;
            kp.drawCenter(hm,vm);
            if(gakki>=2){
                gk = 1;
                kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点2 数値
                kp.drawCenter(hm+hptch,vm);
            }
            if(gakki>=3){
                gk = 2;
                kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk]), hptch);//評点3 数値
                kp.drawCenter(hm+hptch*2,vm);
                kp = new AjustString(g2, String.format("%3d",kamokutensmap.get(kamokumei)[gk+1]), hptch);//評点5 数値
                kp.drawCenter(hm+hptch*3,vm);
            }
            g2.setFont(font10);
        }
        //出欠
        float hwssk = hwkm+hwtn+7f;
        float hwhalf= hwssk+hptch*4;
        float hbas2 = hbas+hwall+3.8f;
        float vwbik = vptch*8f;
        g2.setStroke(boldstroke);
        line.setLR(hbas2,hbas2+hwhalf);
        line.setY(vthtop);
        g2.draw(line); //Rectangle TOP
        line.setY(vtdtop);
        g2.draw(line); //Rectangle th/td
        line.setY(vtdtop+vptch*8);
        g2.draw(line); //Rectangle th/td
        line.setTB(vthtop,vtdtop+vptch*8);
        line.setX(hbas2);
        g2.draw(line); //Rectangle left
        line.setX(hbas2+hwhalf);
        g2.draw(line); //Rectangle right
        g2.setStroke(thinstroke);
        for(int gk=1;4>=gk;gk++){
            line.setX(hbas2+hwhalf-hptch*gk);
            g2.draw(line); //tate hwssk|hptch|hptch|...
        }
        line.setLR(hbas2,hbas2+hwhalf);
        for(int i=1;8>i;i++){
            line.setY(vtdtop+vptch*i);
            g2.draw(line);
        }
        kp = new AjustString(g2, "項目",hwssk-16.4f);
        kp.drawKintou(hbas2+8.2f,vtdtop-(vtdtop-vthtop)/2+g2.getFontMetrics().getHeight()*pt2mm/2f);
        kt = new AjustStringT(g2, "一学期",vtdtop-vthtop-6f);
        kt.drawTtoB(hbas2+hwssk+hptch/2f,vthtop+3f);
        kt = new AjustStringT(g2, "二学期",vtdtop-vthtop-6f);
        kt.drawTtoB(hbas2+hwssk+hptch+hptch/2f,vthtop+3f);
        kt = new AjustStringT(g2, "三学期",vtdtop-vthtop-6f);
        kt.drawTtoB(hbas2+hwssk+hptch*2+hptch/2f,vthtop+3f);
        kt = new AjustStringT(g2, "学年",vtdtop-vthtop-6f);
        kt.drawTtoB(hbas2+hwssk+hptch*3+hptch/2f,vthtop+3f);
        vm = vtdtop-padbtm;
        hm = hbas2;
        kp = new AjustString(g2,"授業日数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch);
        g2.setFont(font09);
        kp = new AjustString(g2,"出校停止・忌引等の日数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*2);
        g2.setFont(font10);
        kp = new AjustString(g2,"出席すべき日数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*3);
        kp = new AjustString(g2,"欠席日数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*4);
        kp = new AjustString(g2,"出席日数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*5);
        kp = new AjustString(g2,"遅刻",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*6);
        kp = new AjustString(g2,"早退",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*7);
        kp = new AjustString(g2,"欠課時数",hwssk-4f);
        kp.drawKintou(hm+2f,vm+vptch*8);

        g2.setFont(mfont11);
        int[] kssum = new int[6];
        for (int gk = 0; gakki>gk; gk++){
            hm = hbas2+hwssk+hptch*gk;
            int zd = ks[0][gk];
            kp = new AjustString(g2,String.valueOf(zd),hptch); //授業日数
            kp.drawCenter(hm,vm+vptch);
            kp = new AjustString(g2,String.valueOf(ks[1][gk]),hptch); //1:忌引き
            kp.drawCenter(hm,vm+vptch*2);
            kp = new AjustString(g2,String.valueOf(zd-ks[1][gk]),hptch);
            kp.drawCenter(hm,vm+vptch*3);
            kp = new AjustString(g2,String.valueOf(ks[2][gk]),hptch); //2:欠席
            kp.drawCenter(hm,vm+vptch*4);
            kp = new AjustString(g2,String.valueOf(zd-ks[1][gk]-ks[2][gk]),hptch);
            kp.drawCenter(hm,vm+vptch*5);
            kp = new AjustString(g2,String.valueOf(ks[3][gk]),hptch); //3: 遅刻
            kp.drawCenter(hm,vm+vptch*6);
            kp = new AjustString(g2,String.valueOf(ks[4][gk]),hptch); //4:早退
            kp.drawCenter(hm,vm+vptch*7);
            kp = new AjustString(g2,String.valueOf(ks[5][gk]),hptch); //5:欠課時数
            kp.drawCenter(hm,vm+vptch*8);
            for(int i=0; kssum.length>i; i++) kssum[i]+=ks[i][gk];
        }
        if(gakki==3){
            hm = hbas2+hwssk+hptch*3;
            int zd = kssum[0];
            kp = new AjustString(g2,String.valueOf(zd),hptch); //授業日数
            kp.drawCenter(hm,vm+vptch);
            kp = new AjustString(g2,String.valueOf(kssum[1]),hptch); //1:忌引き
            kp.drawCenter(hm,vm+vptch*2);
            kp = new AjustString(g2,String.valueOf(zd-kssum[1]),hptch);
            kp.drawCenter(hm,vm+vptch*3);
            kp = new AjustString(g2,String.valueOf(kssum[2]),hptch); //2:欠席
            kp.drawCenter(hm,vm+vptch*4);
            kp = new AjustString(g2,String.valueOf(zd-kssum[1]-kssum[2]),hptch);
            kp.drawCenter(hm,vm+vptch*5);
            kp = new AjustString(g2,String.valueOf(kssum[3]),hptch); //3:遅刻
            kp.drawCenter(hm,vm+vptch*6);
            kp = new AjustString(g2,String.valueOf(kssum[4]),hptch); //4:早退
            kp.drawCenter(hm,vm+vptch*7);
            kp = new AjustString(g2,String.valueOf(kssum[5]),hptch); //5:欠課時数
            kp.drawCenter(hm,vm+vptch*8);
        }
        g2.setFont(font10);
        //return PAGE_EXISTS;
    }

     public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        int gakki = 1;
        SetHRData hrdata = new SetHRData(2017,"1A",gakki);  //printable instance
        LinkedHashMap<Integer,String> namemap = hrdata.getNameMap();
        LinkedHashMap<Integer,LinkedHashMap<String,int[]>>
               seisekimap = hrdata.getSeisekiMap();
        LinkedHashMap<Integer,int[][]> shukketsumap = hrdata.getShukketsuMap();
        LinkedHashMap<String,Integer> tanis = hrdata.getTanis();

        PrinterJob pj = PrinterJob.getPrinterJob();
        PrintRequestAttributeSet reqset = new HashPrintRequestAttributeSet();
        MediaSizeName medname = MediaSizeName.ISO_A4;
        //MediaSizeName medname = MediaSizeName.JAPANESE_POSTCARD;
        reqset.add(medname);

        MediaSize medsize = MediaSize.getMediaSizeForName(medname);
        float medwidth  = medsize.getX(MediaPrintableArea.MM);
        float medheight = medsize.getY(MediaPrintableArea.MM);
        float topmm   = 8.8f;  //landscape前のTOP
        float bottomm = 7.7f;
        float leftmm  = 6.6f;
        float rightmm = 5.5f;
        reqset.add(new MediaPrintableArea(
           leftmm, topmm,
           (medwidth - leftmm - rightmm),
           (medheight - topmm - bottomm), MediaPrintableArea.MM));
        //reqset.add(OrientationRequested.REVERSE_LANDSCAPE);
        //reqset.add(OrientationRequested.LANDSCAPE);
        reqset.add(OrientationRequested.PORTRAIT);

        TsuuchiHR prevPrintable = new TsuuchiHR(namemap,seisekimap,shukketsumap,tanis,gakki);  //printable instance
        JScrollPane scrollPane = new JScrollPane(prevPrintable);
        String[] goOrNot = {"印刷","中止"};
        JOptionPane pane = new JOptionPane(
                                   scrollPane, 
                                   JOptionPane.PLAIN_MESSAGE, 
                                   JOptionPane.DEFAULT_OPTION,
                                   null,goOrNot,goOrNot[0]
                               );
        //JDialog dialog = pane.createDialog( null, "印刷プレビュー" );
        JDialog dialog = pane.createDialog("印刷プレビュー" );
        dialog.pack();
        dialog.setResizable(true);
        dialog.setVisible(true);
        dialog.dispose(); //needs for ends /set HIDE_ON_CLOSE by default
        String svalue = (String)pane.getValue();
        if(! (svalue==null || !svalue.equals("印刷"))){// System.exit(0);
            pj.setPrintable(prevPrintable);  //printable instance
            System.out.println(pj.getPrintService().getName()); //test
            if (pj.printDialog( reqset )) {
                boolean debug = true;
                if(debug){
                    Attribute[] attrs = reqset.toArray(); //test
                    for(int n=0 ; attrs.length > n ; n++){ //test
                        System.out.println( attrs[n].getName()+":"+ attrs[n].toString()+";; ");
                    }
                }
                try { pj.print( reqset ); }
                catch (PrinterException e) {
                    System.err.println(e);
                }
            }
        }
        //System.out.println("...");
        //dialog.dispose();
    }
}

実行結果