谈谈Java报表之JasperReport改造一,动态报表

xf 06-06-30
    

我本对JasperReport一壳不同,只是公司在做产品时选用了JasperReport,主要原因还是免费吧!由于公司是做物流系统,所以对于报表的要求非常高,大体在使用JasperReport过程中分为两类,一类是类似表单形式,还有一类就是传统的汇总报表。其中表单形式十分多,主要用于物流行业中的各种单据打印,比如报关单,发票等等。
国内客户有一个很奇怪的需求,就是喜欢在打印预揽时修改单据的数据(有可能是要做假胀的原因)或者修改具体的表单布局,我们公司遇到这样的情况非常多。JasperReport是通过xml文件记录具体的布局信息,一般也是用同样开源的IReport产生编辑一个具体的JasperReport的布局xml信息。如果我们需要实现客户的功能,乍看起来,等于是要实现一个IReport中的编辑功能。老板要求我来实现,经过几天的研究,发现其实不然,实现在JasperReport良好的封装的基础上实现这样的功能不用很费力。
下面我介绍一下简单原理:
JasperReport提供一个JRViewer的预揽组件,是一个JPanel对象。在JRViewer绘制预揽效果时,会调用
JasperPrintManager.printPageToImage(jasperPrint, pageIndex, realZoom, viewer.isDesignMode);方法得到一个Image对象(双缓冲),然后再将Image对象setIcon给JRViewer上面的显示组件。所以预揽效果最终是靠Image对象呈现,需要动态抓取Image对象中具体的报表数据元素的位置是非常困难,我没有走这条路。其实在JasperReport中每一个图形元素都是一个JRPrintElement接口的实例对象,图形元素的位置,数据,字体等等信息都放在JasperPrint中都包含了这些对象。JasperPrintManager.printPageToImage(jasperPrint, pageIndex, realZoom, viewer.isDesignMode);最终会调用JRGraphics2DExporter中的exportElements(Collection elements)遍例JasperPrint对象中的JRPrintElement分别通过最后输出的Graghic2D句柄绘制图形,文字。我的解决方案就是从JasperPrint对象下手。
1)给JRViewer上面的显示图例组件加MouseListener,MouseMotionAdapter
2)在mousePress中,通过MouseEvent得到当前鼠标的位置,并且通过遍例当前JasperPrint中的所有JRPrintElement的getX,getY,getWidth,getHeight来拿到当前的JRPrintElement对象,并且记入下来(在使用橡皮带技术时需要重化上一个图形的位置,具体算法太过复杂这里忽略介绍)。
3)在mouseDragged方法中,实现橡皮带技术(其实就是画一个虚框,感觉图形在跟着鼠标动)。
4)在mouseRelease方法中,得到release的位置,包括x,y坐标和最后释放矩形的width,height。
5)JRPrintElement对象中没有setX,setY,setWidth,setHeight接口,所以需要改动源码,加上这些方法。在JRTemplatePrintElement或者JRBasePrintElement中改变实例的x,y,width,height。
6)重新调用JasperPrintManager.printPageToImage(jasperPrint, pageIndex, realZoom, viewer.isDesignMode);双缓冲使页面刷新不会有多大抖动的感觉。
这样就可以动态调整图形元素的位置布局。
7)在mousePress中加入e.getClickCount==2的双击判断,对于大多数显示文字的JRPrintElement都是JRPrintText的子类,(JRPrintText在最早的源代码有没有setText我记不清了,如果没有的话也加上setText接口)JRPrintTemplateText和JRBasePrintText都有text这个变量,在setText改变text的值,同样调用JasperPrintManager.printPageToImage(jasperPrint, pageIndex, realZoom, viewer.isDesignMode);就可以看到改变后的效果。
小结:这里我只是简单介绍一下动态报表的实现,其实只要看清JasperReport源代码的一些结构会发现,其面向对象设计做的非常好,还可以有很多改造的余地。后面我还会介绍如何实现将修改后的布局保留成新的xml,以及无穷层子报表的实现。
顺便说一句:客户使用动态报表和开心,他们甚至要我们在开发财务发票模块时,提供一张空白报表,只留一些空白的数据图形元素,然后打印发票前直接填入发票金额,估计这种事情也只有国内客户才做得出来,呵呵!

    

3
banq
2006-07-06 15:55

好文,期待后篇..

zhusuzhen
2007-02-28 14:44

大虾 我要用java生成 pdf 用户要参与图片的摆放位置 我的msn是:msn_zhusuzhen@hotmail.com QQ是:454529447 有问题请教 希望+我

yxxcrtd
2007-03-28 15:05

还能说的详细点儿吗?

dddddddddd
2007-08-06 21:56

既然你需要动态的改 preview时候的东西,为什么不采用web方式的打印报表呢,而不用jasperreport.,弹出一个白的页面,把东西都放在上面。然后js中的window.print()不是很好啊。