java原生打印实现自动调用系统默认打印机

本文档介绍了如何在Java中实现一个自动打印功能,通过继承`Printable`接口并重写`print()`方法,实现单页单面的文本打印。文章详细展示了如何处理文字换行、调整字体和布局,以及如何配置页面格式和打印服务。
摘要由CSDN通过智能技术生成

最近公司项目里要实现一个自动打印的功能,还不让引入网上造好的轮子,所以只能去研究Java自带的打印,网上好多的文章写得都不是很详细,找了很久才找到能够完美实现功能的方法,记录一下

首先是一个继承了Printable类,并且重载了print()方法的类(其实这里的pring()方法的返回值以及第三个参数我也没太搞明白,但是由于需求只要打单页单面就可以了,所以实现了需求之后我就没有再仔细去研究了owo)

import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class PrintTest implements Printable {

    // 每行的高度
    static final int lineHeight = 14;
    // 字体大小
    static final int stringWidth = 10;
    // 字体名
    static final String fontName = "新宋体";
    // 需要打印的内容
    private String message;
    // 单参数构造器,方便打印类构造打印内容
    public PrintTest(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    /**
     * @param gra 打印的图形环境
     * @param pf  打印页格式(页面大小以点为计量单位,1点为1英才的1/72,1英寸为25.4毫米。A4纸大致为595×842点)
     * @param pageIndex 指明页号
     **/
    @Override
    public int print(Graphics gra, PageFormat pf, int pageIndex) throws PrinterException {

        // 字体
        Font font = new Font(fontName, Font.PLAIN, stringWidth);
        
        // 获取设定的纸张高度
        int height = (int) pf.getPaper().getHeight();
        // 计算每张图片有多少行文字
        int lineCount = height / lineHeight;
        // 获取设置的纸张宽度
        double imageableWidth = pf.getPaper().getImageableWidth();
        // 计算每行最大字符数
        int charPerLine = (int)imageableWidth / stringWidth;

        // 转换成Graphics2D
        Graphics2D g2 = (Graphics2D) gra;
        // 获取打印的起点坐标
        float x = (float) pf.getImageableX();
        float y = (float) pf.getImageableY();

        // 分行获取需要打印的内容
        String[] messageInline = this.message.split("\n");
        // 将需要打印的消息根据每行最大字符数存放入list
        List<String> oriList = new ArrayList<String>(Arrays.asList(messageInline));
        List<String> newList = new ArrayList<String>();
        for (int j = 0; j < oriList.size(); j++) {
            if (oriList.get(j).length() > charPerLine) {
                newList.add(oriList.get(j).substring(0, charPerLine));
                oriList.add(j + 1, oriList.get(j).substring(charPerLine));
                oriList.set(j, oriList.get(j).substring(0, charPerLine));
            } else {
                newList.add(oriList.get(j));
            }
        }
        // 计算处理后得到信息需要打印的页数
        int a = newList.size();
        int pageNum = a % lineCount == 0 ? (a / lineCount) : (a / lineCount) + 1;

        // 绘制打印内容
        for (int m = 0; m < pageNum; m++) {
            // 设置打印颜色为黑色
            g2.setColor(Color.black);
            // 设置画笔字体
            g2.setFont(font);
            // 背景色白色
            g2.setBackground(new Color(255, 255, 255));
            // 每张多少行,当到最后一张时判断是否填充满
            for (int i = 0; i < lineCount; i++) {
                int index = i + m * lineCount;
                if (newList.size() - 1 >= index) {
                    g2.drawString(newList.get(index), x, y + lineHeight * (i + 1));
                }
            }
            g2.dispose();
        }
        return PAGE_EXISTS;
    }
}

写完Printable类后就需要写实际调用打印的主类了

import java.awt.print.*;

public class Print {
    public static void main(String[] args) {
        String message = "“两国交兵,不斩来使”在后世流传下来的交战规则主要只有“两国交兵,不斩来使”。春秋时期诸侯派出的外交使节是不可侵犯的。" +
                "公元前596年楚国派出申舟出使齐国,楚庄王特意嘱咐不要从宋国经过。宋国执政华元听说了,觉得这是对宋国的莫大侮辱," +
                "就设伏击杀死楚国使者。楚庄王为此“投袂而起”,出动大军包围宋国国都整整9个月。宋国派出使者到晋国告急,晋国上一年刚被楚军打败," +
                "不敢冒与楚国全面冲突的危险,只是派解扬为使者劝宋国坚守,不要投降。解扬经过郑国,被郑国抓起来交给楚国。楚庄王亲自接见解扬," +
                "企图买通他,要他向宋军喊话,说晋军不再提供救援,断绝宋军的希望,解扬不同意。经楚庄王几次威逼利诱,解扬才答应下来。" +
                "可是当解扬来到了望城中的楼车上,就大声疾呼,说晋国援军不日就到,请宋国无论如何要坚持下去。楚庄王大怒,解扬说:" +
                "“我答应你的条件只是为了实现使命,现在使命实现了,请立刻处死我。”楚庄王无话可说,反而释放他回晋国。长期围困而无战果," +
                "楚庄王打算退兵,可申舟的父亲拦在车前,说:“我儿子不惜生命以完成国王的使命,难道国王要食言了吗?”楚庄王无言以对。" +
                "申舟父亲建议在宋国建造住房、耕种土地,表示要长期占领宋国,宋国就会表示屈服。宋国见楚军不肯撤退,就派华元为使者来谈判。" +
                "华元半夜里潜入楚军大营,劫持了楚军统帅子反,说:“我的国君要我为使者来谈判,现在城内确实已是‘易子而食,析骸以爨’," +
                "但是如果订立城下之盟则情愿举国牺牲。贵军退到三十里外,我国唯命是听。”子反就在睡床上保证做到。第二天报告了楚庄王," +
                "楚军真的退30里外,和宋国停战,双方保证不再互相欺瞒,华元作为这项和约的人质到楚国居住。\n" +
                "后世将这一交战规则称之为“两国交兵,不斩来使”。历史上最著名的战时两国使节以礼相见的故事是“彭城相会”。450年南朝刘宋与北魏发生战争," +
                "刘宋发起北伐,先胜后败,战略据点彭城被包围。江夏王刘义恭率领军队死守彭城(今徐州),北魏太武帝想一举打过长江," +
                "派出李孝伯为使节进彭城劝降。刘义恭派了张畅为代表与李孝伯谈判。两人都是当时的“名士”,互相代表各自的君主赠送礼品," +
                "尽管处在极其残酷的战争环境,但他们在谈判中却仍然是文质彬彬、礼貌周全。这次谈判本身并没有什么实质性的结果,可双方的礼节及言辞," +
                "一直被后世誉为战场佳话。";

        // 首先创建文档类、页面格式类和纸张类
        Book book = new Book();
        PageFormat pf = new PageFormat();
        // 通过Paper设置页面的空白边距和可打印区域。必须与实际打印纸张大小相符。
        Paper p = new Paper();

        // 通过页面格式类对打印的页面进行格式上的约束
        // 设置成竖打
        pf.setOrientation(PageFormat.PORTRAIT);
        
        // 设置纸张大小
        p.setSize(590, 840);
        // 设置打印区域A4(595 X 842),A4纸的默认X,Y边距是72
        p.setImageableArea(30, 30, 530, 840); 
        
        // 将Paper放入PaperFormat中
        pf.setPaper(p);

        // 把 PageFormat 和 Printable 添加到文档中,组成一个页面
        book.append(new PrintTest(message), pf);

        // 获取打印服务对象
        PrinterJob job = PrinterJob.getPrinterJob();
        
        // 将组合好的Book放入打印服务中
        job.setPageable(book);

        try {
        //可以用printDialog显示打印对话框,在用户确认后打印;也可以直接打印
            job.print();
        } catch (PrinterException e) {
            e.printStackTrace();
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值