这几天在做关于JTable的打印工作,项目中客户需要直接将JTable打印出来,之前这方面工作做的比较少,经过这几天的研究,稍微有些积累,现在分享一下。
JTable打印目前用的比较多的还是JasperReport来实现的,JasperReport开源免费,但是不是特别好用,这也是为什么JasperReport免费用,但是培训是收费的。
不过常用的一些JTable的打印实现起来也还好了,只是复杂的稍微有些麻烦,可以看看我之前介绍的一篇入门文章:JasperReport 个人使用的一些经验
这里主要分享的是通过Swing 打印的积累,JasperReport常用的简单的打印没问题,但是遇上比较复杂的表单,比如合成表头等,就稍微有点麻烦,当然也有可能是自己没有找到JasperReport的处理方法,要是有朋友知道欢迎分享下。
通过Swing来绘制,应该是无奈的一步,不过通过这无奈的一步,和同事的帮助下,却学习到了不少这方面的知识,尤其是Swing绘制方面的。
下面的代码是我抽出来的一个比较通用的,基于TableModel的表格打印,普通表头,不带合成表头的,如果Table Model不一样,那么自己就需要改改了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.math.BigDecimal; import java.text.NumberFormat; import javax.swing.JTable; import javax.swing.table.TableModel; /** * * @author xiaoquan */ public class SwingCommonPrinitTools implements Printable { private TableModel model = null; private String info; private int totalRow = 0; private static final int LEFT = 0; private static final int RIGHT = 1; private static final int CENTER = 2; private static final int AUTO = 3; public void printTable(TableModel model, String info) { this.model = model; this.info = info; totalRow = model.getRowCount(); PrinterJob printJob = PrinterJob.getPrinterJob(); printJob.setPrintable(this); if (printJob.printDialog()) { try { printJob.print(); } catch (Exception ex) { ex.printStackTrace(); } } } private static final double paper_offset_x = 20; private static final double paper_offset_y = 20; private static final double title_time_margin = 10; private static final double time_body_margin = 2; private static final double cell_padding_y = 3; private static final double cell_padding_x = 2; private static final double body_btm_margin = 20; private static final double body_cell_height = 20; private static final Font title_font = new Font("黑体", Font.PLAIN, 18); private static final Font time_font = new Font("Dialog", Font.PLAIN, 10); private static final Font body_font = new Font("Dialog", Font.PLAIN, 10); @Override public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException { //纸张宽 double pageWidth = pf.getImageableWidth(); //纸张高 double pageHeight = pf.getImageableHeight(); //打印的内容起始X double pageStartX = pf.getImageableX(); //打印的内容起始Y double pageStartY = pf.getImageableY(); //表头高 double tableHeadH = 0; //Cell高 double cellH = 0; //计算表头高度和单元格高度 g.setFont(body_font); FontMetrics cellFm = g.getFontMetrics(); cellH = cellFm.getHeight() + cell_padding_y * 2 + 1; tableHeadH = cellH * 2; //计算Title以及其位置 String title = info; g.setFont(title_font); FontMetrics titleFm = g.getFontMetrics(); int titleW = titleFm.stringWidth(title); //表底和表头文字属性 g.setFont(time_font); FontMetrics btmFm = g.getFontMetrics(); FontMetrics timeFm = g.getFontMetrics(); //表格以上的Margin double tableTopMargin = paper_offset_y + titleFm.getHeight() + title_time_margin + timeFm.getHeight() + time_body_margin; //表格每列的最大宽度 double[] cellColMaxWidths = caculateTableCellWidth(model, cellFm); //当前Page的数据容量高度-不包括表头和表尾 double currentPageDataCapacityHeight = pageHeight - tableTopMargin - tableHeadH - btmFm.getHeight() - body_btm_margin - 1; //当前Page的数据容量 int currentPageBodyCapacityRows = (int) (currentPageDataCapacityHeight / cellH); //Y方向的分页数量 int pagesY = 0; if (model.getRowCount() % currentPageBodyCapacityRows == 0) { pagesY = (int) (model.getRowCount() / currentPageBodyCapacityRows); } else { pagesY = (int) (model.getRowCount() / currentPageBodyCapacityRows) + 1; } //当前页数大于总页数时不打印 if (pageIndex + 1 > pagesY) { return NO_SUCH_PAGE; } //绘制Title g.setFont(title_font); g.drawString(title, (int) (pageStartX + (pageWidth - titleW) / 2), (int) (pageStartY + paper_offset_y + titleFm.getAscent())); //绘制区域移动到新的(0,0)点 g.translate((int) (paper_offset_x + pageStartX), (int) (tableTopMargin + pageStartY)); int currentX = 0, currentY = 0; //绘制第一张表 //绘制表头 g.setFont(time_font); String time = "表头: " + info; g.drawString(time, currentX, currentY); currentY += 5; //绘制单一表头 for (int i = 0; i totalRow ? totalRow : (currentPageBodyCapacityRows * (yIndex + 1)); for (int row = startRow; row < endRow; row++) { //绘制单项表头下面的数据 for (int i = 0; i < model.getColumnCount(); i++) { double width = cellColMaxWidths[i]; double height = body_cell_height; Object value = model.getValueAt(row, i); drawCell(g, value, currentX, currentY, (int) width, (int) height, AUTO); currentX += width; rightCellX = currentX; } currentX = 0; currentY += cellH; } //绘制闭合线,下面和右侧两条 g.drawLine(currentX, currentY, rightCellX, currentY); g.drawLine(rightCellX, 5, rightCellX, currentY); drawBottomInfo(pageIndex, pagesY, currentY, g, (int) pageWidth); return PAGE_EXISTS; } private void drawBottomInfo(int pageIndex, int pagesY, int currentY, Graphics g, int pageWidth) { if (pageIndex + 1 == pagesY) { //绘制底部信息 int btmX = 0; int btmY = currentY + 20; g.drawString("负责人:", btmX, btmY); g.drawString("制表:", pageWidth / 3, btmY); FontMetrics fm = g.getFontMetrics(); int dataWidth = fm.stringWidth("日期: 2009/10/26"); g.drawString("日期:", pageWidth - dataWidth, btmY); } } /** * 计算最大列宽 * @param cellFm * @return */ private double[] caculateTableCellWidth( TableModel model, FontMetrics cellFm) { //表格每列的最大宽度 double[] cellColMaxWidths = new double[model.getColumnCount()]; //计算表头每列最大宽度 double[] headerColMaxWidths = new double[model.getColumnCount()]; for (int i = 0; i < model.getColumnCount(); i++) { String name = model.getColumnName(i); headerColMaxWidths[i] = cellFm.stringWidth(name) + cell_padding_x * 2 + 1; } //没有数据时,表头每列的最大宽度就是表格每列的最大宽度 cellColMaxWidths = headerColMaxWidths; //算数据每列的最大宽度和表头每列最大宽度对比 for (int j = 0; j < model.getRowCount(); j++) { for (int i = 0; i < model.getColumnCount(); i++) { //做些数据类型的判断 Object value = model.getValueAt(j, i); if (value instanceof BigDecimal) { value = ((BigDecimal) value).doubleValue(); } String text = ""; if (value != null) { text = value.toString(); } double temp = cellFm.stringWidth(text) + cell_padding_x * 2 + 1; if (cellColMaxWidths[i] < temp) { cellColMaxWidths[i] = temp; } } } return cellColMaxWidths; } /** * 绘制单元格及里面的文字 * @param g * @param value * @param x * @param y * @param width * @param height */ private static void drawCell(Graphics g, Object value, int x, int y, int width, int height, int locate) { g.drawLine(x, y, x + width - 1, y); g.drawLine(x, y, x, y + height - 1); FontMetrics fm = g.getFontMetrics(); if (value == null) { value = ""; } switch (locate) { case 0: //居左 g.drawString(value.toString(), (int) (x + cell_padding_x), y + (height - fm.getHeight()) / 2 + fm.getAscent()); case 1: //居右 g.drawString(value.toString(), (int) (x + (width - fm.stringWidth(value.toString()) + width - fm.stringWidth(value.toString()) - cell_padding_x) / 2), y + (height - fm.getHeight()) / 2 + fm.getAscent()); case 2: //居中 g.drawString(value.toString(), x + (width - fm.stringWidth( value.toString())) / 2, y + (height - fm.getHeight()) / 2 + fm.getAscent()); case 3: //自动判断 NumberFormat formatter = NumberFormat.getNumberInstance(); formatter.setMinimumFractionDigits(2); formatter.setMaximumFractionDigits(2); //根据数据类型左对齐还是右对齐绘制还是居中对齐 if (value instanceof BigDecimal) { //居右 value = ((BigDecimal) value).doubleValue(); value = formatter.format(value); g.drawString(value.toString(), (int) (x + (width - fm.stringWidth(value.toString()) + width - fm.stringWidth(value.toString()) - cell_padding_x) / 2), y + (height - fm.getHeight()) / 2 + fm.getAscent()); } else if (value instanceof Integer || value instanceof Long || value instanceof Double) { //居右 g.drawString(value.toString(), (int) (x + (width - fm.stringWidth(value.toString()) + width - fm.stringWidth(value.toString()) - cell_padding_x) / 2), y + (height - fm.getHeight()) / 2 + fm.getAscent()); } else { //居中 g.drawString(value.toString(), x + (width - fm.stringWidth( value.toString())) / 2, y + (height - fm.getHeight()) / 2 + fm.getAscent()); } } } public static void main(String[] args) { new SwingCommonPrinitTools().printTable(testData(), "测试"); } private static TableModel testData() { final Object rows[][] = { {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", "Test1", "Test2", "Test3"}, {"five", "go - \u4E94", "Test1", "Test2", "Test3"}, {"six", "roku - \u516D", "Test1", "Test2", "Test3"}, {"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"}, {"eight", "hachi - \u516B", "Test1", "Test2", "Test3"}, {"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"}, {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", "Test1", "Test2", "Test3"}, {"five", "go - \u4E94", "Test1", "Test2", "Test3"}, {"six", "roku - \u516D", "Test1", "Test2", "Test3"}, {"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"}, {"eight", "hachi - \u516B", "Test1", "Test2", "Test3"}, {"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"}, {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", "Test1", "Test2", "Test3"}, {"five", "go - \u4E94", "Test1", "Test2", "Test3"}, {"six", "roku - \u516D", "Test1", "Test2", "Test3"}, {"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"}, {"eight", "hachi - \u516B", "Test1", "Test2", "Test3"}, {"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"}, {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", "Test1", "Test2", "Test3"}, {"five", "go - \u4E94", "Test1", "Test2", "Test3"}, {"six", "roku - \u516D", "Test1", "Test2", "Test3"}, {"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"}, {"eight", "hachi - \u516B", "Test1", "Tes12121t2", "Test3"}, {"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"}, {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", 12, "Test2", "Test3"}, {"five", "go - \u4E94", 121212, "Test2", "Test3"}, {"six", "roku - \u516D", 1212121212, "Test2", "Test3"}, {"seven", "shichi - \u4E03", 12.01, "Test2", "Test3"}, {"eight", "hachi - \u516B", 135.12, "Test2", "Test3"}, {"nine", "kyu - \u4E5D", 93828.34, "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"}, {"one", "ichi - \u4E00", "Test1", "Test2", "Test3"}, {"two", "ni - \u4E8C", "Test1", "Test2", "Test3"}, {"three", "san - \u4E09", "Test1", "Test2", "Test3"}, {"four", "shi - \u56DB", "Test1", "Test2", "Test3"}, {"five", "go - \u4E94", "Test1", "Test2", "Test3"}, {"six", "roku - \u516D", "Test1", "Test2", "Test3"}, {"seven", "shichi - \u4E03", "Test1", "Test2", "Test3"}, {"eight", "hachi - \u516B", "Test1", "Test2", "T1212121212est3"}, {"nine", "kyu - \u4E5D", "Test1", "Test2", "Test3"}, {"ten", "ju - \u5341", "Test1", "Test2", "Test3"},}; final Object headers[] = {"English", "Japanese", "Column1", "Column2", "Column3"}; JTable table = new JTable(rows, headers); return table.getModel(); } } |
Popularity: 15% [?]

Recent Comments