最近公司项目里要实现一个自动打印的功能,还不让引入网上造好的轮子,所以只能去研究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();
}
}
}