SHOEISHA iD

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

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

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

縦書きのための均等割付と宛名自動改行印刷

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

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

葉書縦書き宛名プログラム縦棒・漢数字版

 上記の改良版です。これまでに書いた縦棒の対策に加え、フォントの選択を起動時引数で行い、合致するフォントがない場合はIPAex系のフォントにしようとし、それも失敗すれば論理フォントを使うようにしています。

PostcardsJushoVer.java 縦棒・漢数字版
/** PostcardsJushoVer.java
 PostcardsJushoHor.javaの縦書き版
 宛名を縦書きにし、1行に入り切らない時は複数行に分けます。
 プレビューはMultiPageDialogを適用
 枠に合わせて描画も拡大・縮小、JScrollPaneも使用します。
 AddressListを使って複数の宛名を扱います。
 ハイフォンなどを縦にし数字を漢数字にします。
 2019-12-02
@author Adachi Junichi
@version 3.0
*/
import java.awt.*;
import java.awt.print.*;
import java.util.List;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.swing.*;

public class PostcardsJushoVer extends JPanel implements Printable,MultiPageViewable {
    List<Person> hitos;
    int previewpage = 0;
    double wZh;
    Dimension motodims  = new Dimension();
    Dimension scaledims = new Dimension();
    float mm2pt = 72/25.4f;
    double trdx = 0;
    double trdy = 0;
    PrintRequestAttributeSet rqset ;
    double ratio = 1.0d; //用紙サイズに応じてsetPanelSize()で再設定
    String FONTSERIF = Font.SERIF; //①
    String FONTSANS  = Font.SANS_SERIF;
    String recSERIF = "IPAex明朝";
    String recSANS  = "IPAexゴシック";
    public PostcardsJushoVer(List<Person> hitos){
        this.hitos = hitos;
        setBackground(Color.white);
        setFontSans(recSANS);
        setFontSerif(recSERIF);
        rqset = new HashPrintRequestAttributeSet();
        //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 = 5.1f;
        float R = 5.2f;
        float T = 5.3f;
        float B = 5.4f;
        rqset.add(new MediaPrintableArea(
            L, T, (mwidth - L - R), (mheight - T - B),
            MediaPrintableArea.MM));
        setPanelSize(mwidth,mheight);
    }
    /**プレビューのサイズ、拡大率を設定する*/
    public void setPanelSize(float w,float h){
        motodims.setSize(w*mm2pt,h*mm2pt); 
        setPreferredSize(motodims);
        wZh = motodims.getWidth()/motodims.getHeight();
        ratio = 2.0d; //葉書は小さいので初期2倍で表示
    }
    public void setFontSerif(String f){ //②
        if (Font.decode(f).getFontName().equals(f)) {
            FONTSERIF = f;
        }else if(Font.decode(recSERIF).getFontName().equals(recSERIF)){
            FONTSERIF = recSERIF;
        }else{
            FONTSERIF = Font.SERIF;
        }
        //System.out.println(FONTSERIF+" /");
    }
    public void setFontSans(String f){ //③
        if (Font.decode(f).getFontName().equals(f)) {
            FONTSANS = f;
        }else if(Font.decode(recSERIF).getFontName().equals(recSERIF)){
            FONTSANS = recSANS;
        }else{
            FONTSANS = Font.SANS_SERIF;
        }
        //System.out.println(FONTSANS+" /");
        // if (Font.decode(f)!=null) does not work
    }
    @Override
    public double getRatio(){
        return ratio;
    }
    @Override
    public int incPreviewPage(){
        previewpage++;
        if (previewpage>=hitos.size()) previewpage=0;
        repaint();
        return previewpage;
    }
    @Override
    public int decPreviewPage(){
        previewpage--;
        if (0>previewpage) previewpage = hitos.size()-1;
        repaint();
        return previewpage;
    }
    @Override
    public int number(){
        return hitos.size();
    }
    @Override
    public String getStatus(){
        String retv;
        if(hitos.size()==0){
            retv ="....";
        }
        else{
            retv = (previewpage+1)+"/"+hitos.size();
        }
        return retv;
    }
    @Override
    public String getCurrentData(){
        String retv;
        Person hito = hitos.get(previewpage);
        retv = hito.zip+" "+hito.addr +"/"+ hito.name;
        return retv;
    }
    //spinner-bidou
    @Override
    public void setTrdx(double x){
        trdx = x*mm2pt;
        //System.out.println("trdx:"+trdx);//test
    }
    //spinner-bidou
    @Override
    public void setTrdy(double y){
        trdy = -y*mm2pt;
    }
    @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;
        double scale;
        if((viewpw-vbarw)/(double)viewph > wZh){
            scaledims.setSize(viewpw-vbarw, (viewpw-vbarw)/wZh);
            scale = (viewpw-vbarw)/motodims.getWidth();
        }else if( wZh > (double)viewpw / (viewph-hbarh)  ){
            scaledims.setSize((viewph-hbarh)*wZh, viewph-hbarh);
            scale = (viewph-hbarh)/motodims.getHeight();
        }else{
            if ( (double)viewpw/viewph > wZh ) {
                scaledims.setSize(viewph*wZh, viewph);
                scale = viewph/motodims.getHeight();
            }else{
                scaledims.setSize(viewpw, viewpw/wZh);
                scale = viewpw/motodims.getWidth();
            }
        }
        g2.scale(scale,scale);
        setPreferredSize(scaledims);
        drawPage(g2,previewpage);
    }
    @Override
    public int print(Graphics g, PageFormat pf, int pageIndex) {
        if (pageIndex >= hitos.size()) return NO_SUCH_PAGE;
        Graphics2D g2 = (Graphics2D) g;
        drawPage(g2,pageIndex);
        return PAGE_EXISTS;
    }
    public void drawPage(Graphics2D g2,int idx){
        g2.translate(trdx,trdy); 
        String zip = hitos.get(idx).zip;
        String tmp = hitos.get(idx).addr;
        String addr = ExchChar.numToo(tmp);  //④
        //String addr = ExchChar.hyphen(tmp);

        String name = hitos.get(idx).name;
        g2.setColor(Color.BLACK);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                            RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
        float xzip1 = 44.0f;
        float xzip2 = 66.0f;
        float xpch1 = 13.9f/2;
        float xpch2 = 20.5f/3;
        float wzbox = 5.7f;
        float yzip  = 20.3f;
        float vzip  = 8.3f;
        g2.setFont(new Font(FONTSANS, Font.PLAIN, 16));

        float padb = 1.5f; //yzipそのままだと下線に接するのでもどす値(mm)
        AdjustString ads;
        for(int i=0; 3>i; i++){
            ads = new AdjustString(g2, zip.substring(i,i+1),wzbox);
            ads.drawCenter(xzip1 + xpch1*i, yzip - padb);
        }
        for(int i=0; 4>i; i++){
            ads = new AdjustString(g2, zip.substring(i+4,i+1+4),wzbox);
            ads.drawCenter(xzip2 + xpch2*i, yzip - padb);
        }
        float yaddr = 25f;
        float haddr = 94f;
        float xaddr = 87f;
        float xpch  = -7.5f;
        float yname = 32f;
        float xname = 53f;
        float hname = 87f;

        g2.setFont(new Font(FONTSERIF, Font.PLAIN, 16)); //⑤
        AfureStringV afv;
        afv = new AfureStringV(g2,addr,haddr);
        afv.drawTop(xaddr, yaddr);
        int ct = 0;
        while(afv.hasNext()){
            afv.nextLine();
            afv.drawBottomEnx(xaddr + xpch*(++ct), yaddr); //⑥
        }
        g2.setFont(new Font(FONTSERIF, Font.PLAIN, 18));
        AdjustStringV adv;
        adv =  new AdjustStringV(g2,name+"様",hname);
        adv.drawTtoB(xname, yname);
    }
    public void doPrint() {
        PrinterJob pj = PrinterJob.getPrinterJob();
        pj.setPrintable(this);
        if (pj.printDialog(rqset)) {
            try { pj.print(rqset); }
            catch (PrinterException e) {
                System.err.println(e);
            }
        }
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                String arg = (args.length>0)? args[0]: "x"; //⑦
                createAndShowGUI(arg);
            }
        });
    }
    public static void createAndShowGUI(String arg) {
        if (arg.equals("0")) arg="Serif.plain";    //⑧
        if (arg.equals("1")) arg="KouzanBrushFont";
        if (arg.equals("2")) arg="衡山毛筆フォント";
        if (arg.equals("3")) arg="青柳衡山フォントT";
        if (arg.equals("4")) arg="HG行書体";
        if (arg.equals("5")) arg="HG正楷書体-PRO";
        String fname = "kakuujusho.txt";   //⑩
        List<Person> ls = AddressList.readTextFile(fname);
        PostcardsJushoVer pable = new PostcardsJushoVer(ls);
        if (!arg.equals("x")) pable.setFontSerif(arg); //⑨
        MultiPageDialog dialog = new MultiPageDialog(null,true,pable);
        dialog.setTitle(fname);
        dialog.pack();
        dialog.showDialog();
        while (dialog.getValue()==1){
            System.out.println("印刷を開始");
            pable.doPrint();
            System.out.println("印刷を終了");
            dialog.showDialog();
            //retv = dialog.showDialog();
        }
        System.out.println("Canseled:"+dialog.getValue());
        dialog.dispose();

    }
}

PostcardsJushoVer.javaの解説

  • ①フォントの選択に使います。環境に合わせてインストールしてあるフォントを書けばいいのですが、よく使うものを一箇所に書いておく方が変更しやすいでしょう。また、指定したフォントがない場合にデフォルトの近いフォントになってしまいます。今回は指定したフォントがない場合にIPAex系のフォントになるように工夫しました。FONTSERIFは明朝系のよく使うフォントを入れておく文字列です。recSERIFは指定したものがない時に代替えさせるデフォルトのフォントです。SANSはゴシック系。これは確実に存在するフォントを指定します
  • ②setFontSerif()はコンストラクタから呼ばれrecSERIFが使えれば、それをFONTSANSに設定し、使えなければ論理フォントのFont.SANS_SERIFを設定します。使えるかどうかは、文字列からdecode()で探したフォントの名前が元の文字列と等しいことで判断します
  • ③は②のゴシック系のものです
  • ④は住所の文字列を文字置換に通しています。ハイフォンだけならhyphen()、数字もならnumtoo()にします。名前にも長音符が必要な人がいるなら、これも通します
  • ⑤フォントの指定ではFONTSERIFなどの文字変数を使用します。以前は直接リテラル値を書いていました
  • ⑥文字列の中にグリフのないハイフォンが混ざっている可能性のあるところは、drawBottom()の代わりにdrawBottomEnx()メソッドを使います。住所の1行目にも出てくるならば、drawTop()もdrawTopEnx()にします
  • ⑦~⑨いろいろなフォントを試すために書いていますが、通常は不要なものです。起動時の引数に一文字入れてフォントを選択するようになっています。⑦では引数がなければ"x"にします
  • ⑧では引数の数字に対して、あらかじる調べてあるフォント名を当てています
  • ⑨ではPostcardsJushoVerのインスタンスpableにsetFontSerif()メソッドでそのフォントを設定するように指示しています。ここに書いてあるフォント名はWindows 10のものとLinuxのものが混在していて、環境にそのフォントがない場合はメソッド内でIPAex明朝に設定されます
  • ⑩印刷対象の宛名の入ったファイルの名前です

 このプログラムのコンパイルと実行には次のプログラムが同一フォルダに必要です。「AfureStringV.java」はEnxの拡張されたメソッドが追加されたものが必要です。

MultiPageViewable.java
ExchChar.java
AddressList.java
AdjustString.java
AdjustStringV.java
AfureStringV.java

Enx拡張のAfureStringV.java

 drawBottomEnx()、drawTopEnx()、drawTtoBEnx()、drawMidEnx() を追加したものを再掲載しておきます。

AfureStringV.java
/**
文字列を指定幅に改行しながら配置する-縦書き版
改行位置の候補文字列(文字列の末尾で改行)を配列で持つ。
候補文字が半角空白の場合はこれを印刷しない。
drawBottomEnx追加、Top,TtoB,Mid にも
U+FE32,U+FE31をU+007Cを縮小して代用する。
@author Adachi
@version 3.2
*/
import java.awt.Graphics2D;
import java.awt.FontMetrics;
import java.awt.Font;

public class AfureStringV {
    String zstr, str;
    float  wdmm;
    float  remm;
    int    zslen;
    int    nextjbgn;
    Graphics2D  g2;
    FontMetrics fm;
    Font  fnt;
    float mm2pt = 72/25.4f;
    float pt2mm = 25.4f/72;
    float ascent, mojih;
    float h2ascent = 0.9f;
    String[] afure = {" ","丁目","大字","字","郡","市","番地"};
    boolean debug = true;
    /** string の内、areawidth に入る最初の部分をstrに保持。 */
    public AfureStringV(Graphics2D g2, String string, float areawidth) {
        this(g2,string,areawidth,null,false);
    }
    /** string の内、areawidth に入る最初の部分をstrに保持。改行候補をafureにする */
    public AfureStringV(Graphics2D g2, String string, float areawidth, String[] afure) {
        this(g2,string,areawidth,afure,false);
    }
    /** string の内、areawidth に入る最初の部分をstrに保持。debugをtrueにできる */
    public AfureStringV(Graphics2D g2, String string, float areawidth, boolean debug){
        this(g2,string,areawidth,null,debug);
    }
    /** string の内、areawidth に入る最初の部分をstrに保持。
                        改行候補をafureにし、debugをtrueにできる */
    public AfureStringV(Graphics2D g2, String string, float areawidth,
                        String[] afure, boolean debug){
        this.g2 = g2;
        fm = g2.getFontMetrics();
        fnt = fm.getFont();
        zstr = (string!=null) ? string : "";  //nullなら""
        wdmm = (areawidth>=0f) ? areawidth : 0f;  //負なら0
        if(afure!=null)this.afure=afure;
        this.debug = debug;
        mojih = fm.getFont().getSize();
        ascent = mojih * h2ascent;

        zslen = zstr.length();
        nextjbgn = 0; //string-index not cp-index
        if(debug) System.out.println("constr:'"+zstr+"',"+wdmm);
        nextLine();
    }
    /** 次の行に書ける部分をstrに保持。 */
    public void nextLine(){
        //溢れ改行文字での改行はcpに踏み込まなくてもよい
        int jbgn = nextjbgn;
        str = zstr.substring(jbgn,zslen);
        int cpct = str.codePointCount(0,str.length());
        remm = wdmm - mojih*pt2mm*cpct;
        int afi = 0;
        if(debug) System.out.printf("AfreBegn:%s %3d %3d  %3.1f\n",str,jbgn,nextjbgn,remm);
        while(0>remm && afure.length>afi)  {
            if (str.indexOf(afure[afi])>=0){
                if (afure[afi].equals(" ") ){
                    nextjbgn = str.indexOf(afure[afi])+jbgn;
                    str = zstr.substring(jbgn,nextjbgn);
                    nextjbgn++;
                }else{
                    nextjbgn = str.indexOf(afure[afi])+jbgn+afure[afi].length();
                    str = zstr.substring(jbgn,nextjbgn);
                }
                cpct = str.codePointCount(0,str.length());
                remm = wdmm - mojih*pt2mm*cpct;
            }
            afi++;
        }
        if(debug) System.out.printf("Afre2dec:%s %3d %3d  %3.1f\n",str,jbgn,nextjbgn,remm);
        cpct = str.codePointCount(0,str.length());
        int maxcpct = (int)Math.floor(wdmm/mojih/pt2mm);
        if(maxcpct>cpct)maxcpct=cpct;
        remm = wdmm - mojih*pt2mm*maxcpct;
        int maxidx = str.offsetByCodePoints(0, maxcpct);
        str = str.substring(0,maxidx);
        nextjbgn  = jbgn + maxidx;
        if (nextjbgn>=zslen) nextjbgn = -1;
        if(debug) System.out.printf("output--:%s %3d %3d  %3.1f\n",str,jbgn,nextjbgn,remm);
    }
    /** 書くべき文字が残っている時trueを返す */
    public boolean hasNext(){
        return nextjbgn>=0;
    }
    /**縦書きを左寄せのように上に詰める。hmを中心線にする*/
    //str,fm,g2,mm2pt,mojih,ascent
    public void drawTop(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            fontwd = fm.stringWidth(str.substring(i,nexti));
            g2.drawString(str.substring(i,nexti),
                          hm*mm2pt-fontwd/2,
                          vm*mm2pt+mojih*cpcti+ascent);
            i=nexti;
            cpcti++;
        }
    }
    /**drawTop()のverticalEnDashのグリフのない時の対処版*/
    //str,fm,fnt,g2,mm2pt,mojih,ascent
    public void drawTopEnx(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        float smfsize;
        float smf;
        String s;
        float vbase = vm*mm2pt+ascent;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            s = str.substring(i,nexti);
            if( fnt.canDisplayUpTo(s)>=0 &&
                (s.equals("\uFE32")|| s.equals("\uFE31"))){
                smf = (s.equals("\uFE32"))? 0.5f :0.8f;
                smfsize = fnt.getSize()*smf;
                g2.setFont(fnt.deriveFont(smfsize));
                s = "\u007C";
                fontwd = g2.getFontMetrics().stringWidth(s); //not fm
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*(cpcti-0.5f)+smfsize/2);
                g2.setFont(fnt);
            }else{
                fontwd = fm.stringWidth(s);
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*cpcti);
            }
            i=nexti;
            cpcti++;
        }
    }
    /**縦書きを右寄せのように下に詰める。hmを中心線にする*/
    //str,fm,g2,mm2pt,mojih,ascent
    public void drawBottom(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            fontwd = fm.stringWidth(str.substring(i,nexti));
            g2.drawString(str.substring(i,nexti),
                          hm*mm2pt-fontwd/2,
                          (vm+remm)*mm2pt+mojih*cpcti+ascent);
            i=nexti;
            cpcti++;
        }
    }
    /**drawBottom()のverticalEnDashのグリフのない時の対処版*/
    //str,fm, fnt ,g2,mm2pt,mojih,ascent
    public void drawBottomEnx(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        float smfsize;
        float smf;
        String s;
        float vbase = (vm+remm)*mm2pt+ascent;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            s = str.substring(i,nexti);
            if( fnt.canDisplayUpTo(s)>=0 &&
                (s.equals("\uFE32")|| s.equals("\uFE31"))){
                smf = (s.equals("\uFE32"))? 0.5f :0.8f;
                smfsize = fnt.getSize()*smf;
                g2.setFont(fnt.deriveFont(smfsize));
                s = "\u007C";
                fontwd = g2.getFontMetrics().stringWidth(s);
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*(cpcti-0.5f)+smfsize/2);
                g2.setFont(fnt);
            }else{
                fontwd = fm.stringWidth(s);
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*cpcti);
            }
            i=nexti;
            cpcti++;
        }
    }

    /**縦の均等割付 hmを中心線にする */
    //str,fm,g2,mm2pt,mojih,ascent,gapmm
    public void drawTtoB(float hm, float vm) {
        int strlen = str.length();
        int cpct = str.codePointCount(0,strlen);
        if (cpct>1){
            int i=0;
            int cpcti = 0;
            int nexti;
            float fontwd;
            float gapmm = remm/(cpct-1);
            while (strlen>i){
                nexti = str.offsetByCodePoints(i,1);
                fontwd = fm.stringWidth(str.substring(i,nexti));
                g2.drawString(str.substring(i,nexti),
                              hm*mm2pt-fontwd/2,
                              (vm+gapmm*cpcti)*mm2pt+mojih*cpcti+ascent);
                i=nexti;
                cpcti++;
            }
        }else if(cpct==1){
            g2.drawString(str,hm*mm2pt-fm.stringWidth(str)/2,
                              (vm+remm/2)*mm2pt+ascent);
        }
    }
    /**drawTtoB()のverticalEnDashのグリフのない時の対処版*/
    //str,fm,fnt,g2,mm2pt,mojih,ascent,gapmm
    public void drawTtoBEnx(float hm, float vm) {
        int strlen = str.length();
        int cpct = str.codePointCount(0,strlen);
        float fontwd;
        float smfsize;
        float smf;
        float vbase = vm*mm2pt+ascent;
        if (cpct>1){
            int i=0;
            int cpcti = 0;
            int nexti;
            float gapmm = remm/(cpct-1);
            String s;
            while (strlen>i){
                nexti = str.offsetByCodePoints(i,1);
                s = str.substring(i,nexti);
                if( fnt.canDisplayUpTo(s)>=0 &&
                    (s.equals("\uFE32")|| s.equals("\uFE31"))){
                    smf = (s.equals("\uFE32"))? 0.5f :0.8f;
                    smfsize = fnt.getSize()*smf;
                    g2.setFont(fnt.deriveFont(smfsize));
                    s = "\u007C"; //2503";
                    fontwd = g2.getFontMetrics().stringWidth(s); //not fm
                    g2.drawString(s,
                                  hm*mm2pt-fontwd/2,
                                  vbase+gapmm*cpcti*mm2pt+mojih*(cpcti-0.5f)+smfsize/2);
                    g2.setFont(fnt);
                }else{
                    fontwd = fm.stringWidth(str.substring(i,nexti));
                    g2.drawString(s,
                                  hm*mm2pt-fontwd/2,
                                  vbase+(gapmm*mm2pt+mojih)*cpcti);
                }
                i=nexti;
                cpcti++;
            }
        }else if(cpct==1){
            if( fnt.canDisplayUpTo(str)>=0 &&
                (str.equals("\uFE32")|| str.equals("\uFE31"))){
                smf = (str.equals("\uFE32"))? 0.5f :0.8f;
                smfsize = fnt.getSize()*smf;
                g2.setFont(fnt.deriveFont(smfsize));
                str = "\u007C"; //2503";
                fontwd = g2.getFontMetrics().stringWidth(str); //not fm
                g2.drawString(str,
                              hm*mm2pt-fontwd/2,
                              (vm+remm/2)*mm2pt+(mojih-smfsize)/2+smfsize*h2ascent);
                g2.setFont(fnt);
            }else{
                g2.drawString(str,hm*mm2pt-fm.stringWidth(str)/2,
                              (vm+remm/2)*mm2pt+ascent);
            }
        }
    }
    /**縦の中央寄せ hmを中心線にする */
    //str,fm,g2,mm2pt,mojih,ascent
    public void drawMid(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            fontwd = fm.stringWidth(str.substring(i,nexti));
            g2.drawString(str.substring(i,nexti),
                          hm*mm2pt-fontwd/2,
                          (vm+remm/2)*mm2pt+mojih*cpcti+ascent);
            i=nexti;
            cpcti++;
        }
    }
    /**drawMid()のverticalEnDashのグリフのない時の対処版*/
    //str,fm,fnt,g2,mm2pt,mojih,ascent
    public void drawMidEnx(float hm, float vm) {
        int strlen = str.length();
        int i=0;
        int cpcti = 0;
        int nexti;
        float fontwd;
        float smfsize;
        float smf;
        String s;
        float vbase = (vm+remm/2)*mm2pt+ascent;
        while (strlen>i){
            nexti = str.offsetByCodePoints(i,1);
            s = str.substring(i,nexti);
            if( fnt.canDisplayUpTo(s)>=0 &&
                (s.equals("\uFE32")|| s.equals("\uFE31"))){
                smf = (s.equals("\uFE32"))? 0.5f :0.8f;
                smfsize = fnt.getSize()*smf;
                g2.setFont(fnt.deriveFont(smfsize));
                s = "\u007C"; //2503";
                fontwd = g2.getFontMetrics().stringWidth(s);
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*(cpcti-0.5f)+smfsize/2);
                g2.setFont(fnt);
            }else{
                fontwd = fm.stringWidth(s);
                g2.drawString(s,
                              hm*mm2pt-fontwd/2,
                              vbase+mojih*cpcti);
            }
            i=nexti;
            cpcti++;
        }
    }
}

まとめ

 縦書きのための均等割付AdjustStringV.javaと自動改行AfureStringV.javaを作りました。

 これを使って葉書の宛名を縦書きで印刷するPostcardsJushoVer.javaを作りましたが、 ハイフォンと長音符を縦書きにする必要があります。縦の線になっている文字に置換することで対処できましたが、フォントによってはそのグリフが入っていないことがあります。これを検知して自動でASCIIの縦棒文字を縮小して代わりにする機能をAfureStringV.javaに追加しました。

 文字の置換は独立したExchChar.javaで行います。算用数字を漢数字にする機能も追加しました。

 PostcardsJushoVer.javaを改良してフォント変更をしやすくし、IPAex系のフォントがデフォルトになるようにしました。

 この回で掲載したプログラムリストの一覧を示します。複数回出ているものは機能追加されたものです。強調しているのは、今後の連載で部品として使う可能性のあるものや改良・追加・発展が考えられるプログラムです。

プログラム一覧

  • AdjustStringV.java:
    縦書きのための均等割付。AdjustString.javaの縦書き版
  • TestASV.java:
    AdjustStringV.java のCUI用動作確認プログラム
  • AfureStringV.java:
    縦書きのための住所の自動区切りプログラム。AfureString.javaの縦書き版
  • TestAfureStringV.java:
    AfureStringV.javaの使用方法を示すもの。表示のみ
  • PostcardsJushoVer.java:
    PostcardsJushoHor.javaの縦書き版(ハイフォンなど対策なし)
  • ExchChar.java:
    ハイフォンや長音符を縦書き文字に置換。数字も漢数字にできる。
  • ExchCharTest.java:
    ExchChar.javaの使い方を示す。CUIでの確認のみ
  • AfureStringV.javaに追加したdrawBottomEnx()メソッド:
    フォントにverticalEnDashのグリフのない時にdrawBottom()の代わりに使用
  • PostcardsJushoVer.java:
    PostcardsJushoHor.javaの縦書き版(ハイフォンなどを縦にし数字を漢数字にする)
  • AfureStringV.java:
    drawBottomEnx()メソッドなどを加えたAfureStringV.javaの改良版

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

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

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング