JTable打印 教程1

这几天在做关于JTable的打印工作,项目中客户需要直接将JTable打印出来,之前这方面工作做的比较少,经过这几天的研究,稍微有些积累,现在分享一下。

JTable打印目前用的比较多的还是JasperReport来实现的,JasperReport开源免费,但是不是特别好用,这也是为什么JasperReport免费用,但是培训是收费的。

不过常用的一些JTable的打印实现起来也还好了,只是复杂的稍微有些麻烦,可以看看我之前介绍的一篇入门文章:JasperReport 个人使用的一些经验

这里主要分享的是通过Swing 打印的积累,JasperReport常用的简单的打印没问题,但是遇上比较复杂的表单,比如合成表头等,就稍微有点麻烦,当然也有可能是自己没有找到JasperReport的处理方法,要是有朋友知道欢迎分享下。

通过Swing来绘制,应该是无奈的一步,不过通过这无奈的一步,和同事的帮助下,却学习到了不少这方面的知识,尤其是Swing绘制方面的。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值