javaで帳票印刷 文章を印刷

所定枠に文章を印刷

通知表によくある所見欄を例に、所定枠に文章を印刷することを考えます。

ある程度長い文章を書いても自動的に改行してくれること、箇条書きのようなものにも対応することが求められます。 出来れば禁則処理もある程度取り込みたいところです。

入力時の操作方法が使い勝手に重要なところですが、帳票印刷がテーマなので、データがあるものとして書くところから始めます。

文章の表現としては、文字列のリストがいいでしょう。

いままでのデータと同様にするなら生徒番号をキーとした文字列のリストのMapとして、SetHRData.javaでデータを用意するという事になります。SetHRData.javaの中に書き込むよりファイルにしておいて読むほうが作成が楽なので、そのようにします。ふと、それならばSetHRData.javaのなかで読むのではなく、ファイル名のMapを渡して書く時に読むので良いのではないかとも考えたのですが、print()内に置くと1人に付き2回は呼ばれますのでこれはやめておきます。

ファイルを読んでリストにするのに、Files.readAllLines()メソッドを使うことにしました。これにについて詳しくは、ファイルから文字列を読んでListに格納を参照してください。

データ収集 SetHRData.javaに追加

他のデータと同パターンにします

ListなのはFiles.readAllLines()の戻り値がListだからです。

SetHRData.java フィールドとコンストラクタに追加

LinkedHashMap<Integer,List<String>> shokenmap;
public SetHRData(int nendo, String HR, int gakki){
     ....
    setNameMap();
    nmax = namemap.size();
    setSeisekiMap(kams);
    setShukketsuMap();
    setTanis(kams);
    setShokenMap();
}

SetHRData.java メソッド追加

private void setShokenMap(){
    shokenmap = new LinkedHashMap<Integer,List<String>>();
    for (int n=1;nmax>=n;n++){
        String fname = HR+String.format("%02d",n)+"tsu"+gakki+".txt";
        String pwd = getClass().getResource("").getPath()+"/data";
        List<String> list = null; //Collections.emptyList();
        Path path = Paths.get(pwd,fname);
        if(Files.notExists(path)) continue;
        try {
            list = Files.readAllLines(path, UTF_8 );
            if (list.size()>0) shokenmap.put(n,list);
        }catch (IOException e) {
            System.err.println( e);
        }
	}
}

public LinkedHashMap<Integer,List<String>> getShokenMap(){
    return shokenmap;
}

ファイル名は data/1A03tsu1.txt などとします。

Files.readAllLines()メソッドについて詳しくは、ファイルから文字列を読んでListに格納を参照してください。(再掲)

本体 TsuuchiHR改めTsuuchiBun.javaに追加

フィールド、引数、フィールドに代入

TsuuchiBun.javaの一部

LinkedHashMap<Integer,List<String>> shokenmap;
...
    LinkedHashMap<Integer,List<String>> shokenmap,
    ...
    this.shokenmap = shokenmap;

mainからの呼び出しはSetHRDataのインスタンスを作って、getShokenMap()メソッドを使う。

public static void createAndShowGUI() {
    SetHRData hrdata = new SetHRData(2017,"1A",gakki);
    ...
    LinkedHashMap<Integer,List<String>> shokenmap = hrdata.getShokenMap();

選択の後、選択されたものだけにする。

LinkedHashMap<Integer,List<String>> selshokenmap = new LinkedHashMap<>();
for (int no:selectedno){
    selnamemap.put(no,namemap.get(no));
    selseisekimap.put(no,seisekimap.get(no));
    selshukketsumap.put(no,shukketsumap.get(no));
    selshokenmap.put(no,shokenmap.get(no));
}
TsuuchiBun prevPrintable = new TsuuchiBun(
    selnamemap,selseisekimap,selshukketsumap,
    tanis,selshokenmap,gakki);  //printable instance xxx add sel-

本体 TsuuchiBun.javaの印字部分

枠を作ってその中に入れます。文字数制限はなく、プレビューではみ出さないことを確認します。

行間や、フォントの大きさで調整する余地がありますが、今回は固定としています。

TsuuchiBun.java

//備考
int bgpt = 0;
g2.setFont(font08);
vm = vtdtop+vptch*9f;
kp = new AjustString(g2,"所見",8f);
kp.drawKintou(hbas2+2f,vm+5f);
g2.setStroke(boldstroke);
line.setLR(hbas2,hbas2+hwhalf);
line.setY(vm);
g2.draw(line); //Rectangle TOP
line.setY(vm+vwbik);
g2.draw(line); //Rectangle bottom
line.setTB(vm,vm+vwbik);
line.setX(hbas2);
g2.draw(line); //Rectangle left
line.setX(hbas2+hwhalf);
g2.draw(line); //Rectangle right
g2.setFont(font10);
float fh10 = (float)(g2.getFontMetrics().getHeight()*pt2mm*1.4f); //改行幅
int ln=0;
vm = vm + fh10+2f;
List<String> bundata;
if( (bundata = shokenmap.get(n))!=null ){
    for(String bun :bundata){
        kp = new AjustString(g2,bun,hwhalf-4f);
        if(kp.hasNext()) kp.drawKintou(hbas2+2f,vm+fh10*(++ln));
        else             kp.drawLeft  (hbas2+2f,vm+fh10*(++ln));
        while((bgpt=kp.getNextPt()) > 0){
            kp = new AjustString(g2,bun,hwhalf-4f,bgpt);
            if(kp.hasNext()) kp.drawKintou(hbas2+2f,vm+fh10*(++ln));
            else             kp.drawLeft  (hbas2+2f,vm+fh10*(++ln));
        }
    }
}

実行結果とこれからの課題

テキストデータの作成は現時点ではエディタやワープロなどで作成しUTF-8で保存します。専用エディタを用意したいところです。

禁則処理はこれからです。現時点ではプレビューを見ながら文章を勘案して句読点が冒頭に来ないようにすることで回避します。