iReport是一个能够创建复杂报表的开源项目。它100%使用Java语言编写。是目前全球最为流行的开源报表设计器。
由于它丰富的图形界面,你能够很快的创建出任何一种你想要的报表。
以下是iReport一些比较突出的功能:
• 拖拽式,所见即所得的报表编辑器。
• 多样的向导来简化复杂的报表设计任务。
• 超过30个排版和格式化工具。
• 报表可转换为PDF HTML EXCEL FLASH CSV RTF TXT OpenOffice Java2D JRViewer等格式。
• 支持所有有效的数据源。如:JDBC,CVS,Hibernate,JavaBean等
• 用户自定义数据源。
• 无限次数的撤消/重做。
• 集成脚本(scriptlet)支持。
• 内置图表支持:超过20种的图表支持。并可扩展。
•国际化:集成超过15种语言。
• 报表模板与报表库样式管理。
• 源文件的备份
• 文档结构浏览器
iReport报表结构
在本章中我们将一起来分析一下报表的结构,看一下报表中每一部分的作用是什么,以及在生成报表的时候每一部分将产生什么样的效果。
4.1栏(Bands)
报表被垂直分成若干个部分,每一个部分我们叫它为“band”。每一个band都有自己的特性,在报表生成的时候有些会打印一次,有些会打印多次。如下图。
图4.1
接下来我们就对每一种类型的band分别进行介绍。
Title Band:title段只在整个报表的第一页的最上面部分显示,除了第一页以外,不管报表中共有多少个页面也不会再出现Title band 中的内容。
pageHeader Band:顾名思义,pageHeader段中的内容将会在整个报表中的每一个页面中都会出现,显示在位置在页面的上部,如果是报表的第一页,pageHeader 中的内容将显示在Title Band 下面,除了第一页以外的其他所有页面中。pageHeader 中的内容将显示在页面的最上端。
pageFooter Band:显示在所在页面的最下端。
Detail Band: 报表内容段,在这个Band中设计报表中需要重复出现的内容,Detail 段中的内容每页都会出现。
columnHeader Band:针对Detail Band的表头段,一般情况下在这个段中画报表的表头。
columnFooter Band:针对Detail Band的表尾段。
Summary Band:表格的合计段,出现在整个报表的最后一页中的Detail band的后面,一般用来统计报表中某一个或某几个字段的合计值。
为了实际演示各个band的生成效果,我们可以在报表中的各个band里添加不同的对象,以测试各个band的作用。
从示例数据库的employee表里取数据,在query editor里输入下面的语句:
select top 10 * from employee
图4.2
在报表中的各个band分别放置如下内容:
图4.3
启动报表,生成的效果如下:
图4.4 生成的报表第一页
图4.5生成的报表第二页,也是最后一页
iReport报表元素
在本章中我们将要解释可以在报表中使用的对象及他们的相关属性。
我们所说的元素主要是一些图形对象,比如text,rectangle等。在iReport中没有段落,表格或分页的概念,在报表中最基本的对象主要有七个:
-Line
-Rectangle
-Ellipse
-Static text
-Text field
-Image
-Subreport
-Crosstab
-Chart
通过以上这些组件的组合我们可以做出各种各样复杂的报表样式。iReport提供两种特殊的图形对象:chart和barcode。
每一种类型的对象都有一些通用的属性,如高度、宽度、位置、所在的band等。除此之外还有一些针对不同元素的特殊属性。
每一个元素都必须在一个band内部,如果一个元素跨了一个以上的band,那么在编译的时候将会抛出元素位置错误的异常。
要添加一个元素到报表中,我们可以从主工具栏中选择相应的工具,然后添加到报表区域中即可。
图5.1
我们可以通过双击对象或右键菜单打开元素的属性设置窗口。
图5.2
属性窗口由若干个标签页构成,“Common”标签里包含每一个组件都具有的通用属性,其它的标签页是针对不同元素的属性设置。在下面的章节中,我们将对每一个对象的使用做详细的介绍。
iReport字体和样式(Fonts and Styles)
一个style是一个预定义的属性的集合用来控制元素的外观(比如背景色、边框线、字体等)。我们可以为我们的报表定义一个默认的style。
要为一个元素应用一个style,我们可以选择该元素并从元素的属性窗口common标签里的style列表选择你需要的style。
Fonts是用来描述text的外观特征。此外,你可以定义一个名为“Report font”的全局字体。
6.1字体(font)
通常定义一个字体,我们需要做下面几件事情:
-Font name(字体名称)
-Font dimension(字体大小)
-Attribute(属性,诸如bold-faced,italics,underlined,barred)
如果我们需要导出PDF格式的报表,需要为字体添加下面的信息:
PDF Font Name:PDF字体名称(预先定义PDF字体或一个在classpath里的TIF文件的名称)。
PDF Embedded:当使用一个外部的TTF类别的字体文件生成报表时是否把它包含在PDF文件里的一个标志。
PDF Encoding:指定一个字体编码名称。
如果我们需要将报表导出成PDF格式,将会使用指定的PDF字体,其它属性将会被忽略掉。
如果我们使用扩展的TTF(True Type Font),那么扩展的字体文件(以.ttf结尾的文件名)必须放置在classpath当中。
图6.1
在“Font name”下拉框中,仅显示的是java虚拟机管理的系统默认字体,因此,如果要选择一个扩展的TTF字体在非PDF格式报表中,那么我们首先需要在使用之前在系统中把这些字体安装好。
图6.2
上面的字体列表中显示是内置的PDF字体集合,如果直接去编辑下拉框里的字体但这些字体在设计时候不可用,如果字体文件在启动的时候找不到,那将会产生一些错误。
如果我们选择的字体是一个扩展的TTF格式字体,要保证在导出PDF格式时显示正确,请勾选“PDF Embedded”复选框。
如果要导出PDF格式报表选择正确的字体编码至关重要。Encoding指定字体如何被编译。举个例子,如果使用意大利语,要打印正确的重音符(比如:è, ò, a, ù)我们必须使用CP1252编码格式。
iReport在下拉框里有一些预定义的编码格式。当报表导出PDF时包含一些非标准的字符时,要保证所有的fields都有相同的编码格式并且检查从数据库里读出的数据采用的字符集格式。
6.2样式(Styles)
我们可以选择主菜单的“Format Styles” 来定义一个style。如下图所示:
图6.3
点击“New”按钮添加一个新的style。在弹出的窗口中我们可以定义一些属性,如果我们需要某个属性的值,我们可以点击按钮来实现。
图6.4
在每个元素属性窗口的“Common”标签里有一个style属性下拉框,如果我们需要为一个元素设置一个style,我们可以在这个下拉框里选择我们定义好的style,这样就可以把一个style应用到一个元素上面啦。
图6.5
我们可以为一个Style加一个动态的条件,当条件满足的时候采用某个style,否则就采用默认的style。举个例子,还是以doradosample里的hsql数据库里的employee表为例,如果员工的薪水大于3500,我们让薪水以红色加粗的字体显示。
打开Query窗口,输入下面的查询SQL:
Select * from employee
图6.6
新建一个style,在弹出窗口的style conditions里新建一个conditions,在表达式窗口里输入下面的表达式:
($F{SALARY}.intValue()>3500?new Boolean(true):newBoolean(false))
如下图:
图6.7
新建的style如下图:
图6.8
接下来把员工姓名和员工薪水拖到报表当中,并将我们新建的style应用到薪水这个field上,如下图:
图6.9
启动查看运行效果如下:
图6.10
iReport字段,参数,变量
在ireport中有三种类型的对像可以用来保存数据:Fields/Parameters/Variables.这三种对象可以用在某些地方的Expression中,通过一定的逻辑在报表生成的时候动态的更改某些值。Fields/Parameters/Variables有类型的概念,它们的类型就是一个标准的Java的Object。要使用这三种类型的对象我们必须首先创建它,创建的方法是点击“View”主菜单中,选择其中的子菜单Fields,Variables,Parameters我们可以创建不同的对象。通过这三个子菜单我们可以查看并管理Fields,Variables,Parameters对象。
图1.1
通过该窗口,我们可以创建,修改,删除这三种类型对象。
7.1字段(Fields)
Field在ireport是专门用来组织记录。Field的创建有多种途径可以实现,我们可以根据在ireport中各种类型的数据源来创建我们所需要的Field。
在图1.1中的Fields标签页中,我们可以点击new 按钮来创建一个新的Field。
图1.2
一个Field有两个必填的属性: name、type和一个可选项的description。从ireport1.0.0开始,fields可以是任何Java数据类型。这样当我们使用JavaBean作为数据源时我们可以很方便的从java.lang.Object向报表中的Field的转换工作。在对象的Expression里你可以使用下面的语法来引用一个field:
${field name}
例如如果你想处理com.bstek.test.domain.Person Bean里的username 字段,可以这样去写:
((com.bstek.test.domain.Person)${username})
用一个SQL query来创建Field
在ireport的设计中使用SQL query的方式来创建或记录字段的是使用最广泛的也是最直接最简单的一种方式。做此操作我们需要首先打开ReportQueryDialog窗口(点击主工具栏的 按钮),ReportQueryDialog窗口出现后,我们可以输入合适的SQL检索并创建Fields。
图1.3
在打开ReportQueryDialog窗口之前请先确认我们已经有一个数据源连接处于激活状态(激活方式请查看相关章节),插入一条查询语句,如:select * form employee
iReport将启动SQL查询引擎,根据输入的SQL将分析结果用fields的形式展示出来。在下面的窗口中选择你要的fields(可以多选)然后点击OK按钮, fields就被创建出来了。
在这个例子当中所有字段有多程类型,一般地说,fields的数据类型是构建在原始SQL 类型基础之上的,如String,Integer…
用JavaBean生成Fields
ireport的高级特性之一是它的数据源除了可以构建在SQL query基础之上外,还可以使用含有getter和setter方法的JavaBean(或者叫POJO)对象来创建。在这个例子中fields就是POJO类里的属性(或者是属性的属性,即子对象的属性)。
选择JavaBean Datasource 标签,通过该窗口你可以指定POJO来创建fields。如下图:
图1.4
点击“Read attributes”按钮,你可以浏览这个对象,可以看到这个对象的直接属性嵌套的对象(子对象),双击里面的子对象你可以查看子对象的属性。
要把一个属性添加到field列表,只需选中需要的属性然后点击“Add field(s)”按钮。如果要把一个field作为一个文本打印,可以直接把一个field拖到report的band里或者在report的band里添加一个textfield然后设置它的expression(把一个field放在expression里)和textfield的类型,如果需要还可以为一个要打印的field定义一个pattern(模式)用来对field内容进行格式化。
图1.5
7.2参数(Parameters)
Parameters通常是用来在打印的时候从程序里传值到报表里.也就是说parameters通常的是起参数传递的作用。他们可以被用在一些特定的场合(比如应用中SQL 查询的条件),和report中任何一个需要从外部传入的变量等(如一个Image对象所包括的char或报表title的字符串)。
和使用Fields一样,parameters也需要在创建的时候定义它的数据类型.parameters的数据类型是标准的java的Object。
图1.6
在ireport中Parameters的机制是允许用户通过应用程序传递参数致报表当中。在jasperreort中的某个对象中的expression可以通过下面的语法来访问一个当前report中存在的parameter:
$P{parameter name} 如果应用程序没有为报表中定义的parameter赋值,那么parameter将会取我们在定义它的时候设置的default value的值。parameters是一个Java Object,所以如果它的类型是Object类型,我们在其default value里写下面的表达式就是错误的:
0.123
你必须要创建一个Object,如:
New Double(0.123)
这种写法就是正确的。
在查询中使用Parameters
Parameters可以用来做SQL查询的条件参数的传递.如果你想根据部门编号(dept_id)得到客户的详细信息 (设计的时候我们是不知道这个部门编号的具体值是多少的).此时我们可以这样组织查询语句:
select * from employee where dept_id=$P{deptId}
此时SQL查询引擎将会采用PreparedStatement来处理传入的deptId值以此作为查询条件参数。
如果你想直接通过parameter 值来作为SQL语句的一部门,那么你可以使用下面的特殊语法:$P!{parameter name}。这种写法允许你在查询时用parameter的值来替换parameter name。例如,如果我们有一个参数名为MyWhere其值为:where dept_id=D11 ,查询写法如下:
Select * from employee $P!{MyWhere}
查询时实际提交的字符串是:
Select * from employee where dept_id=D11
在程序里使用Parameters
在应用程序里如果想把某个值传递到我们的报表中parameters时,我们可以把相关的值放入一个扩展java.util.Map接头类里,然后传入到report里。如下面的代码:
... Map hm = new HashMap(); ... JasperPrint print = JasperFillManager.fillReport(fileName,hm,new JREmptyDataSource()); |
fillReport是一个关键的方法,它允许你通过一个文件名,一个参数集来传递到我们要调用的报表当中。例如通过下面的处理方法我们可以让一个处部的传入值作为我们报表的title。
a).声明一个parameter.这个parameter是java.lang.String 类型,名字为:name_report:
图1.6
b.将这个parameter拖到page中的titleband.修改上面的程序代码如下:
HashMap hm = new HashMap(); hm.put(“name_report”,”report title”); ... JasperPrint print = JasperFillManager.fillReport(fileName,hm, new JREmptyDataSource()); |
图1.7
运行时效果如下:
图1.8
一般情况下,我们不需要为报表中的每一个parameters传递一个值,除非某一个parameter一定要从外部程序传入时我们才需为一个parameter设置一个值。如果一个parameter外部门程序没有为其赋值那么ireport将使用Default Value Expression来对一个parameter进行初始化,如果连Default Value Expression没有设置那么它的值就是null。
事实上,对于一个parameters我们不仅仅可以传递一个String,Integer,Boolean等java中小的对象,同时我们还可以利用parameters来传递一些足够大足够复杂的对象,比如一个图像(java.awt.Image),或者通过一个parameters来为一个为子报表提供的datasource 连接等。在用Map类型传递参数时我们要注意传递的参数要与report里的parameters类型保持一致,否则会抛出ClassCastException。
ireport内嵌的Parameters
ireport提供了一些内建的parameters,这些parameters对于用户来说是只读的。内嵌的parameters列表如下:
参数名 |
说明 |
REPORT_PARAMETERS_MAP |
它是一个java.util.Map类型的对象,可以通过它来传给填充报表去填充报表里所有的parameters,在这个参数里还包含用户定义的parameters. |
REPORT_CONNECTION |
一个JDBC的Connection参数,报表可以根据传入的JDBC Connection来获到相应的数据 |
REPORT_DATASOURCE |
为报表中的Connection提供一个DataSource。外部传入的时候类型也要是DataSource类型 |
REPORT_SCRIPTLET |
报表生成时使用的Scriptlet实例,如果没有指定ScriptLet,那么这个parameters将使用net.sf.jasperreports.engine. |
IS_IGNORE_PAGINATION |
通过这个参数你可以控制分页功能是打开还是关闭。默认情况下,分页是打开的。但是如果导出为HTML或EXCEL时不进行分页处理。 |
REPORT_LOCALE |
它被用来设置报表所处的地区。如果没有提供地区,那么将采用系统默认的地区。 |
REPORT_TIME_ZONE |
设置报表的时区,如果没提供的话采用系统默认的。 |
REPORT_RESOURCE_BOUNDLE |
为报表指定要加载的资源文件,在国际化一章中介绍了如何使用资源文件来构建报表。 |
7.3变量(Variables)
Variables是用来存储对某些字段计算后的结果,比如sum等。
图1.9
和fields,parameters一样,Variables也是有数据类型的。你必须为一个Variable实例声明一个java类型。图1.9显示了如何创建一个新的Variable。看一下每个字段的意思:
Variable name: variable的名称,我们可以在表达式中通过下面的方法来引用一个Variable:
$V{variable name}
Variable Class Type : variable也可以是任意一个Java类型,在下拉框里你可以看到大多数常用的类型,如java.lang.String等。
Calculation Type : 一个计算类型可以用来计算结果。当一个预先定义的值是“nothing”时,那它的意思是不做任何计算。ireport会根据指定的计算类型和从数据源中获取的每一条记录计算出结果,然后去更改variables的值。做一个变量的计算意为着去执行一个表达式,如果计算类型为nothing,那么ireport将会根据variable expression为variable赋值。计算类型列举如下:
类型 |
说明 |
Nothing |
不做任何计算 |
Count |
对记录集数量进行循环累加(计算有多少条记录),这和sum不一样,sum的计算是针对数字的,会对数字进行累加操作。 |
Distinct Count |
也是对计算有多少条记录的累加操作,只是在累加过程中会忽略已经出现的记录(比如某个字段的值已经出现后就不会再记录) |
Sum |
添加每一次表达式(这里的表达式只能是数字类型)迭代的结果到变量中 |
Average |
它用算术的方法来计算表达式累加结果的平均值 |
Lowest |
返回表达式最小值 |
Highest |
返回表达式最大值 |
StandardDeviation |
根据表达式所有值返回标准方差 |
Variance |
返回表达式接收到的值的变化 |
System |
不做任何计算并且表达式也是没有价值的,在这样的用例中,报表引擎仅仅保存内存中variable的最后的值。 |
Reset Type : 重置类型。表示一个变量在什么时候做重置操作。reset类型如下:
类型名称 |
说明 |
None |
任何时候都不做重置操作 |
Report |
在报表创建的时候Variable才会对表达式进行初始化 |
Page |
Variable的初始化在每一页都做一次reset操作 |
Column |
Variable的初始化在每一列都做一次reset操作(这里的Column指的是report里的page的column,每个报表的column可以通过报表的Editàreport properties窗口进行修改) |
Group |
Variable的初始化在每一个组都做一次reset操作 |
Reset Group :如果group reset type被勾选,这里就要选择group名称(关于group可以参考后面的章节)。
Increment : 它指定当一个variable值被评估或当你想要这个组采用类似于subtotals 或averages来计算,increment 类型可以参考下面的表。
Increment Group : 如果这个group的increment type 被勾选它将指定这个组决定variable的increment。
Custom Incrementer Factory Class : 指定一个实现了JRIncrementerFactory接口的java类名称,通常用来定义一些诸如sum之类的非数字类型的操作。
Variable Expression : 它是一个java的expression,用来标识variable每一次迭代的值。
Initial Value Expression : 它是一个为variable初始化时采用的expression.
内置的variables
和parameters一样,ireport提供了一些内置的variables(这些由报表引擎直接管理),这些变量是只读的,不能被用户修改,如下表所示:
Variable 名称 |
说明 |
PAGE_NUMBER |
它包含当前页的页。 |
COLUMN_NUMBER |
它包含当前的列数。 |
REPORT_COUNT |
当前的记录数目 |
PAGE_COUNT |
当前的页号 |
COLUMN_COUNT |
当前的列号 |
<group name>_COUNT |
在<group name>里的记录总数 |
iReport栏和组(Band and group)
在本章中,我们将解释如何用iReports去管理bands和groups,在第四章中我们介绍了报表的结构,在本章中我们将要看到如何使用bands来划分报表。同时我们还将看到如何使用groups,如何创建report中的breaks,如何管理subtotals等等。
8.1栏(Bands)
ireport把一个报表划分成七个主要的bands和一个名为backgroup的band(一共是八个bands),每当我们添加一个group时就会有两个新的band添加到报表当中:group footer bands和group header bands。
点击按钮在弹出的窗口中我们可以对当前报表所具有的bands的进行相关属性的修改。
图8.1
通过上图中的窗口,我们可以修改左边列表窗口中的任何一个band的属性,比如它的高(以像素为单位)。Print When expression表示我们可以在这里输入一个表达式,这样我们可以根据表达式的值来控制当前的这个band是否输出。这里需要注意的是Print When expression里必须返回一个java.lang.Boolean类型的对象,如:
New Boolean(true)
上面的表达式说明这个bands总会被打印(如果我们什么都不输入这个就是默认值),在表达式里可以使用fields,variables,parameters。根据这个特性我们可以通过相关的fields,variables,parameters来灵活的控制当前的band是否可以输出,比如下面的代码:
($F{SALARY}.intValue()>4000?new Boolean(true):newBoolean(false))
上面的代码说明当salary的值如果大于4000就输出当前的band否则就不输出当前的band。
把鼠标移到bands的边上我们可以鼠标拖拉的方式改变band的大小以此来适配band里的内容。
图8.2
8.2组(Groups)
Groups允许我们对报表里的数据进行全新的切割分组组合。分组是通过一个表达式来定义的,ireport会通过这个表达式进行计算分组情况,每一个新的组都是从我们在expression value里输入的表达式发生变化的时候开始的。接下来我们将通过一个例子的演示一步一步说明如何使用groups。
假设我们有一个员工的列表,我们想要创建一个根据员工所在的部门进行分组的报表。
a)首先我们打开一个新的报表文件,然后点击Connection/Data Sources,选择JDBC Connection,我们创建一个JDBC的Connection,如下图:
图8.3
b)点击和工具栏里的按钮,输入查询语句,如下图
图8.4
c)把Employee_name和dept_id两个field拖到report 中的detail的band里,同时调整detail band的高度,如下图:
图8.5
d)保存报表文件,并按浏览报表生成后的效果,如下图:
图8.6
到这里,我们看到员工的数据已经可以在报表里显示,接下来我们就对员工信息按dept_id字段进行分组显示。
e)点击主工具栏里的按钮,打开groups定义窗口,并添加一个新的名为dept的group,如下图:
图8.7
一个group有下面几个属性需要我们去定义:
Group name:为这个group指定一个名称,group创建完成后会产生两个新的band : header和footer band,这两个band的名称采用group的名称来定义。
Start on a new column:如果此选项勾选,那么分组只会在报表中的新的column产生,也就是说在一页中报表分组在一个column里只会做一次。
Start on a new page:与上面的选项类似,如果该选项勾选,那么分组只会在每一页做一次,也就是说每一页最多只会有一个分组数据。
Reset page number:该选项允许在一个新组开始的时候重设页号。
Print header on each page:如果该选项勾选,那么如果当前页没能显示完组里的所有数据时,到一页显示该数据时会把该组的header打印出来,否则将不会打印。
Min height to start new page:该选项用来设置当前报表中页面所余下的高度的最小值分组的最小值,默认值是0,如果我们设置为100,表示如果当前页面余下的高度小于100就不再继续显示分组的数据,而是在下一页显示分组的数据。
Group expression : 分组时采用的表达式规则,如上图中我们在定义dept这个group时我们在GroupExpression里输入了$F{DEPT_ID},表示将该组按员工的DEPT_ID字段进行分组显示。
Group header band height:新产生的header band的高度。
Group footer band height:新产生的footer band的高度。
f)接下来我们把在detail band里的dept_id的field移到report里新产生的deptHeader的band里,
图8.8
g)点击按钮,报表的生成效果如下:
图8.9
在jasperreport里group的数量是没有限制的,一个group可以有一个父group同时也可以有若干个子group。通过group定义列表,我们可以通过”move up”和”move down”来设置group的顺序。
Group 向导
在iReport中还有一种简单的方法创建一个group,那就是向导,通过向导我们可以快速的创建一个group,我们可以通过主菜单中的Edit new report groupwizard来启动创建group的向导。
图8.10
向导允许用户创建最多有四个group的报表(group header,group footer和每一个group关联)。
Groups和records的排序
我们可以在设置查询的地方选择设置选项来使ireport自动对依据字段进行排序,我们也可以在创建一个group时要对分组的字段做好正确的排序工作。比如在sql中我们可以添加“order by ”来对要分组的字段进行排序。
iReport子报表(SubReport)
SubReport是ireport提供的高级功能,通过SubReport我们可以创建复杂的报表。通过SubReport我们可以创建一个包含若干个子报表的报表。创建一个包含子报表的报表我们需要三个对象:一个jasper文件,一个包含参数map(当然可以为空)和一个DataSource(数据源,或者是一个JDBC的Connection)。在本章中我们将解释如何通过这三个对象创建一个SubReport并实现在子报表中数据过滤显示的目的。
9.1创建一个子报表(create a SubReport)
一个SubReport是一个真正的包含它自己xml文件并且是一个已经编译好的jasper文件。创建一个SubReport就是创建一个普通的报表文件,创建过程中唯一需要注意的是设置SubReport的宽度、高度及一些不需要显示的band,一般情况下对于不显示的band我们把它们的高度都设置为0。在设置子报表的宽度时我们应该考虑到它在父报表中显示时的效果,然后针对这一特性有针对性的去设置。
在父报表中我们要添加一个子报表可以通过iReport中的SubReport工具 来实现。子报表的形状和一个距形类似,我们可以调整SubReport的尺寸和位置以控制子报表的显示。
将一个子报表链接到父报表中需要做三件事情:获得SubReport所对应的jasper报表对象、如何为它提供数据及如何为子报表的parameters设置具体的值。所有这些信息的定义我们可以通过SubReportproperties窗口来实现。
图9.1
图9.2
9.2传递参数(Passage of the parameters)
当我们在应用程序里通过fillReport方法来生成一个报表的时候,我们会提供一个包含参数值的Map一起传递到报表中,包含参数的Map对象是由报表引擎直接管理的。在子报表属性窗口的里的“SubReport”标签里的“Parameters Map Expression”属性就是提供给我们的最简单的方法来为子报表设置parameters的值,它允许我们定义一个最终可以返回java.util.Map对象的表达式,使用这种方法我们可以把从外部应用程序传到父报表里的parameter对象,当然这个parameter的实际值是一个java.util.Map对象传递给子报表使用(比如$P{TestMap}),这里我们也可以使用内建的报表parameters:$P{REPORT_PARAMETES_MAP}把子报表中的java.util.Map对象传递到父报表中供使用。如果该属性我们空着不填那么一个不包含任何值的空的java.util.Map将会被传到子报表中。这种机制的局限性是parameters里所对应的java.util.Map值是死的、不会变的。为了克服这种局限性jasperreport允许我们定义parameter键值对的时候每个对象的值通过一个表达式来创建,如在图9.2中的“SubReport Parameter”表中通过添加个参数java.util.Map来填充子报表。
图9.3
deptId是子报表中一个parameter的名称,如果设置值时也要与子报表中deptId的数据类型保持一致。
指定数据源
为子报表指定数据源就是告诉jasperreport引擎如何获到数据来填充SubReport。我们可以指定两种类型的数据源:JDBC Connection和DataSource。
使用JDBC来填充报表是很简单的,在Connection Expression里定义一个已经连接到数据库的java.sql.Connection对象。要把一个已经处于打开状态下的连接传到SubReport中我们只需使用一个预定义的包含一个基于从应用程序里调用fillReport方法时的传入的连接REPORT_CONNECTION参数
如果使用一个DataSource就稍微复杂一点,事实上它是一个简单的记录的集合,记录集合的概念和JDBCConnection不同,既然如此我们可以通过一个parameter来传递一个DataSource来填充SubReport,此时采用这种机制内建的parameter REPORT_CONNECTION就不再起作用了。
一个DataSource是一个普通的“消费品”对象仅仅可用来填充一次报表。所以一个作parameter传递的DataSource可以满足一个SubReport的需要。因此parameter的方式不能满足当父报表的每一行记录都有一些子报表的数据与之对应(除非主报表中只有一条记录)。当我们解释DataSource时我们可以看到这个问题可以通过自定义DataSource方式解决。
指定SubReport
创建一个SubReport我们需要指定一个扩展名为.jasper文件,我们需要在SubReport属性窗口中设置SubReport Expression属性。表达式返回的类型必须与我们在下拉框里选择的类似保持一致,类型列表如下:
类型名称 |
含义 |
net.sf.jasperreports.engine.JasperReport |
在一个JasperReport对象里预加载一个jasper文件 |
Java.io.InputStream |
一个jasper文件的流 |
Java.net URL |
一个用来定义jasper文件的URL |
Java.io.File |
一个jasper文件的File对象 |
Java.lang.String |
Jasper文件的文件名 |
如果表达式是一个String类型,那么引擎将通过JRLoad来加载指定位置的jasper文件。
9.3 子报表示例(SubReport sample)
在这个例子中我们将采用示例数据库来创建一个简单的包含子报表的报表。我们要从两张表里取数据:dept(部门表)、employee(员工表),要达到的效果是根据部门表的部门ID取出该部门下的所有员工。类似的效果的报表我们在groups一章中使用group也实现了一次,这里我们将用SubReport来实现相同的效果。
新建一个空报表,新建一个名为deptId的parameter对象,如下图:
图9.4
在这里我们在Default Value Expression里赋予了一个空的字符串,为什么要这样做呢,因为接下来我们要使用该parameter来作为SQL的查询条件的输入值,所以我们要对这个参数赋予一个初始化的值。
点击打开SQL查询引擎窗口,输入下面的查询语句:
Select * from employee where dept_id=$P{deptId}
在这里,我们在查询员工信息的时候加了一个部门的条件,如下图:
图9.5
此时如果我们把相关的field拖到detail band里,然后点击 我们发现没有任何记录,原因是因为我们并没有为deptId赋值。
保存报表文件,我们命名为emp.jrxml,我们把这个报表文件作为下面将要引用的子报表文件。因为它将作为子报表被引用,所以我们需要调整该报表的不用显示的band的高度及detail band的高度,如下图:
图9.10
在detail band里我们放置了三个字段:employee_name(员工姓名)、sex(性别)、birthday(出生日期)。
接下来我们需要建立一个父报表,关闭emp.jrxml文件,新建一个空的报表文件,命名为dept.jrxml。点击主工具栏里打开SQL查询窗口,输入下面的语句:
Select * from dept
如下图:
图9.11
把dept_name这个field拖动到报表的detail band里,同时在detail band里添加一个了报表,在弹出的子报表向导中我们选择“Cancel”按钮,这里我们不采用向导来创建SubReport。如下图
图9.12
双击子报表图标打开子报表属性设置窗口,在弹出的窗口中我们选择“SubReport”标签,在“Connection/DataSource Expression”属性里我们选择“UseConnection Expression”并且指定内建的parameter:REPORT_CONNECTION作为表达式用来存储JDBC连接,如下图:
图9.13
切换到“Subreport(other)”标签窗口,指定如何找到子报表文件“emp.jasper”以及如何创建和修改在子报表与父报表之间的参数传递。
使用绝对路径在iReport里我们不用去考虑子报表文件是否可以被找到的问题,因为子报表存放的目录已经被自动的加到iReport的classpath里了。这里我们指定的值是“$P{SUBREPORT_DIR} +java.io.File.separator+"emp.jasper"”
图9.14
为了在子报表里可以显示员工的信息我们需要为子报表的deptId这个parameter赋值,这里我们通过父报表传过去,在“Subreport parameters”窗口中,我们添加了一个用于为子报表的deptId赋值的parameter,该值到于父报表中的$F{DEPT_ID}这个field。编译子报表和父报表。
点击主工具栏中的按钮,查看生成的后父报表效果。
图9.15
在这里我们看到子报表里的有一些字段显示的有问题(如sex性别这块显示的是true和false,还是日期不是我们要的日期格式),需要我们进一步对显示的字段信息进行格式化操作。
打开emp.jrxml文件,选中detail band里的sex field,右键选择properties,在弹出的窗口作如下修改:
图9.16
在Text Field Expression里我们输入($F{SEX}.booleanValue()?"男":"女")的意思是把原来显示的true和false翻译成男和女。这里$F{SEX}是java.lang.Boolean类型,所以需要先把它转化成java.lang.Boolean所对应的简单类型,然后如果值为true则为男,否则为女。对于birthday(出生日期)我们同样需要对其做格式化操作,如下图:
图9.17
关闭emp.jrxml(关闭之前别忘记对其进行编译)。打开父报表dept.jrxml文件,编译查看报表效果:
图表9.18
Return Parameters
有时候我们需要从子报表里返回一些值到子报里,比如子报里有多少条记录等。
Jasperreport1.0.0提供的一个新的特性就是允许用户从子报表中返回值到父报表中,如下图,在“Subreport (other)”标签下的“Subreport returnvalues”标签里设置我们需要在父报表里显示子报表里的参数值。
图19.19
SubReport Wizard
从前面的操作中我们可以看出,当我们插入一个SubReport时会自动弹出向导窗口,通过这个向导窗口我们可以快速创建一个SubReport对象,创建过程非常简单,我们这里就不再介绍。
ireport数据源
一个DataSource是Jasperreport获取数据以生成报表的源。这里有两种类型的DataSource:一种是JDBC Connection用来从关系型数据库里取数据;另外一种是扩展了JRDataSource接口的java object,这种类型的对象允许我们去管理数据的细节,比如一个xml文件或一个javabean的集合。
通过sql 查询从关系型数据库里取数据来填充生成报表是很简单的,iReport可以通过各个数据库厂商提供的JDBC Driver来获取连接生成要检索的field。
如果我们不通过JDBC直接访问数据库来获到生成报表的字段与数据的时候,我们需要使用JRDataSource(全称JasperReport Data Source).JRDataSource是一个接口,它允许我们访问具有行列结构的数据(在Datasource行我们叫records,列我们叫record fields).
不管是JDBC Connection还是JRDataSource他们都不能通过JasperReport来创建,但是当应用程序调用生成报表的时候我们可以通过JasperReports的fillReport方法传递一个打开的数据库连接(一个java.sql.Connection对象)或者是一个JRDataSource对象实例用于填充被调用的报表.对于传递一个java.sql.Connection对象的情形JasperReports将在指定的报表里使用JDBC Connection来执行一个SQL查询.查询的结果将会被包含在一个JRResultSetDataSource对象里(JRResultSetDataSource也是一个JRDataSource对象的实例),这样JasperReports将使用一个JRDataSource对象来关联打印数据。
在本章中,我们将阐述JRDataSource的不同类型和他们如何在iReport中使用。此外我们还将看到如何对一个JRDataSource做扩展;通常通过扩展一个datasource可以克服JsperREports自身的一些局限性,比如在交叉报表中使用等。
10.1 iReport中的数据源(DataSource iniReport)
iReport允许我们管理和配置不同类型的DataSources用来填充报表。这些DataSources被储存在iReport配置文件中当我们需要的时候即可以使用。
我们可以使用的DataSources类型如下:
- JDBCConnection
- XMLDataSource
- JavaBeanCollection DataSource
- CSV DataSource
- CustomDataSource
- JRDataSourceProvider
- HibernateDataSource
打开状态的JDBC Connection在报表生成的时候会被直接传递到JasperReport中。XML DataSource允许我们从XML文档里获取数据用来填充报表。一个CSV DataSource允许我们打开一个CSV文件来填充报表。JavaBean Collection DataSource,Custom DataSource和JRDataSourceProvider他们允许我们一个写好的java类来获取数据。Hibernate DataSource定义了一个执行HQL语言的方法。DataSource的管理我们可以通过在主菜单“DataConnections/DataSources”(图10.1)打开配置管理DataSource窗口界面。
图10.1
从技术的角度去看一个Connection和一个DataSource是两个不同的对象(Connection需要一个关系一个关系型数据库,但是一个DataSource只是提供一个简单的接口用来访问数据结构)。
虽然我们可以建立了若干个DataSource准备使用,但是iReport在工作时同一时候总是使用一个DataSource或一个connection。因此你需要设置一个“active”datasource。设置一个dataSource为“active”最简单的方法是在工具条上的下拉框里选择一个你要使用的datasource,那么这个datasource就处于“active”状态了。
图10.2
同时你也可以从主菜单里的“DataàSet the active connection”在弹出的窗口中选择一个DataSource并设置其为“active”状态。
图10.3
最后我们还可以在DataSource窗口里通过“set default”来设置“active”状态的DataSource。
图10.4
如果没有datasource处理“active”处于激活状态,那么iReport里生成的报表里面将不会产生数据。同时当我们使用报表向导的时候要求必须要有一个处于“active”状态的JDBC Connection。
10.2 JDBC连接(JDBC Connection)
一个JDBC Connection允许我们从一个关系型数据库里直接获取数据(需要有一个JDBCDriver)。要添加一个新的JDBC Connection,可以点击“New”按钮(如图10.1)打开创建新连接的管理窗口。
图10.5
选择“Database JDBC Connection”点击“Next”,在出现的窗口中输入数据源的名称及Driver、URL、username,password等相关信息。
图10.6
点击“test”按钮,对JDBC连接做测试。
图10.7
完成新建JDBC Connection之后,别忘了在管理窗口中设置Connection的“active”状态。
当报表采用的是一个JDBC Connection创建的时候,用户需要指定一个SQL语句用来从数据库里取出数据。主报表的Connection也可以为其子报表提供服务。例如,JasperReport里的REPORT_CONNECTION,一个java.sqlConnection类型的内建参数对象放在表达式里提供给子报表使用。
$P{REPORT_CONNECTION}
这个参数包含的是一个正确的从应用程序里传入的java.sql.Connection对象。使用JDBC或一个SQL Connection是一种最简单的最容易的方式用来填充报表,关于创建SQL查询的细节我们将在11章中讲解。
为了可以在报表中使用通过SQL查询出来的fields,我们需要“Register”它们(要注册的可能不是全部是字段,仅仅只是我们在报表中要使用的字段)。对于每一个字段我们需要指定一个名称和字段的类型,下表中显示了SQL类型所对应的Java类型。
SQL 类型 |
JAVA类型 |
CHAR |
String |
VARCHAR |
String |
LONGVARCHAR |
String |
NUMERIC |
Java.math.BigDecimal |
DECIMAL |
Java.math.BigDecimal |
BIT |
Boolean |
INTYING |
Integer |
SMALLINT |
Integer |
INTEGER |
Integer |
BINARY |
Byte[] |
VARBINARY |
Byte[] |
LONGVARBINARY |
Byte[] |
DATE |
Java.sql.Date |
TIME |
Java.sql.Time |
TIMESTAMP |
Java.sql.Timestamp |
表10.1
在上面的表当中对于BLOG和CLOB类型和其它的特殊类型如ARRAY、STRUCT,REF等我们没有指定对应的JAVA类型,这是因为这些类型在JasperReports里不能自动管理它们。
10.3 JRDataSource接口(The JRDataSourceInterface)
除了使用SQL做为数据源之外,我们还可以使用其它类型的数据源。在使用之前,我们需要明白如何使用JRDataSource接口。对于实现每一个JRDataSource接口的类必须实现两个方法:
Public Boolean next()
Public Object getFieldValue(JRField jrField)
对于第一个方法是用来移动一个虚拟的游标到下一条记录,判断是否还有记录。如果Next方法返回true表示还有记录否则表示已经没有记录了。
当JasperReports执行next方法时,在报表里声明的所有字段将被赋上相应的值并且所有的表达式重新计算它的值,接下来将决定是否在一个新的group里打印header,是否开始一新的页等。当next方法返回false时,报表的内容也就宣告结束同时开始打印所有的最后的bands(group footer,column footer,last pagefooter 和summary)。很多时候需要调用next方法用来取下一条记录。
当JasperReports调用完成next方法后如果返回true的时候就调用getFieldValue方法。事实上报表里的每一个field在取值的时候都会调用getFieldValue方法(查看第七章看如何声明一个报表的field)。getFieldValue方法返回数据的类型必须与声明的字段类型相匹配,当然如果返回一个null除外。
10.4使用JavaBean作为数据源(JavaBean set datasource)
在DataSource里面我们还可以使用一些JavaBean做为数据源来填充数据,这里的JavaBean指的是一个POJO,里面private类型的若干个属性和与之对应的getter方法:
Public <returnType> getXXX()
这里的<returnType>(返回值)是一个普通的java类或一个简单类型如int、double等。
要创建这种类型的connection我们只需在创建的时候选择“JavaBeans set datasource”
图10.8
点击“Next”输入“JavaBeans set data source”的名称,JavaBean set datasource使用一个扩展类(一个工厂类)来生成我们所需要的JavaBean对象,然后组合成数据传递到报表当中。输入包含包名的java class名称,它需要有一个static方法产生一个包含若干个javaBean的Collection类型或一个array(Object[])类型。让我们来看看如何去写这个工厂类。
假如你的数据是一个Person对象,它包含两个fields:name和age:
Person { String name; age; Person(String name, age) { (); .name = name; .age = age; } getAge() { age; } setAge( age) { .age = age; } String getName() { name; } setName(String name) { .name = name; } } |
接下来我们要写我们的工厂类,我们这里的工厂类名为TestFactory
TestFactory { java.util.Collection generateCollection(){ java.util.List list = java.util.ArrayList(); ( i = 0; i < 10; i++) { Person p= Person("user"+i,i); list.add(p); } list; } } |
我们的DataSource提供了一个包含10个Person类型的JavaBean。使用JavaBean作为DataSource的特点是它的字段必须通过getter方法暴露在外面,意思是如果我们的JavaBean有一个getXyz方法,那么xyz就是一条记录的field,在我们的例子中我们的是name和age。创建一个新的创建文件,然后添加两个名为name和age的字段:
图10.9
接下来把这两个字段拖到报表detail当中。
图10.10
将前面我们做的两个类添加到iReport中的classpath当中。添加一个JavaBean set data source,名为TestBeanDataSource,并将其设置为“active”,如下图:
图10.11
启动生成报表效果如下:
图10.12
10.5 JREmptyDataSource
在JasperReports中提供了一个名为JREmptyDataSource特殊的DataSource,这个DataSource是当我们点击 按钮生成报表时调用。这个DataSource的next方法会根据记录的数量返回true,同时每次调用getFieldValue方法时总是返回null值。这种操作有些类似于一些记录没有字段一样,这就是一个空的DataSource。
该项类有两个构造方法:
Public JREmptyDataSource(int count)
Public JREmptyDataSource()
第一个构造方法让我们告诉这个DataSource该返回多少条记录,第二个构造方法会把记录的总数设置为一。
当我们点击按钮生成报表时我们可以按住shift键来设置报表里产生的空记录数。如下图:
图10.13
10.6 HQL查询和Hibernate连接(HQL and Hibernate connection)
从jasperreports1.2版开始,Jasperreports提供了一种直接使用HQL(Hibernate Query Language)来创建报表。要使用这个功能,首先我们需要设置一个Hibernate connection。把所有的JAVA编译好的类,jar包和使用Hibernate mapping的配置文件放在classpath里。换句话说,iReport必须要保证可以访问所有的你需要使用的*.hbm.xml文件。
把这些对象添加到classpath中的方法是,选择主菜单中的ToolsàClasspath,在弹出的窗口中设置你需要加入到classpath中的对象。
接下来我们需要打开DataSource对话框,点击“New”新建一个DataSource,不过这时我们选择Hibernate connection作为我们的DataSource类别。点击“Next”输入connection的名称。再次点击“Next”进入下上步设置,如下图:
图10.14
在点击“test”按钮时要保证hibernate.cfg.xml在你的classpath里。
同时设置这个“test hibernate”为active状态。此时iReport仅使用Hibernate Configuration工作。
从主菜单中的ViewàReport query里打开查询窗口,在Query language里我们选择Hibernate QueryLanguage(HQL),然后输入相应的HQL,接下来的工作就像使用SQL一样啦。
10.7如何实现一个新的JR数据源(How to implement a new JRDataSource)
有时使用Jasperreports所内置的JRDataSource不能完全满足我们的要求。此时我们可能需要写一个自己的新的JRDataSource。自定义一个JRDataSource并不复杂,事实上创建一个自定义的JRDataSource就是实现JRDataSource接口类,重写里面的next和getFieldValue方法就OK啦。
Package net.sf.jasperreports.engine Public interface JRDataSource{ Public Boolean next() throws JRException; Public Object getFieldValue(JRField jrField) throws JRException; } |
这里的next方法是用来把记录移动到下一条,同时判断还有没有记录。如果返回true表示还有记录可用,否则表示没有可用记录了。
当next方法调用时,getFieldValue方法将会返回请求字段的值(如果请求的字段没找到或不存在,那么将返回null)。一般来说,请求字段名会作为参数包含在JRField对象里。JRField是一个接口对象,通过它我们可以得到三种信息:字段名称,描述,和字段类型。
接下来我们就来写一个我们自己的DataSource。我们的这个DataSource要实现对一个目录进行浏览并返回里面的文件或文件夹。DataSource的field有以下几方面:文件名(fileName),一个标志位(isDir)用来表示它是一个文件还是一个文件夹,文件大小(size)。
我们的DataSource有两个构造方法,一个构造方法有一个参数可以用来接收要扫描目录;一个就是没有参数的构造方法(那么将采用默认的目录进行扫描)。
我们这个DataSource将会根据指定的目录查询文件和文件夹,并且以一个文件数组的形提供出来。
test; java.io.File; net.sf.jasperreports.engine.JRDataSource; net.sf.jasperreports.engine.JRException; net.sf.jasperreports.engine.JRField; JRFileSystemDataSource JRDataSource{ File[] fileArray; index=-1; JRFileSystemDataSource(String path){ File f= File(path); (f.exists() && f.isDirectory()){ fileArray=f.listFiles(); } } JRFileSystemDataSource(){ ("."); } Object getFieldValue(JRField arg0) JRException { File f=fileArray[index]; (f==) ; (arg0.getName().equals("fileName")){ f.getName(); } (arg0.getName().equals("isDir")){ Boolean(f.isDirectory()); } (arg0.getName().equals("size")){ Long(f.length()); }{ ; } } next() JRException { flag=; index++; (fileArray!= && index<fileArray.length){ flag=; }
flag; } } |
到这里我们自定义的一个JRDataSource已经完成了,接下来我们将会来解释如何在报表中使用我们自己的的DataSource。
为了使用这个DataSource,接下来我们需要编写一个JavaBean set DataSource,这个和我们前面写过的很像,代码如下:
test; net.sf.jasperreports.engine.JRDataSource; TestFileSystemDataSource { JRDataSource getFileSystemData(){ JRFileSystemDataSource("d:/doc"); } } |
这个类中的static方法将会被调用,执行并产生一个新的JRFileSystemDataSource对象,同时指定该对象里的文件夹路径为“d:/doc”目录。
接下来我们可以新建一个connection,创建时我们选择“Custom JRDataSource”类型,并设置它的名称为“Test FileSystemDataSource”,如下图:
图14.5
接下来我们需要在页面中新建三个field,分别是fileName(String),isDir(Boolean),size(Long),并将他们拖到报表的detail band中,如下图:
图14.6
运行报表,生成效果如下:
图14.7
对于这种生成的格式,为了美观期间我们可以对其进行格式化。把“目录/文件”拿掉,通过在“文件名”列前面加图片的方式来显示该文件是文件还是文件夹。
在detail里,在fileName列前加一个image对象,并在其Expression里加上如下代码:
($F{isDir}.booleanValue()?"D:\\iReport-2.0.1\\report test\\folder.gif":"D:\\iReport-2.0.1\\report test\\file.gif") |
该句话的含义是:如果isDir返回的为true则输入文件夹图片,否则输入文件图片,如下图:
图14.8
设置报表的列数为2,报表排版如下:
图14.9
启动报表,生成的效果如下:
图14.10
国际化
国际化意味着报表可以根据不同的地区显示不同的语言文字。报表所要显示的不同的语言文字是存储在资源文件里。在本章中我们将介绍怎样使用内置函数msg()来处理国际化问题。
资源文件 (Resource Bundle Base Name)
当我们想让一个报表实现国际化功能时,我们需要定位所资源文件里的名称字符串,就是label或者叫key,key与value是一对字符串,中间用“=”连接。如:
Title_username=用户名 Title_phone=电话号码 |
保存这些key与value对的文件以“.properties”为后缀。在运行期间,报表引擎将会在classpath里查找以“.properties”结尾的资源文件。如果文件找到了,那么就从文件里读取相应的资源信息。资源文件的指定是通过报表属性窗口的“i18n”来实现的。
一般来说,一个资源文件名的组成包括三个部分:一个是资源文件名,一个是国家地区代码(与文件名之间以“_”连接),最后就是文件的扩展名“.properties”。对于默认的资源文件名来说是没有国家地区代码的。完整的资源文件的格式如下:
<resource bundle base name>[_language code[_country code[_other code]]].properties |
比如:
I18nReport_fr_CA_UNIX.properties I18nReport_zh_CN.properties I18nReport_en.properties I18nReport.properties |
前面格式里提到的“other code”(比如上面的“_UNIX”)一般不去指定它。
在iReport中,它有能力自己去管理资源文件,资源文件我们需要把它和报表文件(jrxml文件)放在同一目录,并且资源文件的名称也要与报表文件的名称保持一致。
我们可以从主菜单的“EditàInternationalication”的“Localization files”打开资源文件管理窗口。如下图:
图11.1
我们可以通过“Create New Locale”按钮创建一个新的资源文件。
图11.2
创建时我们需要指定文件名及国家代码,创建完成之后我可以通过“Modify file”按钮来对资源文件的内容做相应的修改。
图11.3
11.2获取本地化字符串 (Retrieval of localized strings)
得到资源文件里的key所对应的vlaue我们可以通过下面的方法实现:一种是使用JasperReports内部的表达式str(“key name”),或者是使用表达式$R{keyname}:
$R{test.name}
在JasperReport中的国际化我们可以使用函数msg,通过使用msg函数我们可以对取到的国际化的值做相应的格式化处理。比如我们的资源文件中一个key/value对为:
title=my name is {0}
此时我们需要为{0}指定具体的值,通过使用msg函数我们可以对这里的{0}进行填值处理:
msg($R{title},"gaojie")
这样在报表生成后最终的值就是:my name is gaojie
我们有三种方式来使用msg函数:
Public String msg(String pattern,Object arg0) Public String msg(String pattern,Object arg0, Object arg1) Public String msg(String pattern,Object arg0, Object arg1, Object arg2) |
在iReport中我们可以指定所在地区,这样我们就可以控制显示的语言。点击主菜单“Buildàset report local or BuildàSet time zone”,在弹出的窗口中我们可以对地区做相应的修改。
iReport中的脚本(Scriptlet)
Scriptlet是一个javaclass用来在报表生成的时候执行特定的动作(比如新页开始的时候或者处理结束的时候)。在本章当中我们将要看如何写一个简单的Scriptlet以及如何在报表里使用它们。
12.1 JRAbstractScriptlet
要写一个scriptlet我们只需扩展java类net.sf.jaspererports.engine.JRAbstractScriptlet。在该类中可以触发报表生成的时候,数据产生的时候的事件,同时我们可以访问报表中的所有的variables,fields,parameters。
最简单的scriptlet实现类是jasperreports提供的JRDefaultScriptlet:
package net.sf.jasperreports.engine; public class JRDefaultScriptlet extends JRAbstractScriptlet { public JRDefaultScriptlet() { } public void beforeReportInit() throws JRScriptletException {} public void afterReportInit() throws JRScriptletException {} public void beforePageInit() throws JRScriptletException {} public void afterPageInit() throws JRScriptletException {} public void beforeColumnInit() throws JRScriptletException {} public void afterColumnInit() throws JRScriptletException {} public void beforeGroupInit(String groupName) throws JRScriptletException {} public void afterGroupInit(String groupName) throws JRScriptletException {} public void beforeDetailEval() throws JRScriptletException {} public void afterDetailEval() throws JRScriptletException {}
|
就像我们看到的那样,该是一系列的after和before组成的方法,这些方法代表着不同类型事件的触发。
事件/方法 |
描述 |
Before Report Init |
当报表初始化的之前时候调用该方法 |
After Report Init |
当所有的的variables初始化之前的时候触发该方法 |
Before Page Init |
当产生一新页的时候,所有variables初始化之前调用 |
After Page Init |
当产生新页时,所有的variable初始化之后调用 |
Before Column Init |
当产生一个新的column时,在所有的variables的resetType为“columns”时初始化之前调用 |
After Column Init |
当产生一个新的column时,在所有的variables的resetType为“columns”时初始化之后调用 |
Before Group<x> init |
当group x调用的时候,并且所有的variables 的resetType为“group”,group x 初始化之前调用 |
After Group<x> init |
当group x调用的时候,并且所有的variables 的resetType为“group”,group x 初始化之后调用 |
Before Detail Eval |
在detail band打印的时候之前调用 |
After Detail Eval |
在detail band打印的时候之后调用 |
在Scriptlet内部我们可以使用下面的Map得到所有的fields,variables和parameters,这些Map是:fieldsMap,variablesMap和ParametersMap。
iReport模板(Template)
在iReport 中最有用的工具之一是使用向导利用templates来创建报表,在本章里我们将解释如何创建一个自定义的templates,如何把它们添加到我们的模版库里。
13.1模板结构 (Template structure)
一个模版文件就是一个普通的jrxml文件。当使用向导创建一个新报表时选择的模版文件将会被加载同时会对用户输入地方做相应修改。
有两种类型的模版:columnar 和tabular。columnar是一种用一个静态的text显示field name同时用一个textfields显示field的值的竖排的记录报表(如图13.1)。
图13.1 Columnar template
而Tabular类型将会像下图这样显示所有记录(图13.2)
图13.2 tabular type
模版是一些放在iReport安装目录下templates目录里的jrxml文件。iReport根据文件的名称来决定它是columnar类型还是tabular类型的模版。如果文件名以T结尾,那么它将作为一个tabular类型的模版。如果它是以C结尾的话它将会被做为columnar类型模版。下面是iReport提供的模版列表:
File |
Report type |
classiC.xml |
Columnar report |
classicT.xml |
Tabular report |
Classic_landscapeT.xml |
Tabular report |
graycC.xml |
Columnar report |
grayT.xml |
Tabular report |
Gray_landscapeT.xml |
Tabular report |
表13.1 iReport提供的报表模版
我们打开classicC.xml文件,查看之后我们可以明白一个模版的结构。在这个文件里你可以发现四个组:group1,group2,group3,group4,title band和group footer可见,columns band不可见(因为对于columnar 类型的报表columns band没有用)。在detail band里有一些为将来每一个field准备的静态的text label作为模版的label(如图13.1),textfield是一个真正的field。在particular里每一个group可以通过n包含一个图形元素和一些静态text元素:
GnLabel
这里的n代表group的编号,textfield元素包含下面指定的表达式:
GnField
这个元素将包含使用group表达式的值。
图13.3 Columnar template
Detail部分至少要包含像下面一样的一个静态文本:
DetailLabel
同时一个textfield元素用下面的表达式:
DetailField
其它的bands可以包含任何元素。在这些bands中将会在使用模版时生成。
表格类型的报表模版的设计和上面很相似,图13.4是classicT.xml在窗口里显示时的情形。
同样,有四个group,在它们之前有一个column header,它需插入一个静态的字符串作为columns labels。
在detail band区域,仅仅只有一个DetailField元素将被作为所有列的一个列名标签。
图13.4
模版是不能编译的,这是因为在textfield里包含的表达式不是一个合法的java表达式。
13.2使用自定义模板 (Using a custom template)
下面我们就来看一下怎么创建和使用一个模版。最简单的方法是打开一个已经存在的模版,选择一个最接近我们想要的模版的类型,然后按我们想要的对其进行修改,对存在的元素进行修改添加新的元素或者删除不需要的元素
图13.5
为了使用模版,我们必须把改好的模版入到templates目录里。记住使用.xml作为扩展名,在图13.5的例子中我们命名为mytemplateT.xml。添加C或T字母到模版的扩展名之前表示模版的类别。
以上工作完成后,我们可以通过向导来创建一个新的报表。在模版选择处我们可以看到新的我们刚才添加的报表模版在模版列表当中(图13.6)。
图13.6
这里,你应该可以看到我们自定义的模版没有预览图可用,要想让我们自定义的模版关联到一个预览图可以在templates文件夹里放上一个150x150的gif图片(在这个例子当中我们用的图片名叫: mytemplateT.gif).
图13.7
图13.7中显示了在向导窗口中当我们选择我们自定义的模版时出现的预览图。
使用模版可以帮助我们提高开发报表的效率。通过使用我们自己的模版,我们创建的报表生成的效果如下:
图13.8
13.3将模板放置在jar文件中 (Put templates in jar files)
我们知道模版文件都是放置在模版目录里面的。这样的话当iReport访问远程文件系统时可能会带来一个问题,当发展到0.5版本的时候我们可以把模版文件放到jar包里去,每一个jar可以包含一个或多个模版和一个在ireport目录下的名为template.xml的模版描述文件。当报表向导执行时,iReport将要查找所有的在classpath下的可用的名为/ireport/templates.xml文件。
为了了解如何使用一个jar提供一个模版,我们来创建一个基于名为Classic TemplateResource模版的例子。
Template.xml的内容如下:
<?xml version="1.0" encoding="UTF-8"?> <iReportTemplateSet> <iReportTemplate name="Classic Template Resource" type="Columnar"> <XmlFile>/it/businesslogic/ireport/templates/classic.xml</XmlFile> <IconFile>/it/businesslogic/ireport/templates/classic.gif</IconFile> </iReportTemplate> </iReportTemplateSet> |
Template.xml定义了一个模版的集合,每一个模版我们都可以定义它的名字,类型(columnar或者Tabular),和图标。
这个jrxml和图标用“/”开始指定,我们jar里的内部目录树可能类似于下面这种。
template_sample.jar
├───ireport
├───it
│ └───businesslogic
│ └───ireport
│ └───templates
└───META-INF
Template.xml将要被放到ireport目录下,同时所有的其它文件(如这个例子中的 classic.xmlt和classic.gif)将会被放到/it/businesslogic/ireport/templates目录下。
把创建好的jar放到classpath里,这时即使在模版目录里没有它我们也可以使用啦。
iReport图表(Chart)
iReport很多的图表(Chart)类型可提供使用。iReport现在支持Pie,Pie 3D,Bar,Bar 3D,XY Bar,Stacked Bar,Stacked Bar 3D,Line,XYLine,Area,XY Area,Scatter Plot,Bubble,Time Series,High Low Open Close和Candlestick 多种类型图表。
iReport使用jfreechart作为其图表引擎,jfreechart是一个强大的chart 生成工具。
创建chart的机制是建立在dataset的概念之上的,这就使得数据的管理和对更多复杂图表类型如High Low 之类实现可视化。
14.1第一个图表 (First chart)
在这一章节里我们将来学习如何使用chart 工具一步一步在一个报表里创建一个Pie3D的chart。在这个例子中我们将使用doradosample里的数据库作为数据源。
建立一个空白的文档,点击打开查询窗口并且写下如下查询语句:
select degree,count(*) employeeCount from employee groupby degree
图14.1报表的查询窗口
这里我们想生成一个chart用来显示根据学历员工数目。点击OK确认,iReport将注册查询得到的fields。同时把这些fields从objects library里拖出放入detail的band里(图14.1)。
图14.2
选择chart tool 在summary里放置一个新的chart。
图14.3
从charts窗口里我们选择pie3D图标并按OK按钮。请查看图14.3。
要配置chart,双击chart打开属性窗口,同时你可以通过右键菜单的方式打开chart的属性窗口。
图14.4
图14.5
点击“Edit chart properties”按钮出现的chart属性窗口。
图14.6
这个窗口包含两个标签:“Chart properties”和“Chart Data”。第一个标签包含控件的parameters列表;第二个标签是用来决定和当前图片关联的数据。修改图形的不同样式,设置背景的alpha和前景的alpha为0.5和depth factor(深度因子)为0.2。
下一步定义和图形关联的data。切换到“Chart Data”标签。
图14.7
在“Type of dataset”列表框中允许你指定一个dataset用来生成图形。在“dataset”标签里你可以在报表的上下文里指定一个dataset。Reset type和Reset group 允许你对dataset进行重置。
为了我们的需要,我们设置Reset type 为“Report”当我们不想数据被重置时。同时我们设置Increment type 为None,这样每一条记录都将被附加到我们的dataset里。
在Detail标签里允许你键入一个表达式和每一个在datasource里单独的值关联。针对Pie 图表类型,有三个表达式需要我们输入:Key,Value和Label。
表达式Key允许你标识Pie图里的一块。如果Key的值出现重复,那么Label和Value的值会关联起来用来覆盖Key的值。一个Key值不能为null。Value的表达式值指定这个Key的数字值。
Label表达式的值允许你为并图中每一块指定一个标签。这个表达式的值是可选的,同时默认值为“<key>=<value>”,例如:“A=100”,A是并图中一个块的Key同时100是它的值。
图14.8
确认对chart的修改,保存文件并且点击 按钮启动报表。在图14.9里我们可以看到最后的效果。
图14.9
14.2数据集 (Datasets)
当报表生成的时候chart会去收集数据然后存储在相关的dataset里。Dataset类型有:
Pie
Category
Time period
Time series
XY
XYZ
High-Low
可以把dataset想成是一个表格,每一个dataset都有不同的列(fields)。当一条新记录插入到dataset里时值将会被添加到fields里。
在图14.7中演示了在jasperreports中如何从dataset里取得数据你可以选择的一些选项。特别地,如果dataset必须为空的话同时当添加一行新的记录到dataset里时你可以指明它。根据你选择的dataset类型,在“Chart data”标签里显示指定的dataset的fields。
14.3图表属性 (Properties of the charts )
我们可以通过图14.5显示的窗口来管理chart的外观。在这个窗口里你可以查看并编辑charts和graphs的通用属性(如title,图例等)。
你可以使用表达式编辑框来更改Chart title 和Chart subtitle表达式
图14.10
JasperReports只是利用了JFreeChart图表库的一小部分功能。如果你想自定义一个图表你可以写一个实现下面的接口的类:
Net.sf.jasperreports.engine.JRChartCustomizer
从这个接口中我们只需要实现一个方法:
Public void customize(JFreeChart chart,JRChartjasperChart);
在这个方法里用JFreeChart和JRChart作为它的参数。JFreeChart作为第一个参数通常是用来产生图片的,第二个参数包含用户在设计阶段一些参数。
iReport子数据集(SubDataset)
报表的生成是基于一个data source(一个查询,一个java 的collection或者一个xml)。当你想要处理一个chart或一个crosstab时,这时可能上面的data source就不行了。一个subdataset 可用来在报表里提供另外一种记录集。你可能会使用一个subdataset用来填充一个chart或一个crosstab。在一个报表里你可以有任意多个subdatasets。
一个subdataset可以有它自己的fields,variables,parameters,同时如果需要它还可以执行一个查询。Dataset里的记录可以像主报表一样进行一次或多次分组。在组里可以使用subdataset的variables。一个subdataset通过一个叫“dataset run”的选项和一个chart或一个crosstab关联。
15.1创建一个数据集 (Creating a subdataset)
要创建一个新的subdataset,可以在工程library里右键选择“add-sub dataset”方式完成。
图15.1
Subdataset的创建窗口打开。
图15.2
这里你需要设置subdataset的名称,同时你也可以使用该subdataset合适的“when resource missing type”指定一个resourcebundle(查看关于资源文件的国际化章节)。
Jasperreports允许使用scriptlet在一个subdataset的records里执行一个特殊的计算。如果你需要你可以指定一个你的scriptlet类的名称。点击“create”按钮把这个subdataset添加到报表当中。
你可以在library标签里或者在subdataset列表对话框里查看刚才新建的subdataset (主菜单中Edit->sub dataset)
图15.3
图15.4
你可以使用和在主报表中相同的方法添加fields,variables和parametres到你的subdataset里。 Subdataset窗口里的“Query”按钮可以打开查询工具用来指定一个查询(像在主报表里一样),你可以用一个查询或一个其它的数据源(如javabean等)来反向得到字段。
15.2运行数据集 (Dataset runs)
你可以在一个chart里或一个crosstab里使用subdataset。JasperReports 需要一些扩展信息诸如jdbc connection执行sql 查询或者为一个指定的subdataset的parameter用来填充dataset。所有这些信息的提供者是一个dataset run。
图15.5
Dataset 的工作方式与在主报表中引用一个SubReport类似。你可以使用表达式(里面可以包含主报表里的对象,如:fields,variables,parameters)为指定的subdataset的parameters设置值。在启动运行时可以定义一个parameters Map来为subdataset parameters填充值,同时还可以定义一个连接或一个datasource在subdataset获取数据时使用。
实例
在这个例子中我们将演示如何使用一个subdataset去填充一个chart。
在主报表中只有一条统计所有记录总数的记录(select count(*) as employeeCount from employee)
第一步,创建一个新的空白报表
图15.6 第一步,创建一个新的空白报表
第二步,打开查询工具( )同时插入下面的sql语句:
|
图15.7
第二步,插入查询语句
第三步,从library 标签里拖动字段employeeCount到detail band如下图添加一个labels
图 15.8 添加字段employeeCount
第四步,创建subdataset
在library里右键选择弹出菜单选择Add->sub Dataset,我们创建一个名为subdataset1的subdataset。
图 15.9 创建一个新的subdataset
第五步,在subdataset的对话框里点击“Query”按钮,我们键入如下语句:
select degree, count(*) as empCount from employee groupby degree
图 15.10 定义subdataset的查询语句
第六步,添加pie3d chart到报表里
图15.11 创建一个chart
第七步,编辑chart属性
打开chart属性编辑窗口我们来编辑一下chart的相关数据,选择subdataset1作为它的subdataset。切换到“Connection/Datasource exp”标签同时从下拉框里选择“useconnection expression”。这里我们使用主报表里的connection来填充subdataset($P{REPORT_CONNECTION}) 。
图15.12 设置chart属性
第八步,设置Pie Dataset的属性
切换到“Detail”标签,我们输入下面的表达式:
Key expression: $F{DEGREE}
Value expression : $F{EMPCOUNT}
Label expression : $F{DEGREE}
图15.13 定义pie data
第九步,保存并启动报表
图15.14
第十步,报表制作完成
图15.15 最终的效果
用iReport制作交叉表(CrossTabs)
一个CrossTabs是一种在设计的时候既不确定行数和也不确定列数的一种表格,在运行环境下它会像下面显示的不同年份的一个销售报表一样。
水果/年份 |
2004 |
2005 |
2006 |
草莓 |
|
|
|
野生樱桃 |
|
|
|
CrossTabs在jasperresports中从1.1.0版本时开始提供,同时iReport也从1.1.0开始支持CrossTabs。
Jasperreports的CrossTabs工具允许对行和列的数据进行分组、汇总和自定义每一个cell里的内容。填充CrossTab的数据可以来自主报表里的dataset或来自subDataset。使用iReport里提供的向导我们可以简单快速的创建功能强大的交叉报表组件。
一个CrossTabs本质上是一个表格,行和列的数量取决于填充这个表格的数据。行和列也可以在groups里做聚合操作。对于每一个行或列的group我们都可以得到一个细节信息和一个可选的行列数据的汇总。
16.1交叉表向导 (Crosstab wizard)
为了说明怎么让一个crosstab工作起来,我们将使用向导创建一个crosstab,当我们在工具条里选择crosstab元素并将其添加到报表中时crosstab的向导会自动启动。
还是以DoradoSample里提供的hsql数据里的employee报为例,我们使用包含下面查询语句的空报表开始:
Select * from employee
我们把crosstab放在报表的底部:summary band
图16.1
在第一步里我们需要选择一个dataset来填充crosstab,我们这里使用主报表里提供的dataset,点击下一步继续。
图16.2
在第二步里我们需要定义至少一个行分组.我们这里选择对所有记录使用DEPT_ID进行分组。这样就意味着crosstab的每一行将会采用一个明确的部门编号,这样JasperReports将会使用部门编号对数据集里的数据进行重新整理计算。使用向导,我们可以定义两个行分组,这是使用向导的局限性所在,事实上,如果你需要的话你可以通过Crosstab的属性设置窗口定义若干个行和列的分组。点击下一步继续。
和定义行分组一样,从这里我们可以定义两个列分组,这里我们仅使用一个列分组,使用数据中的DEGREE字段对数据进行分组。该字段的含义是学历,这就表示,我们要做的这个交叉报表是用来计算不同部门员工在学历方面的人数分布情况。
图16.4
是时候定义detail 数据了,一般的,这个detail是使用类似根据country,year得到orders总数或者是相同组合的物品总数的一个聚合函数的计算出来的结果值。我们这里选择打印员工的数量(Detail field:ordered,function:count)。点击下一步继续。
图16.5
最后一步我们可以为crosstab的布局设定一个布局。我们可以设置是否能看到表格线、或者是否包括行和列总数统计之类。我们这里全部选择。
点击finish
注意当一个crosstab添加到一个报表中后,会自动在设计窗口中添加一个用来编辑当前crosstab的tab页窗口。
图16.6
当点击crosstab的tab页,两个新的属性窗口将会被添加在窗口的左边和右边:一个crosstab的结构树,用来显示crosstab的当前选中单元格和帮助相关信息。一个是crossstab对象列表用来显示和该CrossTab相关的一些variables或fields等。
当点击工具条上的启动按钮后,我们将可以看到引擎生成的如下效果的报表:
图16.7
最后一列包含每一行交叉所有列的总计,最后一行包含每一列交叉所有行的总计。
16.2列,行,单元格 (Columns,rows,cells)
一个crosstab至少必须有一个行分组和一个列分组,每一个行和列的分组都有一个可选的行/列的统计。
下面图中所示的是一个基本的由一个行列分组构成的crosstab。
Crosstab header cell |
Column group1 header |
Column group 1 total header |
Row group 1 header |
detail |
Col group 1 total |
Row group 1 total header |
Row group1 total |
Row group 1 total/column group 1 total |
当再次添加一个行分组时,这个crosstab 将会显示出如下效果:
Crosstab header cell |
Column group1 header |
Column group 1 total header |
|
Row group 1 header |
Row group 2 header |
detail |
Col group 1 total |
Row group 2 total header |
Row group 2 total |
Row group 2 total/column group 1 total |
|
Row group 1 total header |
Row group1 total |
Row group 1 total/column group 1 total |
16.2.1行和列 (Rows and columns)
一个行或列的分组可能通过crosstab的属性窗口来对它进行修改(在crosstab编辑器右键菜单里选择Crosstab properties)。
图16.8
点击“row and column groups”的标签页。在这里我们可以看到已经定义好的行或列的分组。
图16.9
添加一个新的分组请点击名为Add的按钮。
图16.10
所有分组必须有一个唯一的名称。当你添加或修改一个行分组时,你可以设置rowgroup header的宽度。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Column group1 header |
Column group 1 total header |
Row group 1 header |
detail |
Col group 1 total |
Row group 1 total header |
Row group1 total |
Row group 1 total/column group 1 total |
“bucket”是分组的标准,它通过一个java类来定义。在一个bucket表达式里,你可以使用主报表里所有的fields/variables/parameters。但是,如果你选择使用subdataset来填充crosstab,那么必须使用subdataset里提供的fields/variables/parameters。
一个header的单元格增长依赖于它所跨越的行数。你可以选择多个元素放置在header里。
|
|
|
|
最后,你可以选择是否打印出总计的结果。这些选项是:
None : 没有总计行被打印
Start : 总计行打印在detail行之前
End : 总计行打印在detail行之后
创建column的group 是非常简单的。定义column group 时你可以定义column的高度来替代行高(看下图)
Column group height |
|
Column group1 header |
Column group 1 total header |
Row group 1 header |
detail |
Col group 1 total |
Row group 1 total header |
Row group1 total |
Row group 1 total/column group 1 total |
当Bucket在行分组里时,header的单元格内容的定位相似。但是在这个用例中, details可以改变header宽度而不是高度。
|
|
|
|
|
|
|
再一次,如果打印总计列的话,你可以做一些选择。各选项如下:
None : 没有总计列被打印
Start : 总计列在detail列之前打印
End : 总计列在detail列之后打印
列和行的高度可以很容易的在crosstab编辑器里通过鼠标拖曳表格线的方式改变。
图16.11
当一个行或列添加到crosstab里时,一个特殊的用来引用bucket表达式的变量将要被创建。它和新的group有相同的名称。你可以从crosstab objects 标签里通过查找绿色小点的方式来定位这个bucket variable。
图16.12
iReport为group创建新的header cells是很简单的,这个操作不需要添加任何新的额外元素到crosstab里。你可以根据你的喜好来填充cells,最好的方式是通过拖曳把bucket从crosstab objects列表拖到新的单元格里。
图16.13
图16.14
在上图中,你可以看到加在一个新加的嵌套在column group里四个新添加到crosstab里的单元格,group header单元格,group total header单元格。
你可以使用”up”和”down”按钮来更改你的group的嵌套顺序。
图16.15
下图中所示的crosstab就是在图16.14在SEX的group被向上移后的效果。
图16.16 MONTH group向上移后的效果
16.2.2单元格 (cells)
每一个行和列的交叉处定义一个单元格,我们有header单元格,total单元格,detail单元格和一个可选的“when-no-data”单元格。单元格可以包含一个类似于textfields,statictexts,rectangle,images之类元素的集合,但是他们不能包含一个SubReport, 一个chart,或者一个crosstab。
你可以去修改每一个单元格的背景色和单元格的borders:移动鼠标在一个单元格上并且按右键在弹出的菜单中选择“cellproperties”打开单元格属性编辑窗口。
从这个对话框中你可以修改单元格的外观。
图16.18
16.2.3特殊单元格 (Special cells)
如果一个crosstab不能包含一些数据,你可以选择打印别的东西来替代。例如,你可以包含一条消息,方法是,你必须编辑“when-no-data”单元格。在crosstab上右键勾选弹出菜单中的“when-no-data default cell”复选框。这个操作完成后将会出现一种很明显的编辑模式,你可以操作“when-no-data”单元格的内容。
图16.19 激活“when-no-data”单元格的编辑模式
“when-no-data”单元格和crosstab元素有相同的尺寸。如果没有数据展示的话它将替代crosstab打印。单元格橙色的边框标志出你可以编辑的单元格区域。可以在这个单元格里添加一个或多个元素。
在一个crosstab里,所有的元素关联一个单元格,如果一个元素在单元格外面或部分在单元格外面,这是不正确的放置方式并且当编译的时候jasperreports将会抛出异常。iReport在界面中标识这个错误会以红色的框显示。
16.2.4度量(Measures)
在crosstab里每一个元素的表达式(如textfield 表达式)可以包含唯一的measure。在这种情况下,你可以直接使用fields,variables或parameters。
一个measure和variable一样是一个对象。要建立一个measure,请打开crosstab属性窗口(在crosstab编辑器上右击,选择crosstabproperties)并且到measure标签页。
图16.20
点击Add按钮,创建一个新的measure。Measure的属性窗口将显示,你最少应该去设置它的name,class type和expression。在measure里你可以使用fields,variable和parameters
一个measure可以存储一个来自你代码中的实际的值(将calculation type设为nothing)或者一个类似于用count,sum等计算出来的值。
对于每一个measure 你可以提供一个自定义的incrementer类(一个继承自
net.sf.jasperreports.engine.fil.JRIncrementerFactory
的类)去实现特定的increment 方法。
图16.21 measure 属性窗口
这里的“percentage of”选项允许你选择表现变量最终值的百分比。
你可以提供一个特殊类来计算百分比的值,此时这个类必须实现net.sf.jasperreports.crosstabs.fill.JRPercentageCalculator接口。
16.2.5Crosstab element properties
在主设计窗口中双击crosstab元素将打开element properties窗口,点击crosstab标签。
图16.22 crosstab element properties
Repeat column headers : 如果勾选,当crosstab完全添加到页面中时列的header将会被重复打印。
Repeat row headers : 如果勾选,当crosstab完全添加到页面中时这个行headers将会被重复打印。
Column break offset : 当crosstab超过页面宽度时它指定上一块的数据与下一块之间的空白间隔。
图16.23 列被打断后
16.2.6交叉表参数 (Crosstab parameters)
你可以使用元素属性窗口里的crosstab parameter表格建立一个crosstab parameter并且设置一个crosstab的parameter同时为其设置一个默认的表达式(图16.22),要添加一个parameter,请点击Add按钮,这个crosstab parameter 窗口将会出现。
图16.24
对于一个parameter,你必须为其指定name,class type,同时你还可以为其指定一个可选的可以包含主报表中任意一个fields,variable,parameters的表达式。
警告:使用dataset的过滤查询,你必须用定义在crosstab properties窗口里的dataset 启动parameters,不能用crosstab里的parameters.
你可以在crosstab objects窗口里看到crosstab parameters的列表,他们用红色的点标记出来。
图16.25
你可以在启动时用一个MAP来设置crosstab parameters里声明的值。在这个用例中,你需要在element properties窗口里提供一个合法的parameter mapexpression。
16.2.7交叉表数据 (Crosstab data)
你可以用主报表或一个subdataset来填充一个crosstab。在后面的例子中,在crosstab properties窗口“crosstab data”标签里你必须指定要启动的dataset。
图16.26
如果你的数据是pre-sorted.你可以勾选“Data is presorted”的checkbox以使得填充数据的处理速度加快。
Reset type/group和increment type/group选项可以用来定义当集合类型的数据需要重置并且当添加一条记录到你的dataset。
关于怎么设置dataset的启动参数请参考subdataset的相关章节。
16.2.8交叉表合计变量 (crosstab total variables)
Crosstab variables 是内置的对象,可以结合数据在不同的聚合水平使用在crosstab textfield的表达式里。
图16.27
对于每一个尺寸,jasperreports创建variables根据每一行或列存储measure的合计值。
下面的例子是一个用来显示不同学历不同部门的员工数的报表.
图16.28
图16.29
常规问题解决方案
这章我们将处理一些我们在使用iReport和JasperReport过程中遇到的常见问题。他们是iReport论坛上常见的问题,但JasperReport官方文档也没有清楚的解决方案的。
打印百分比
经常需要在报表上显示一个字段的值和与这个值有关的百分比。考虑表16.1中的这几行。
|
|
|
香蕉 |
10 |
20% |
橘子 |
25 |
50% |
草莓 |
15 |
15% |
表格16.1
这个例子的百分比插入在C列,它表示B列中的值所占的百分数。用以下公式计算得出:
C = (ΣB*100)/ B (1)
ΣB =所有B列的值的和
尽管这个公式看起来很容易就算出了百分比,但公式(1)不适合在JasperReports中计算。这是因为公式使用的值是无效的在公式被使用时;具体来说ΣB是获得报表最后的值,就是当所有的记录被处理以后。然而,你要使用的B的值仅仅在计算(1)记录结果时。这儿没有简单的方案为这个问题。唯一的计算总数的方式就需要最终的百分比(先前例子中的ΣB )。当你预先计算你需要的值,你可以将它作为参数传递给报表。公式(1)就将变为:
newDouble(($P{TOTAL_OF_B}.doubleValue()*100)/$F{B}.doubleValue())
TOTAL_OF_B代表包含你计算的值的参数
计算组的发生数
每个组在JasperReports中和一个表达式关联。在报表生成期间,表达式的值一改变,一个新组开始发生一些事情。有时必须计算组的数量(计算组的值改变了多少次)。照这样做,需要一个变量:我们将命名为GRP_COUNT;基本思路就是仅仅当变量<group name>_COUNT 等于0时增加变量。<group name>_COUNT是一个JasperReports的内置变量,它包含当前组<group name>的记录数目。自一个任意组的变量<group name>_COUNT等于0仅仅一次,GRP_COUNT将正确包含组出现的次数。
图16.1
图16.1中的例子用到的查询:
“select *from customers order by country” 和COUNTRY组的表达式:$F{COUNTRY}.
声明变量GRP_COUNT :
Class: java.lang.Integer
Calculation type: Count
Reset type: Report
Variable expression: (($V{COUNTRY_COUNT}.intValue() == 0) ? "" : null)
这个表达式是说:如果你计算当前组的实例的第一条记录(记录号为0),然后返回一些非空的东西,也返回null值。自我们选择count作为计算类型,
变量GRP_COUNT将增加仅仅当表达式的值非空时,就说当当前组的第一条记录被计算时。
图16.2
显示这个值到textfield,你设置元素表达式的赋值时间到这个组来计算发生次数,在我们的例子中使用COUNTRY组(图16.3)。
图16.3
图16.4
图16.4可以看到打印结果。在空白框中显示了组号。
如果evaluationtime设置到“Report”, 组发生的总次数就将被打印出来。
分离detail
有时需要将detail分开成更多的bands。主要是为了在一些情形发生时在一个指定的detail band中用另一个来替代。这些情形必须用band PrintWhen Expression 测试过。可能有任意数量的detailbands创建新组,这些新组用一个组表达式,这个表达式在每条记录后改变值。你可以用来作为记录的关键字段表达式或一个计算变量。使用这种方式,此外在detail band中,你将有每条记录的group header和group footer,不能用同样的方式使用这个detail band。
图16.5可以看到报表的设计,detailband被隐藏到一对新组的header bands的剩余空间,这个使用一样的组表达式:这条记录关键字。
选择选项为第一组,我们能一页打印一条记录。
图16.5
插入一个页
JasperReports不提供任何方法来插入一个页和band合用。意思就是说你在一个页上呈现多个detail。下面的例子中将分detail在两页上:第一页我们想显示客户的名字的代码,第二页打印客户地址。
完成这个例子,我们将打印每条记录在一个新页上:这种方式是我们期望在一页上有一条记录在两页的内容。
让我们一步一步来,首先我们将创建一个组在一个空白报表上,我们指定组的表达式$V{REPORT_COUNT}和检查组标“Start on a new page”:我们用这种方式得到每条记录的在同一页上。现在我们去分开detail。接下来我们使用一个没有任何连接和datasource(我们设置子报表的连接属性为“Don’t use connection or datasource”)的子报表。准备创建这个子报表通过一个简单空白文档,且设置margins为0。
图16.6
也设置所有的bands的高为0(title band和summary band除外)。在我们用做子报表的报表属性选择选项“Title on a new page”和设置“When no data”值为AllSectionNoDetail 。
所有来自与主报表字段的值将作为参数传递;所以我们声明所有需要的参数。我们例子中需要四个字段:
- CUSTOMERID
- COMPANYNAME
- CITY
- REGION
那么放所有你需要的textfields到报表中。请注意所有插入到title band中的元素被打印在第一页,另外,放在summary band中的字段将在第二页被打印。返回到主报表,将字报表插入到detail band中。
我们填充子报表参数用正确的表达市在主报表中(更准确的说,我们填充子报表参数表在“Subreport(Other)”选项卡,查看图16.8)。
编译主报表和子报表并运行打印,如果一切ok,将看到类似图16.9的结果。
交叉报表
JasperReports不支持交叉报表,指报表的行和列都变化的报表。
以下表格是一个交叉报表的记录,显示了所有有效年代的生产记录:
|
|
|
|
|
900 |
950 |
1000 |
|
400 |
500 |
600 |
年代不可预言的,取决与取到的数据。
这种情形,最常用的方法为这种报表就是去固定一个列的最小号显示,手动填充一个datasource(例如JRJavaBeanArrayDataSource)来组织每行的值。这种方式我们很难想象到将出现的数据。
如果供应许多的列比你需要的(例如,报表能显示后5年的信息,但是你仅仅有前3前的信息),你的工作就是加一个假值做为字段值替代null或空白字符或短字符(-)。
使用多重连接找回数据
有时你需要重新找回更多的数据比在单独一个datasource,在同一时间。去达到这个,解决方案依赖你严密的想法。通常执行多个问题的方法就是使用子报表。此时你可以说点什么关于我们必须连接子报表,你能设置不同的表达式为每个子报表。你可以使用两个连接中的一个作为参数传递给报表。
如果不能分别找回数据通过不同的datasource用子报表,你得实现一个“lookup”方法,就像用一个静态类,或者添加它到报表脚本中。Lookup方法可以重新找回数据从任意的datasource。
以下的例子表现了一个简单的lookup类。用这个类去解码一个国家的名字给一个国家的代码。这个方法被传递一个已经打开的JDBC连接和代码作为参数去解码
Public class LookUp {
public static String (java.sql.Connectioncon, int code)
{
java.sql.Statement stmt = null;
java.sql.ResultSet rs = null;
try {
stmt = con.createStatement();
rs = stmt.executeQuery(
"select STATE_NAME from STATES wherecode=" + code );
if (rs.next())
{
return rs.getString(1);
}
return "#not found!";
} catch (Exception ex)
{
return "#error";
} finally {
if (rs != null)
try { rs.close(); }
catch (Exception ex2) {}
if (stmt != null)
try { stmt.close(); }
catch (Exception ex2) {}
}
}
}
调用这个方法,传递作为不同数据连接,你可以得到你想要的数据从不同的数据库。
如何使用存储过程
JasperReports不支持使用存储过程来找回数据去打印。为避免这个局限性,你可以在运行报表之前执行存储过程。
重新找回数据用存储过程能被插入在临时表格中,你可能执行一个查询,或者如果他们很少,你可以把他们作为参数传递给报表。在最后,这个临时表将被删除。如果你的存储过程可以返回一个ResultSet,你可能包含它在一个datasource用JRResultSetDataSource
iReport JasperReports深入讲解
JasperReports
iReport的核心就是一个开源的JasperReports库,它是由一个罗马的叫Teodor Danciu的开发者开发。是目前最有利于创建分布式和强有力的报表的免费软件库。这章我们就来阐述一下JasperReports的基础概念来加深我们对iReport工作流程的理解。
JasperReports API, 为报表定义的XML结构语法,以及在我们程序中需要用的库的详细资料都归档在这本名叫“TheJasperReports Ultimate Guide.”的手册中。这本书非常的超值。(目前标价35$).其他可以直接利用的信息和例子可以到官方网站: http://jasperreports.sourceforge.net.
两者不相同的是,iReport的分布式依照GPL规范,而JasperReports依照LGPL规范,因此它的局限性很小。这就意味着JasperReports能够被随意应用于商业,不用购买昂贵的软件许可或呆在家里从网上搜索复杂的开源的许可。这是用iReport创建一个被用做商品报表的基本原则,事实上,程序仅仅需要用JasperReports库来打印出报表来,仅仅在程序运行时用到它。由于没有完整的商业许可(指需求以外的许可),iReport只能作为一种开发工具,也不可能成为一个不符合GPL分布式标准的程序的一部分。
报表生命周期:
报表的生命周期和java类的生命周期非常的相似。Java被一些源文件来组成,也就是它可以依照它的语言规则进行自身的扩展,编写。这些源代码被编译器编译成扩展名为class的文件。可以通过接口来实例化或直接加载到内存中调用;执行期间这些属性将被加强。
同样的,一个报表也是由一个源代码的文件来描述,这个源文件就是由DTD(jasperreport.dtd,version0.6.3 is listed in Appendix B)来定义的XML标记。在0.5.3版本中它的源文件扩展名变成了.jrxml(例如:JasperReportsXML); 取代了一般的.xml扩展名。报表的源代码被编译成jasper文件(扩展名是.jasper)。jasper文件是一种预报表,严密的说就像是java的类被封状成的对象。Jasper文件通过你的应用程序来加载。它被添加一个数据源的标记从而创建报表,接着它就能以你想要的格式输出(例如:pdf或xls)。
因此它可以被定义成两种截然不同的动作:一个是用于执行在开发期间(设计和编写一个报表,编辑一个jasper源文件),另一个是用于执行在运行期间、
(加载开发期间的jasper文件生成报表)。
Jrxml源代码和jasper文件:
已经解释过,一个报表就由一个被创建的DTD文件定义的XML文件 (jasperreport.dtd)。这个源文件是由一系列的片段定义,这些片段就是一些关于报表的物理特性,像这个页面的尺寸,版面的布置,以及版块的高度等等;还有一些逻辑上的特性,像参数,变量,一个为得到被选择的数据的查询的定义等等
简单的说,这个jrxml源代码包含的片段就是下面这些:
Report main characteristics |
Property (0,+) |
Import (0,+) |
Global font (0,+) |
Parameters (0,+) |
SQL query (0,1) |
Fields (0,+) |
Variables (0,+) |
Groups (0,+) |
Group header |
Group header elements (0,+) |
Group footer |
Group footer elements (0,+) |
Predefined bands |
Predefined bands elements |
jrxml文件例子:
<?xml version="1.0"encoding="ISO-8859-1" ?>
<!-- Created with iReport - A designer forJasperReports -->
<!DOCTYPE jasperReport PUBLIC"//JasperReports//DTD Report Design//EN"
"http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">
<jasperReport
name="untitled_report_1"
columnCount="2"
printOrder="Vertical"
orientation="Portrait"
pageWidth="595"
pageHeight="842"
columnWidth="266"
columnSpacing="0"
leftMargin="30"
rightMargin="30"
topMargin="20"
bottomMargin="20"
whenNoDataType="NoPages"
isTitleNewPage="false"
isSummaryNewPage="false">
<property name="ireport.scriptlethandling"value="2" />
<queryString><![CDATA[select * fromcustomers]]></queryString>
<field name="CUSTOMERID"class="java.lang.String"/>
<field name="COMPANYNAME"class="java.lang.String"/>
<background>
<band height="0"isSplitAllowed="true" >
</band>
</background>
<title>
<band height="46"isSplitAllowed="true" >
<staticText>
<reportElement
mode="Opaque"
x="145"
y="6"
width="245"
height="34"
forecolor="#000000"
backcolor="#FFFFFF"
key="element-1"
stretchType="NoStretch"
positionType="FixRelativeToTop"
isPrintRepeatedValues="true"
isRemoveLineWhenBlank="false"
isPrintInFirstWholeBand="false"
isPrintWhenDetailOverflows="false"/>
<textElement textAlignment="Center"
verticalAlignment="Top"rotation="None" lineSpacing="Single">
<font fontName="Arial"
pdfFontName="Helvetica" size="24"isBold="false" isItalic="false"
isUnderline="false" isPdfEmbedded="false" pdfEncoding ="Cp1252"
isStrikeThrough="false" />
</textElement>
<text><![CDATA[This is thetitle]]></text>
</staticText>
</band>
</title>
<pageHeader>
<band height="0"isSplitAllowed="true" >
</band>
</pageHeader>
<columnHeader>
<band height="0"isSplitAllowed="true" >
</band>
</columnHeader>
<detail>
<band height="19"isSplitAllowed="true" >
<textField isStretchWithOverflow="false"
pattern="" isBlankWhenNull="false"evaluationTime="Now" hyperlinkType="None" >
<reportElement
mode="Opaque"
x="1"
y="1"
width="264"
height="18"
forecolor="#000000"
backcolor="#FFFFFF"
key="element-2"
stretchType="NoStretch"
positionType="FixRelativeToTop"
isPrintRepeatedValues="true"
isRemoveLineWhenBlank="false"
isPrintInFirstWholeBand="false"
isPrintWhenDetailOverflows="false"/>
<textElement textAlignment="Left"
verticalAlignment="Top"rotation="None" lineSpacing="Single">
<font fontName="Arial"
pdfFontName="Helvetica" size="10"isBold="false" isItalic="false"
isUnderline="false" isPdfEmbedded="false" pdfEncoding ="Cp1252"
isStrikeThrough="false" />
</textElement>
<textFieldExpression
class="java.lang.String"><![CDATA[$F{COMPANYNAME}]]></textFieldExpression>
</textField>
</band>
</detail>
<columnFooter>
<band height="0"isSplitAllowed="true" >
</band>
</columnFooter>
<pageFooter>
<band height="0"isSplitAllowed="true" >
</band>
</pageFooter>
<summary>
<band height="0" isSplitAllowed="true">
</band>
</summary>
</jasperReport>
清单3.1
图3.1展示了清单3.1打印出来的结果。其实清单3.1是iReport的加长型,它比我们需要的太长拉。这是因为iReport不能生成精短的代码(例:不能一些具有缺省值的属性)。
图3.1
不管如何减少XML代码,也无法改变报表的最终结果和生成速度。
在编辑(通过一些JasperReport类来实现)jrxml文件期间,这个xml文件被分解加载为JRBaseReport对象。JRBaseReport一个丰富的数据结构,可以将xml的内容精确的放到内存中。所有的解析表达式被加载,生成它相应java类文件。这些类继承JRCalculator,依靠普通java编译器编译成的这些类被加载为缓冲字节。开始初始化JRBaseReport,一个JasperReport类(继承JRBaseReport类)被实例化,先前的JRCalculator类缓冲字节被存储在新类的compileData区域。从而获得的JasperReport类连续的写进jasper文件,并随时准备被加载。
JasperReports的速度取决于实际情况,所有的报表规则被编辑到java的本地字节码中。报表的结构在编辑时被检验,而不是在运行时。
数据源和打印格式:
通过其他方式提供数据来完成打印是不可能的,这些最经久耐用,吸引人的报表是没有意义的。Without the possibility of filling a print through some dynamicallysupplied data,the most sophisticated and appealing report would be useless.
JasperReports 允许通过两种不同的方法来提供指定的数据来打印:通过参数和数据源,这主要依赖一个普通的接口JRDataSource.
图3.2
一整章的内容都是关于datasources,哪儿将解释它如何应用在iReport中和如何能定义一个符合常规的datasources。(为了能提供一个准确的JasperReports)。JRDataSource能读取一组被整理在表格中的记录体(行和列)。
JasperReports可能被报表用任何地方,来代替一个直接的datasources,一个JDBC(已经举过例子)能连接任何一个关系型数据库,对指定的一个报表执行sql查询。 如果数据(通过datasources)不足够,或者它需要指定特定的值完成执行,它将很有可能产生一些名值对传送给打印机。这些对被叫做parameters(参数),他们可以被预先性的传给报表。通过fillManager能够加入一个jasper文件和datasource在一个 JasperPrint 对象。 通过实现JRExporter接口的类这个对象能够创建一个真实的打印以你所期望的格式输出。
JasperReports 可以由你做主来选择不同格式的输出,用来创建pdf,xls,cvs,xml,html,等文件。通过JRViewer类能够直接打印你屏幕上所看到。
版本兼容性:
当一个新的版本的JasperReport被发布,通常一些类会有所改变。这些改进的类特意地定义报表的结构。所以为了避免在编译报表时因用了不同的库而产生的冲突,JasperReport使每个编译过的jasper文件具有联系性,可以精确的判别库版本并使用老版本进行编辑。如果你执行一个打印加载一个jasper文件,它不同于老版本支持的文件,就会产生一个错误。可能是这种情况:
java.io.InvalidClassException:
net.sf.jasperreports.engine.base.JRBaseReport; localclass
incompatible: stream classdesc serialVersionUID = 406,local class
serialVersionUID = 600
net.sf.jasperreports.engine.JRException: Error loadingobject from
InputStream
Caused by: java.io.InvalidClassException:
net.sf.jasperreports.engine.base.JRBaseReport;local class
incompatible: stream classdescserialVersionUID = 406, local class
serialVersionUID = 600
然而,老的报表源可能被编译用新版本的库,这个源代码被第一次编译:这是因为锌版本的通常仅仅传入新的标签但又不是必须的,并没有修改XML通常的结构。
移植一个JasperReports到下一个版本下完全可以的。它能够很快的被执行由于一个叫massive compiler 的iReport插件,它能够编辑所有在同一目录结构下的报表,能安全的拷贝已经现有的jasper文件。
我们将讨论massive compiler 在插件章节。
表达式:
所有的JasperReports的规则被定义通过表达式。一个表达式符合java语法,即有一个对象和结果。
表达式的例子:
• “This is an expression”
• new Boolean(true)
• new Integer(3)
• (($P{MyParam}.equals(“S”)) ? “Yes” : “No”)
无效的表达式例子:
• 3 + 2 * 5
• true
• (($P{MyParam} == 1) ? “Yes” : “No”)
详细的查看第一个和第二个例子都是无效的,因为他们都是简单类型(int 在第一个事例,boolean在第二个事例)。第三个表达式也无效的,因为采取MyParam参数(之后我们将定义为$P{...}格式) 是一个简单类型,它能被比较通过==和一个int型,但结果不是true。
表达式返回的类型是由上下文决定的。举个例子如果一个表达式恰好终止当一个元素被打印之后,这个返回类型将是boolean型。同样地,如果我写一个加了下划线的number型字段,返回类型就是Integer或Double。
在表达式中我提到了参数,变量和字段,报表定义的语法概要:
|
|
$F{name_field} |
指定字段名 (F means Field) |
$V{name_variable} |
指定变量名 |
$P{name_parameter} |
指定参数名 |
$P!{name_parameter} |
这是一种特殊的格式,是报表查询的一部分,这个参数肯定不会负一个值传递给预编译语句,但它是这个查询的一部分。 |
表3.2
字段,变量,参数永远作为一个对象(他们可以负null值),他们的类型在被声明时被指定。JasperReports0.6.2版本以后,出现了一个新类型$R{name_resource}结构。它被用做字符串的本地化。(我们将在国际化那章来讨论)
通常定义一个返回对象用一个表达式是不够的。例如:如果你想打印一个罗马字体的数字,或者用一个特别的数据代替周日,就可能要将详细的细节传给一个外部类方法,这个方法应该声明为staitic,例如:
MyFormatter.toRomanNumber($F{MyInteger}.intValue() )
toRomanNumber 是MyFormatter类的静态方法,带有唯一的int型参数并传回这个罗马版的数字in a lace。
很多地方都用到这个技巧,比如推断出一个CLOB区域的文本内容,或者添加一个值到HashMap参数中。这种操作就不能依靠简单的表达式。
一个简单的程序:
我们用一个简单的程序(清单3.2)来完成这章关于JasperReports提出的介绍。这段代码将展示如何由一个jasper文件生成一个pdf文件,这里用一个特殊的datasources JREmptyDataSource.JREmptyDataSource 是一种空的datasources。我们引用test.jasper文件(清单3.1)来进行编译。
import net.sf.jasperreports.engine.*;
importnet.sf.jasperreports.engine.export.*;
import java.util.*;
public class JasperTest
{
public static void main(String[] args)
{
String fileName ="/devel/examples/test.jasper";
String outFileName ="/devel/examples/test.pdf";
HashMap hm = new HashMap();
try
{
JasperPrint print =JasperFillManager.fillReport(
fileName,
hm,
new JREmptyDataSource());
JRExporter exporter = new
net.sf.jasperreports.engine.export.JRPdfExporter();
exporter.setParameter(
JRExporterParameter.OUTPUT_FILE_NAME,
outFileName);
exporter.setParameter(
JRExporterParameter.JASPER_PRINT,print);
exporter.exportReport();
System.out.println("Created file:" + outFileName);
}
catch (JRException e)
{
e.printStackTrace();
System.exit(1);
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
清单3.2
iReport报表结构完全掌握
这章我们将分析报表的构成,来观察一下它由那几部分构成,当用数据打印时这几部分是如何运转的。
Bands
一个报表依靠“type”页来定义说明。它被分成不同水平的一份被叫做bands。当报表加入数据去打印时,这些部分被印刷很多次依照他们自身的属性(依照报表创建者设计的规则)。举个例子,page header 被重复的打印在每页的开始部分,这样的话,每个band都会重复的打印每一单一的记录。
这个“type” 页被分成9个预先确定的bands作为新组被加进去。事实上,iReport控制每一个头条(Group header)和一个摘要条(Group footer)为每一个组。
图4.1
一个带总是和页的宽度一样(左右的空白除外)然而它的高度,即使已经被设计好,但可能还会依据被包含在内的元素的实际来打印;它能够自由的延长靠近页底。这种特色的出现在bands包含一个subreports或者text field时纵向的内容。通常情况下,bands的高度被用户指定一个“minimal height”。不是所有的bands能依照内容被这个外力改变,特别是:Column Footer,Page Footer 和 Last PageFooter.所有的band高度的总和(除了background)总是小于或等于页的top和bottome之间的最小高度。
Title
这是首先看到的band。它被创建仅仅一次,可能被打印在每一分开的页。耍点小聪明,你能利用这个模拟一个无效的subreports(随后我将看看如何做)。关于尺度的确认,它是不可能躲过去的,在报表页的高度设计期间。As regards the admitted dimensions, it is not possible to exceed,
during design time, the report page height (包含top和bottome标记之间)。如果title被打印在几张单独的页面上,这个band的高度不用被包括在整个band的高度之内的,一般低与page的高度。
Page header
这个band允许你设计一个page的header。它的高度在设计阶段被定义,通常不会改变在创建报表的过程中(除非有垂直插入相当大的成分,例如这个textfields包含很长的文本和subreports)。页面的header出现在整个打印页的相同位置在设计阶段期间。Title和Summary bands不包括page header 在打印一个单独的页时。
Column header
这个band在每一个详细的列开始时被打印。这column的概念一会儿再结实。通常的,包含标签的tabular报表的列的名字被插入在这里。
Group header
一个报表能容纳零个到多个group bands,它允许收藏详细的记录在不动groups。有group header ,自然要有group footer(他们能能独立的展现和取消)。不同的属性被联合在一个group。他们确定他们的行为功过查看 graphic point。它是可能的影响一个新的页的group header或者一个newcolumn,打印这个band在整个页的下面,如果这个bands超出了一个单独的页(以一个组的级别作为一个page header)。它 是可能的去修改被请求的高度并打印它:如果它是超过其他的高度,这个group将被打印在一个新的page(特别要注意它的值由于太长,在打印时会无限的循环),等等。接下来我们将详细讨论groups。
Detail
Detail band 将每个通过datasources读到记录响应的传给打印机。很可能,大多数的元素都被放在这里。
Group footer
这个band表示一个group的结束。通常它包含的区域显示小计或者分开图解元素,作为一条线,等等。
Column footer
这个band的出现表示每一个column的结束。它的尺寸是不能被调整的(即使它包含一个相当大的元素,像subreports或者文本域)。
Page footer
这是页脚。它和page header同时出现在每页。同column footer一样,他是不足够大的。
Last Page footer
如果你想使最后一页的footer与其他的页的footers不一样,这时可能就要用到这个band。如果这个band的高度是0,他将被完全的忽视,其他确定结构的普通页也能适用在最后一页。它首次出现在JasperReports的0.6.2版本。
Summary
在其他的地方这个组名被叫做report footer。它允许你在report的最后插入你想要的任何内容关于总结等。
Background
Band第一次出现在JasperReport0.4.6版本时。它由于许多用户的坚持不懈的要求能够创建水印和similareffects而引入 (整个页面的结构). 它可以具有最大的高度以至于和页面高度一样。
报表属性:
现在我们已经看过报表的单个部分,我们将继续创建一个新的报表。按菜单上的这个按钮选择New Document:打开一个窗口。在这里填写报表的属性(图4.2)。这个窗口可以随时打开通过view菜单的Report properties。
图4.2
报表的名字是第一个属性。这个名字是本地命名,它和源文件的名字是相互独立的,它仅仅被JasperReports library调用(例如:命名一个报表编译后的java文件)。
页面的尺寸大概是报表最重要的属性。一系列报表的尺寸标准被提议。iReport和 JasperReports使用的最小量度单位是像素。(像素大小是75点每英寸,每英寸的点数)。
然而,我们经常使用的报表的量度单位更为平常,像厘米,英寸或毫米。
表4.1列出了量度标准和像素大小。由于尺寸管理基于像素,所以当我们用不同的量度看同一数据会发生很大改动。
|
|
LETTER |
612 x 792 |
NOTE |
540 x 720 |
LEGAL |
612 x 1008 |
A0 |
2380 x 3368 |
A1 |
1684 x 2380 |
A2 |
1190 x 1684 |
A3 |
842 x 1190 |
A4 |
595 x 842 |
A5 |
421 x 595 |
A6 |
297 x 421 |
A7 |
210 x 297 |
A8 |
148 x 210 |
A9 |
105 x 148 |
A10 |
74 x 105 |
B0 |
2836 x 4008 |
B1 |
2004 x 2836 |
B2 |
1418 x 2004 |
B3 |
1002 x 1418 |
B4 |
709 x 1002 |
B5 |
501 x 709 |
ARCH_E |
2592 x 3456 |
ARCH_D |
1728 x 2592 |
ARCH_C |
1296 x 1728 |
ARCH_B |
864 x 1296 |
ARCH_A |
648 x 864 |
FLSA |
612 x 936 |
FLSE |
612 x 936 |
HALFLETTER |
396 x 612 |
_11X17 |
792 x 1224 |
LEDGER |
1224 x 792 |
表4.1
通过修改高度和宽度,你就可以创建任意大小的报表。报表页的定位有landscape和portrait选项,事实上这并没有太大的意义,因为报表页是由宽和高来刻画它的尺度的,并且每个单页都是相互独立。然而这个属性可以别用来确定报表的输出。
页面的空白尺寸依赖于Margin选项卡的四个输入值来确定。
列
像你看到的那样,一个报表页被几条平行线分开为几部分:bands。这个选项页是用来排版报表的,现在的这部分具有独立的数据(像title片段,或者page footers),和其他的片段一样被打印根据数据记录的不同从零开始(像groupheaders和detail)。这个选项页的最后一个属性值能分开垂直的列为了利用报表页中可利用的空间。
上下文中的column的概念很容易被”field”搞混。事实上,column和记录集是没有关系的,只和detail band有关系。意思就是说一条记录用十个fields和一个表的话,不需要十列。然而,这些元素可以用table实现恰当的放置。十列将导致一个很长的记录列(非常狭窄的横条)被打印。下面的例子将告诉你怎样设置值为一个简单的列报表在A4纸上。
图4.3
Columns的值是1,它的宽度和整个页面一样,除了空白。列之间的空间没有意义,所以它的值是0。
图4.4 图4.5
看4.5图,这个页的大部分没有被使用,如果使用大量的列,这个报表看起来会好看一些。图4.6展示了两列报表的尺寸大小。
图4.6
既然这样,在这个“columns“,我们输入2。iReport将自动的计算列的宽度依照页的空白和宽度。如果你想在两列之间插入空白,那就为”spacing”填写一个值。
像4.8图中看到的,这个页面的空白有被更好的利用。
滥用列的话可能将打印一个非常长列(像一个电话本一样)。总之,当detail band和连续的bands出现超过一列的宽度空白时你要记住使用列来减少宽度。所有的空白,列的宽度和每列之间的空白,加起来要小于页的宽度。如果不检验这种情形的话可能导致错误产生。
图4.7 图4.8
在图4.5和4.7中页面上有用区域设置报表的元素(像fields,images等等)。这部分是不可利用的,像空白和第一列余下的空白。Theparts which are not utilizable, such as margins and columns following the firstone (which have to be considered like the continuation of this one) arehighlighted in grey.
高级选项:
以上我们看到的仅仅是基础关于设计的基础设置。现在我们将看一些高级选项。其中一些将被彻底的检查和粉肠详细的解释在以下章节,如果要想完全的理解和应用,那就要在努力学习JasperReports的用法一直到精通。
脚本:
脚本是一个java类,它的方法执行在报表生成期间,通过触发一个特殊的事件,像一个新页的开始,一个group的结束等。我们常常可以看到那些生动的工具图片,像MS Access 或 MS Excel,脚本就相当于一个module,是一些程序和特殊的事件的关联或可返回的功能,在报表的上下文被插入。(例如text field的表达式)
将有一个章节全部用来讲解脚本。在scriptlet选项卡(图4.9),可以指定一个外部的脚本(java类)或激活iReport的内部脚本支持。
图4.9
如果你不想使用脚本,那就设置下拉菜单的值为:Don’t use scriptlet class…或者在输入区域填写你所要使用的类的名字。
更多…
在”more..”选项卡(图4.10)可以对打印进行设置。
图4.10
Title on a new page选项:
Title指定为一个新页的选项,打印在每页的开始,在title之后页面将发生大的变化。图4.12和4.13展示报表的结果,图4.11显示报表。
图4.11
Title被打印总是一样的,而且在每页的顶部。
图4.12显示使用缺省设置打印的结果:
图4.12
图4.13显示打印的结果如果“title on a new page “选项设置为true。Figure 4.13 shows the print result withthe “Title on anew page” option set to true.
像你看到那样,没有一行其他的band被打印在title页,甚至没有pageheader或page footer。然而这页仍然计算这页的总数。
图4.13
Summary on a new page选项:
这个选项完全和先前的选项一样,只是summary band被打印在最后一页。现在,如果你选择了这项,那新页将包含summaryband。
Floating column footer 选项:
这个选项允许你加强column footer band的打印,直接在最后detail band(或group footer)后显示而不不在column后显示。当你想用报表元素创建表格时使用这个选项。 (详细请看JasperReports tables.jrxml)
打印顺序:
Print order用来决定如何组织打印多列数据。缺省的print order一是vertical,它是垂直的打印记录直到页末开始打印新的一列。 (就像报纸或电话本一样) 。Horizontal print orderprints以横向打印记录当一行占据页宽后开始打印另一行。图4.14和4.15:
图4.14 图4.15
这两个图清晰的显示这个两个选项的概念。如你看到的,每个名字按字母的顺序打印。图4.14显示了纵向的打印(第一列打印完接着打印第二列),图4.15显示了横向的打印(打印完所有的行显示出整个列)
无数据打印(如果没有数据时):
当提供一个空的数据打印时(或者sql查询没有返回记录) 一个空文件被创建(或返回是一个零字节长度的流)。这个缺省的行为能被修改通过指定其他的,在没有数据时。(指when no data)。表4.2概述了可能的值和意义。
|
|
NoPages |
缺省值,最后的结果为空。 |
BlankPage |
返回一个空白页。 |
AllSectionsNoDetails |
返回整个页的组成,出了detail band |
表4.2
i18n:
il8n选项卡用来设置片段的参数。
Resource Bundle Base name
Resource Bundle basename 是一个参数名,当你想使报表国际化时。Resource Bundle包含用在报表中的标签,句子,表达式翻译文本以指定的语言。这个语言符合一个特殊的文件。base name
表示文件名,能帮助你找到这个文件用正确翻译。为了用精确的语言来重建文件名,一些language/country首位字母大写(e.g._it_IT,for Italian-Italy)和.properties扩展名作为前缀。我们将解释国际化在11章。
XML源文件的编码设置:
保存源文件的缺省编码格式是UTF-8. 然而,如果你想用一些你需要的XML编码格式,你就需要指定正确的charset(UTF-8)。
The UTF-8 manages all accented letters andthe euro.其他常用的可以选择编码格式列表(“ISO-8859-1” 广泛应用于欧洲).
iReport报表元素大全
这章我们将解释报表的主要对象和他们的特性。
这里的”element”就是一些图形对象,像一些文本或长方形。不同于字处理机那样,在iReport那段的概念中,表和分页符将不存在;任何东西被创建借助于elements,包括文字,当他们排成一行时就创建了表格,等等。这些相近的被大多数报表工具所采用。
“basic”元素中有7个由JasperReports提供:
- Line
- Rectangle(长方形)
- Ellipse
- Static text
- Text field (or simply Field)
- Image
- Subreport
通过这些元素的结合,能够创建任何一种报表。
除了这些之外,iReport还提供了两种特殊的基于象元的元素:chart(图表)和barcode(条形码)。
每种元素都有一些普通的属性,像高,宽,位置,band应该被放的位置和其他特殊的属性(例如:字体,在长方形的情况时,border的厚度)。它可能分为两个大的类别的组:图形元素(像:line,rectangle,ellipse,image)和文本区域(labels和textfield)。
子报表代表一种独立的元素,因为他使用起来很复杂,我也将接触他们在一个单独的章节。
这些元素被插入bands。特别是每一元素都不能合放在一个band中。如果这些元素不能被完整包含在band中,报表编译器将返回一个错误信息,关于元素的错误的姿态;不管怎么样,报表都将被编译,甚至是更糟糕的情况,但”out of band”将不能被打印出来。
选择并插入元素到报表中:
为了添加元素到报表中,选择(图5.1)工具条上目前显示的工具
表格5.1
取向工具被用来对这些元素做更重要操作和一些常用的工具。当你想插入一个元素时,点鼠标左键在你想插入元素的地方向下拖拽鼠标来画一个合适的长方形。当松开鼠标时,一个新的元素将被自动的选择和创建。这个新的元素也将在iReport面板的右边的元素浏览(elements browser)中出现。
图5.1
双击鼠标右键或者选择菜单View→Element Properties,it 能够打开元素的属性窗口(图5.2)。
图5.2
这个窗口是有组织的几个选项卡。This window is organized in severl tabs. The“Common” tab 选项卡包含了每一种元素的通用的属性,其他的选项卡是每一种元素单个的属性。
能够选种多个元素在同一时间功过取选工具和画一个长方形将你要选择的元素包含在内。被选择的区域会显示一个粉红色的长方形框。
或者,选中一个或多个元素在同一时间,通过按“Shift”键用鼠标点中你已经插入的元素。
选种一个元素时将在该元素长方形的每个角显示兰色的小方框(图5.4),当选择多个元素时该元素长方形的每个角显示灰色的小方框。(图5.5)
图5.3 图5.4 图5.5
多重选择中的第一个元素作为主要的选择。.
为了能够调整元素的大小,可以移动鼠标的光标到长方形的边上或拐角处:点并拖拽来安排你想要的尺寸。为了更小心的调整,可以在元素的属性框的特别选项卡中填写合适的尺寸。如果同时选择了多个元素,一个元素的调整会调整所有的元素。
此外,你也可以用放大报表,通过使用工具条上的zoom工具(图5.6):
图5.6
你可以在选择框中选择百分比(图5.6)或者直接写一个你想要的值(明确一下,字符后使用’%’号)。
警告:在调整元素期间,必须注意使用整数(像1x,2x,3x,等)来避免近似值的错误!
布置和元素顺序
一个元素可以通过鼠标来移动:通过点这个元素,选中后可以进行拖拽到任意你想要的位置。为了能够最大化的提高移动的准确度,你可以用方向键进行移动,一次移动一个像素。同样的操作,你可以完成通过按shift键,将引起这个元素十个像素的移动。
.即使移动时有一点阻碍,也可以破坏掉这个元素的阻碍,可以选择菜单Edit→Disable elements mouse move.
菜单可以View→Show grid查看不同元素的位置,通过格栅作为参考。也可以插入一个动作,通过菜单Edit→Snap去对起格线。
图5.7
随着越多元素组织进报表,可能就要用到几个工具,这些工具可以从这两个菜单format和contextual中找到,可以按右键查看选择插入元素。更多的官能性需要选择更多的元素。在这种情况下,基本元素被作为做作的参考。表5.2是对官能性的总结。
|
|
|
Align left(左对齐) |
校正基本元素的左边 |
√ |
Align right(右对齐) |
校正基本元素的右边 |
√ |
Align top |
校正基本元素的上边(或者上部分) |
√ |
Align bottom |
校正基本元素的底边 |
√ |
Align vertical axis |
校正被选中元素的水平中心 |
√ |
Align horizontal axis |
校正被选中元素的垂直中心 |
√ |
Align to band top |
设置最高值为0 |
|
Align to band bottom |
尽可能的放置元素在属于他的底边的band. |
|
Same width |
设置被选择元素的宽度为一样 |
√ |
Same width (max) |
设置被选择元素的宽度都为最大宽度 |
√ |
Same width (min) |
设置被选择元素的宽度的最窄值 |
√ |
Same height |
设置被选择的元素的高度等于基本元素的高度 |
√ |
Same height (max) |
设置被选元素的高度等于最高元素的高度 |
√ |
Same height (min) |
设置被选元素的高度等于最矮元素的高度 |
√ |
Same size |
设置被选元素规格为基本元素 |
√ |
Center horizontally(水平居中) (band based) |
设置被选元素水平居中 |
|
Center vertically(垂直居中) (band based) |
设置被选元素垂直置中 |
|
Center in band |
字段中间 |
|
Center in background |
整体置中 |
|
Join sides left |
被选元素以靠最左边元素为基准,所有元素的左边相连 |
√ |
Join sides right |
被选元素的以靠右边元素为基准,所有元素的右边相连 |
√ |
HS →Make equal |
使被选元素之间保持一样的距离 |
√ |
HS →Increase(增加) |
在所有元素中见插入5个像素的空白(向右移动) |
√ |
HS →Decrease(减少) |
在所有元素中间插入5个像素的空白(向左移动) |
√ |
HS →Remove |
删除水平方向的空白并向左移动元素 |
√ |
表格5.2
元素能够被互搭;也就是通过使用格式功能Bring to frontand Send to back使元素置前或置后。zorder被给通过整齐的元素插入到报表。这个排列能被看到在元素树,这些元素被查看在每一个band从最矮到最高的。
我们说过,一个元素已经被连接到所属的band。如果这个元素的一部分或全部超出band,它将会出现一个红色的高亮框架显示(仅仅为text元素),这个位置可能就是无效的。其他元素,这个错误位置被高亮显示在元素树或者被选择的元素上用一个红色的拐角。
图5.8
如果一个元素的部分遮掩了其他元素,这个拐角用绿色高亮显示;但如果一个元素的全部遮掩了其他元素,这个拐角用粉红色高亮显示。
图5.9
移动一个元素从一个band到另一个band,iReport可以自动改变所属的band。去指定不同的band,需要用属性窗口的第一个复选框(图5.9)。
如果两个或更多个元素被选择,那么属性窗口将只显示公共属性,如果这些属性值是不同的,将显示空值(使用的字段被显示空白)。具体的值为特殊属性,将适用于所有被选择的元素。
使用元素树管理元素:
元素树能够容易和精确地局部地选中报表元素。
图5.10
这里报表的外型是一个属性结构:主节是bands(使用一个文件夹表示),进到band里面是元素符号,名字和坐标能被看到,他们也被置于band中。
双击一个你选择的元素,将打开该对象的属性窗口。也可以通过鼠标右键属性菜单打开。再往后常用的功能就复制和粘贴,这儿有两个特殊的功能,move upand move down, 意思就是说可以修改一个元素在具体band中的z-border.
图5.11
如果选择了band的名字,可以右键属性进行对band 属性的操作。(图 5.11).
所有的band的特征将在第8章被解释。
基本属性:
所有的元素都有公共的属性在属性窗口“common”的选项卡 (图 5.2).主要关系到元素在页面上的位置:以下对不同属性的描写。
并列和同等规格的总是被确定为72个像素大小。
Band 指元素所属的band。所有的元素只属于一个band,一个band总联系着这个元素。元素的安放总是在band中。
Top 所属band的元素的上边到band顶部的距离
Left 从band左边到元素右上角的距离
Width 指元素的宽度s the element width;
Height指元素的高;它实际上的值是根据打印时真实值的高度来确定
表格5.3
Foreground 指文本被打印的颜色和元素的线和拐角被画的颜色。
Background 指元素背景填充色
Transparent 这个选项表示元素为透明的,透明的元素的部分应该被背景色填充。
警告:不是所有的输出格式都支持透明的。
RemoveLine When Blank This这个选项允许拿走垂直空间占有的对象,如果不太明显,这个元素option allows to take away the vertical space
occupied by an object, if this is notvisible; the element visibility is
determined by the value of the expressioncontained in thePrint
WhenExpression attribute; thinking about the page as agrid where
the elements are put, the line which theelement occupies, is that
where it is put;
表格5.4
表格5.3加亮元素的一条线;为了真正的删除这条线,所有的元素占有仅仅一部分线,有null值的地方 (没有被打印出来);
Printin first whole band 这个选项保证当元素值溢出时被打印在下一页或下一列;这个保证被使用当Print repeated values是不活跃时
Printwhen detail overflows 这个选项允许打印元素以页或列,如果band不能被打印当前的列或页
Printrepeated values this 这个选项决定时候打印元素,当该元素的值与前一条记录值一样时
Positiontype 在band被改变的情况下确定顶部的坐标。三个可能的值是:
- FixRelativeToTop 预先定义位置类型;这个坐标从来不改变的。
-Float 元素进一步的向底边增加他们的高度,依据前一个元素的高度
- FixRelativeToBottom 元素维持其到底边的距离的常量值;被用做单独记录的分割线。
Printwhen group changes 所有的报表的组被显示在这个下拉框中;如果他们中的一个被选择,仅当表达式改变组的时候被选择的一个将被打印,此时一个新的坏的组被选择。
Key 它是元素的名字,只有一个意义(iReport自动提出),被程序用来在运行时修改需要修改的文件的属性;
Stretchtype 这个属性用来定义详细打印期间元素的高度;可能值有以下几种::
- Nostretch 预先改变类型利用元素的高度保持一直。
-RelativeToBandHeight 元素成比例的增加使band增加,用来模仿表格的垂线。
-RelativeToTallestObject 这个选项修改一个元素的高度从而改变离它最近的元素:它也被用做element group,这是一个元素组机制,但不能被iReport管理。
Printwhen expression it is它是一个java表达式像那些描述在第三章,返回一个boolean对象;除了这些元素之外,这些表达式也被连接到band中。如果表达式返回true,这个元素是隐藏的。一个null值和一个新boolean(true)关联,将被无条件打印出来。
图形元素的画一个对象像一条线或一个长方形;他们通常不显示数据,但是他们却更多的被打印出来,从美学上看他们更有趣,通俗易懂。所有种的元素分享这个“Graphics element”选项卡在这个属性窗口:
图5.11
Pen 指你画线和框架的厚度;它可能的值是:
- None 厚度为null,表示禁止画线或边框
- Thin 线和边框的厚度最薄,但可以看的到。
- 1Point线和边框被设置为一个像素;
- 2Point线和边框被设置为两个像素;
- 4Point线和边框被设置为四个像素;
- Dotted线和边框被画用虚线;
Fill用来修改填充背景;仅仅被允许使用fill值,完全的填充
线
在JasperReports中线被定义为长方形,有对角线的长方形。
图5.12 图5.13
这个线被画用Foreground色和Pen厚度.
Linedirection it被表示成两条对角线,可能的值是: TopDown (看图 5.13) 和BottomUp.
矩形
长方形常用在一个元素周围的边框。这个边界用一个较粗的前景色线来画的。背景被背景色填充,如果这个元素没有被定义为透明的话。
长方形的特殊性在JasperReports中会有一个rounded comers。被定义的意思的是radius属性,描绘弯曲度在你画一个拐角时,使用像素。
图5.14 图5.15
椭圆
椭圆是唯一一个没有自己的属性的元素。至于长方形,它的边框也是用一个粗的颜色是前景色的线画的。背景被背景色填充如果这个元素没有被定义为transparent。椭圆被画在长方形内切边与长方形的四条边相切。
图5.16
图象
图象是最复杂的图形对象。可以使用raster images
(像GIF, PNG,JPEG, etc...)插入到报表中,但它也能被使用作为一个 canvas
对象,, 你可以画一种箱子:这个图象元素被使用,例如,画一个图表或一个条形码。
图5.17 图5.18
可以使用自己写的类使用net.sf.jasperreports.engine.JRRenderable接口。一个文本连接(“Hyper Link” tab)能够关联到一个图形元素。我们将分析文本连接在这章。
图象特征可以在“Image”选项卡设置.
ImageExpression 它是一个java表达式。它的结果是一个被Image
ExpressionClass属性定义的对象;
ExpressionClassattribute; 以返回类型为理由,图象被装载改变的方式;
ImageExpression Class 表达式的返回类型。
表格5.4概述了Image Expression Class可能采用和描述Image Expression结果的解释。
|
|
java.lang.String |
一个被认为是一个文件名的字符串;JasperReports将设法解释这个字符串想一个绝对的路径;如果没发现文件,它将设法加载指定名字的源从classpath 正确的表达式是: “c:\\devel\\ireport\\myImage.jpg” “it/businesslogic/ireport/icons/logo.gif” |
java.io.File |
指定一个文件对象作为图象去加载。 正确的表达式可能是: new java.io.File(“c:\\myImage.jpg”) |
java.net.URL |
指定It specifies the java.net.URL 对象。当你以html格式输出报表时使用它。 正确的表达式可能是: New java.net.URL(“http://127.0.0.1/test.jpg”) |
java.io.InputStream |
指定一个准备读取的java.io.InputStream对象;既然这样我们就不能考虑图象存在或它在一个文件中:大多数我们读取一图象从数据库,返回一个inputStream。 正确的表达式可能是: MyUtil.getInputStream(${MyField}) |
java.awt.Image |
指定一个java.awt.Image对象;当一个图象对象被创建时大概返回一个简单的对象; 正确的表达式可能是: MyUtil.createChart() |
JRRenderable |
指定一个使用 net.sf.jasperreports.engine.JRRenderable接口的对象。 |
表格5.5
在这个例子中我们有解释, MyUtil 代表一个创造类。如果你想使用一个创造类通过调用一个static 方法去运行特殊的细节,就需要使用一个属于它的包(例如
it.businesslogic.ireport.util.MyUtil)或者用import(菜单Show→Import directives in the report)引用这个包。我们解释这个方法在这个例子中是static的,但当我们讨论变量时,我们将看到如何实例化一个类在打印开始时和如何使用它在表达式中。
在ImageExpression 中使用字段,变量和参数,它将加载或生成图象以变化的方式(像已经发生的,例如,在detail中生成一个有图象的目录,每个目录关联一个图象)
ScaleImage 定义图象怎样适应元素的尺度;可能的值有三个:
- Clip图象的尺寸不改变;
- FillFrame图象适合元素的尺寸(变的不成型)
- RetainShape图象适合元素的尺寸,但保持图象原来的比例
图5.19 图5.20 图5.21
Usingcache this如果这个元素最近将被再打印,可以使用这个选项使图象保存在内存中以便下次使用;图象只有被Image Expression Class 设置java.lang.String 才能使用cache;
Verticalalignment 这个属性用来定义图象为垂直队列依照元素区域;可能的值是:
- Top 图象排列在顶部;
- Middle图象被放在垂直队列的中间在元素区域中。
- Bottom图象被排列在底部;
Horizontalalignment 依照元素区域,图象被定义到水平队列;可能的值是:
- Left图象排列在左边;
- Center依照元素区域,图象排列在水平中间
- Right图象排列在右边;
Evaluationtime 定义Image Expression被处理时的状态;事实上表达式的赋值能被做当报表引擎在创建报表时遭遇这个元素或或者也能延缓在一些特殊的案例中:例如,你想去计算一个子报表。
赋值时间是一个非常有用的功能,它将被解释在JasperReport手册中。可能的值:
- Now立即求表达式的值;
- Report报表产生之后求表达式的值;
- Page页未求表达式的值 ;
- Column列末求表达式的值;
- Group求每组的值;
Evaluationgroup 同Evaluationtime.
图形元素(和text元素)可以被想象成一个框架,或者可以定义它的四个边的值。
它是元素元素和内容之间的空间。边框和内容被定义在border选项卡。他们的属性被介绍在JasperReports0.6.3版本。
图5.22
可以选择元素的类型和画每条边的颜色。边框类型是:
- None,厚度为null,允许不打印出边框线;
- Thin最小厚度;
- 1Point一个像素的厚度;
- 2Point2个像素的厚度;
- 4Point4个像素的厚度;
- Dotted最小厚度的虚线;
一个简单查看图形效果的方式就选择border选项卡中间的显现边框。
文本元素
和图形元素一样,文本元素也有一个允许查看的公共属性:它是font选项卡(图5.24)
图5.23
“font” 选项卡是用来设置元素中文本的属性,所以不仅仅是字体(字符的类型和尺寸),还有文本的队列,可能的rotation和线空间。
Reportfont 是一个边框形式字体的名字。从这里可以设置所有字符的属性;边框形式字体可以定义报表的标准和管理他们通过选择菜单:View→Report fonts;
Linespacing行间距,可能的值是:
- Single单行写如;(预先确定值predefined value);
- 1_1_2间隔一行半写入;
- Double双倍写入;
Horizontalalign依照元素使文本水平排列;
Verticalalign依照元素使文本垂直排列;
Rotation允许指定文本如何去打印,可能的值是:
- None文本将正常的打印从左到右,从上到下;
- Leftthe 文本逆时针旋转90度,它被打印从底到顶,水平和垂直队列依照文本;始针4
ionports0.6.3banbe the 旋转(例如,文本开始打印将沿这底边垂直队列画顶的界限开始);
- Rightthe 文本顺时针旋转90度从顶到底,垂直和水平队列依照文本旋转;
图5.24
其他的字符的字体设置将在第六章详细解释。
文本元素的属性可以用文本工具(图5.25)条来进行修改。
图5.25
静态文本
statictext被用来展示非动态文本的报表。 仅仅一个参数用来区别这个元素从一个普通文本元素在statictext选项卡中,指定你要看到的文本:它是一个标准的字符串,不是表达式,也不需要依照java语言的规范。
图5.26 图5.27
文本域
文本区域可以打印一个java表达式的值。简单例子就是打印一个字符串(java.lang.String)来自于一个表达式想这个:“Hello World!”
既然这样,静态文本创建就需要很小的工作量,因为这个例子中字符串是一个不变的值;其实用java表达式去定义文本区域允许包含非常高的控制超长文本。不直接的联系文本元素(像发生在不同报表工具文本元素隐含的数据库字段的值):不同字段的记录值,是可利用的通过datasource,存储在一个名字叫fields的对象中,他们被访问依靠表达式的语法在第三章。
和图象一样,一个超文本连接可以关联textfields,可以在HyperLink中定义
图5.28 图5.29
Textfield Expression Class it指定域表达式的返回类型;可能的值有许多,包括所有的由sql类型组成和一些管理数据的类的java对象,以下表格列出了所有可选的类型的。
|
java.lang.Object |
java.lang.Boolean |
java.lang.Byte |
java.util.Date |
java.sql.Timestamp |
java.sql.Time |
java.lang.Double |
java.lang.Float |
java.lang.Integer |
java.io.InputStream |
java.lang.Long |
java.lang.Short |
java.math.BigDecimal |
java.lang.String |
表格5.6
列表中包含的 java.lang.Object 类型能够在没有其他类型可以联合数据使用。
Evaluationtime 指定报表创建Textfield在那个阶段赋值;
Evluationgroup 是否赋值在一个组后
Stretchwith overflow当它被选择时,这个选项可以垂直的改变内容,如果元素不能充分的包含在文本线内的话;
Blankwhen null当域表达式返回一个null值时允许打印空白;
Pattern 指定字符串可以使用Format类,指定用Textfield Expression Class是正确的。
JasperReports能格式化日期和数字;下面的表格概述中的一些例子包括字母和他们的意义可以快速的创建日期和数字。
|
|
|
G |
Era designator |
AD |
y |
Year |
1996; 96 |
M |
Month in year |
July; Jul; 07 |
w |
Week in year |
27 |
W |
Week in month |
2 |
D |
Day in year |
189 |
d |
Day in month |
10 |
F |
Day of week in month |
2 |
E |
Day in week |
Tuesday; Tue |
a |
Am/pm marker |
PM |
H |
Hour in day (0-23) |
0 |
k |
Hour in day (1-24) |
24 |
K |
Hour in am/pm (0-11) |
0 |
h |
Hour in am/pm (1-12) |
12 |
m |
Minute in hour |
30 |
s |
Second in minute |
55 |
S |
Millisecond |
978 |
z |
Time zone |
Pacific Standard Time; PST; GMT-08:00 |
Z |
Time zone |
-0800 |
表格5.7
这儿是一些dates和timestamp的格式例子:
|
|
"yyyy.MM.dd G 'at' HH:mm:ss z" |
2001.07.04 AD at 12:08:56 PDT |
"EEE, MMM d, ''yy" |
Wed, Jul 4, '01 |
"h:mm a" |
12:08 PM |
"hh 'o''clock' a, zzzz" |
12 o'clock PM, Pacific Daylight Time |
"K:mm a, z" |
0:08 PM, PDT |
"yyyyy.MMMMM.dd GGG hh:mm aaa" |
02001.July.04 AD 12:08 PM |
"EEE, d MMM yyyy HH:mm:ss Z" |
Wed, 4 Jul 2001 12:08:56 -0700 |
"yyMMddHHmmssZ" |
010704120856-0700 |
表格:5.8
|
|
|
|
0 |
Number |
Yes |
阿拉伯数字 |
# |
Number |
Yes |
阿拉伯数字, 0作为缺省的 |
. |
Number |
Yes |
十进制或货币分割付 |
- |
Number |
Yes |
负号 |
, |
Number |
Yes |
分组号 |
E |
Number |
Yes |
科学符号中为单独是尾数和说明Separates mantissa and exponent in scientific notation.不需要引用像素或后缀Need not be quoted in prefix or suffix. |
; |
Subpattern boundary |
Yes |
分割正负样式Separates positive and negative subpatterns |
% |
Prefix or suffix |
Yes |
乘以100使用百分号 |
\u2030 |
Prefix or suffix |
Yes |
乘以1000使用每一千 |
¤ (\u00A4) |
Prefix or suffix |
No |
Currency sign, replaced by currency symbol. If doubled, replaced by international currency symbol. If present in a pattern, the monetary decimal separator is used instead of the decimal separator.
|
' |
Prefix or suffix |
No |
引用特殊字符Used to quote special characters in a prefix or suffix, for example, "'#'#" formats 123 to "#123". To create a single quote itself, use two in a row: "# o''clock". |
表格5.9
这是一些数字格式的例子:
|
|
"#,##0.00" |
1.234,56 |
"#,##0.00;(#,##0.00)" |
1.234,56 (-1.234.56) |
表格5.8
图5.30
通过“create”按钮可以打开样式编辑,意思就是数字,日期,流通等的简单格式
TextfieldExpression 是一个打印表达式,返回在Textfield Expression Class;中设置的类型
可以转变StaticText在Textfield通过选择和按F3键。
为了能快速的改变一个或更多个普通文本元素的表达式可以选择他们和按F2键。
子报表
子报表是包含在其他报表中的一个元素,由一个jasper文件和在子报表的属性中被指定的datasource提供数据开始创建。
以下是关于子报表特征的一些简要插图。由于这个子栏目的复杂性,我们将在另一章详细解释。
图5.31
图5.32 图5.33
ParametersMap Expression定义一个运行时赋值的表达式;这个表达式必须返回java.util.Map;这个map中包含一些名值对,这些名值对将被传递给子报表作为参数值;
Connection/Datasourceexpression定义一个返回JDBC连接或JRDataSource用来填充子报表;
Usingcache保存或不保存数据到内存,以便能快速的加载数据再下一次;
Subreportexpression 定义一个在运行时返回Subreport expression class对象的表达式。依照返回类型,表达式被赋值为了恢复用来生成子报表的jasper对象;
Subreportparameters this这个表可以定义一些使用适当的表达式动态提供的名值对给子报表;
专用元素
除了JasperReports提供的原始的元素外, iReport提供两个”合成”元素为他们的普通属性和补偿使用图形元素。
图表
所有关于图表的信息查看14章。
条形码
这个元素可以创建一个动态的条形码形式的值。
图5.34 图5.35
指定打印条形码的类型。
可能的值列表在表格5.9
|
2of7 |
3of9 |
Bookland |
Codabar |
Code128 |
Code128A |
Code128B |
Code128C |
Code39 |
EAN128 |
EAN13 |
GlobalTradeItemNumber |
Int2of5 |
Int2of5 |
Monarch |
NW7 |
PDF417 |
SCC14ShippingCode |
ShipmentIdentificationNumber |
SSCC18 |
Std2of5 |
Std2of5 |
UCC128 |
UPCA |
USD3 |
USD4 |
USPS |
表格5.9
Checksumit specifies the code控制条形码是否被打印指定的代码;这个特征仅仅被条形码的一些类型提供;
Showtext指定是否打印文本 ;
BarcodeExpression 指定以来于条形码的表达式的值;总是返回string类型的值;
Evaluationtime eEvaluationgroup 和图形元素的意思一样;
超连接
图形和文本域元素都能被用做一个anchor(锚)在文档中,作为超连接指向源或其他本地的anchor(锚)。锚是一种特殊的“标签”用来识别文档中特殊的位置。
超连接和锚可以通过Hyper Link(图5.35)选项卡来定义。这是分开的两部分。上部分是一个文本域,这里可以指定这个锚的名字。这个名字可以被其他的连接引用。
下部分是定义连接的源或文档中的位置。
JasperReports 可以创建五个类型的超连接: Reference,
LocalAnchor, LocalPage, RemoteAnchor andRemotePage.通过Hyperlinktarget it 可以指定打开一个连接在当前的窗口(预先设定,目标是self(本身))或一个新的窗口(Blanktarget)。
警告:不是所有的输出格式支持超连接。
图5.37
Reference
The Reference 连接指出一个外部的源,一个可以被通过点URL识别的源,例如一个服务器去管理向下的记录功能。这表达式仅仅需要Hypelink Reference Expression.
LocalAnchor
点这个本地锚意思就是创建一个连接在同一文档之间。它可以被使用,例如通过一个标题的连接可以找到相应的章节。
定义一个本地锚去要指定一个能生成有效名字的Hyperlink Anchor Expression
LocalPage
如果指示代替锚,你想点一个详细的当前报表页,就需要创建一个LocalPage连接。既然这样就需要指定这个指示页的号码,意味着使用HyperLink PageExpression(这个表达式返回一个Integer对象)。
RemoteAnchor
如果你想点一个外部的锚的细节,你就要使用RemoteAnchor 连接。既然这样你就要指定在Hyperlink ReferenceExpression域和指定Hyperlink Anchor Expression来命名锚
RemotePage
这个连接可以点进一个文档外部的详细页面。既然这样,这个外部文件的URL点就指定Hyperlink Reference Expression域和这页的号码将指定HyperLink Page Expression。
iReport中字体编码说明
Fonts是描述文本的特征 (形状和尺寸)。在JasperReports中可能指定每个元素的字体属性。而且它可以定义一个名叫“report font” 的球形字,并联合他们到文本元素。这个球形字体将被包含在元素中使用。
字体
通常一个字体被定义有四个特征:
- 字体名字(字体家族)(font family)
- 字体尺寸
- 属性(黑体,斜体,带下划线,barred)如果以PDF输出报表,JasperReports需要一些附加的信息:
PDFFont Name 这是预先确定的PDF文档字体的名字;
PDFEmbedded 这是指定一个字体的标记,像“external TTF”类型,
应该被包含或不包含在PDF文件。.
PDFEncoding 这是一个字符串,用来指定字符编码的名字。
如果不输出PDF格式的报表,字体使用指定的font name,强化的部分可以指定它的属性。在这种情况下的PDF文档,识别使用的字体和它的属性(黑体,斜体,等)。
其他属性是可以被忽视的,因为他们已经被包含在PDF字体中。
扩展字体
可能要使用扩展的TTF(TrueType font)。为了能够使用,就必须将扩展字体(扩展名为.ttf的文件)加到CLASSPATH中:这是需要的在设计(使用iReport时)和生成(通过一个java程序,swing或servlet生成报表时)时。
警告:需要避免添加数以百计TTF到CLASSPATH中,因为可能这可能使iReport启动向下运行变的缓慢。你可以添加一个%WINDIR%\fonts目录在CLASSPATH中。
图6.1
In the 在“Fontname”选择框中仅仅是系统字体,通过java虚拟机来管理,通过操作系统来展示他们。意思就是说如果你想使用扩展的TTF字体在非PDF报表中,你就需要去安装它到系统中。
安装后,在PDF Font Name选择框中选择 “External TTF Font...”。
选择框中的“True Type font”将被激活。它将在classpath中查找所有的True Type fonts引用它。
为了能在输出的PDF中正确的显示字体,需要选择“PDF Embedded”。
编码
字符编码是JasperReports中最模糊的问题之一;这个问题可能发生在打印PDF格式的报表时。所以选择一个正确编码格式是非常重要的。
编码如何指定的说明:The encoding specifies how thecharacters have to be interpreted:在意大利,例如,如果你想打印合适的重音(像è, ò, a, ù,等),就需要使用编码(西方,欧洲一个ANSI标准Western European ANSI aka WinAnsi)。然而一些JVM版本不支持编码(1.4版本以前的),但他们可以使用编码(唯一不同的是小写的”p”)。
iReport 富含预先设置的编码类型在选择框去选择。
如果你在一些不标准的PDF格式报表中有一些问题,确认所有的字段的编码类型是否一致,核实从数据库读取的报表的数据的编码设置。
使用Unicode字符
可以使用Unicode写不标准的字符(像希腊,西里尔和亚洲字符);Unicode编码可以被指定在表达式中,用来识别这些文本。例如,如果你想打印 euro符号,可以使用Unicode \u20ac字符来避免乱码。
注意:表达式\u20ac不是简单字符串,它是识别包含?字符的java表达式。如果写一个静态文本到文本元素中,\u20ac就能打印出来,因为它是静态文本,所以不被作为java表达式类解释(仅仅适合在textfield中)。
报表字体
可以选择菜单”View”中”Reportfonts” 定义球形字体。会打开一个管理球形字体的窗口。一个新的图解可以查看图6.1。
从”Report font”选择框中选择使用球形字体在文本域中(图5.23)。
iReport不做管理使用最理想方式的“report font”。限制自身选择报表字体的属性值到文本元素中和复制所有的球形字体到文本元素中。事实上,球形字体天生就是为节约XML源为目标的,来避免为每一个单独的域指定字体。因为这些工作都可以被iReport自动的完成,最优化的重要性并不大。然而,因为这个企图集中报表字体的管理被迫停滞,因为,如果提出,JasperReports用属性来指定元素的标准,他们总是被指定被。 更简单的,如果一个球形字体报表被使用在文本元素,它的特征被保存在文本元素,本质上还是球形字体报表。
显然一会儿工夫不可能设置超过一个报表的字体。
iReport字段,参数和变量精解
报表中有三个组的对象可以存储值:字段,参数和变量。这些对象被使用在表达式中,他们能改变他们的在打印行期间值和他们的类型,所有他们都有一个符合java类的类型,像string或double。字段,参数和变量被提出在报表中。选择主菜单”view”,我们能够发现“Report fields” (这就是字段), “Reportvariables” and “ReportParameters”这些子菜单.这三个子菜单中的每一个都允许我们管理所有他们的对象(图7.1)
图7.1
通过这个窗口我们可以声明,修改和删除字段,变量和参数。
字段
一个打印一般从数据源开始被创建:数据源在JasperReports 总是被组织成一组记录,这些记录被排列通过一系列正确字段像一个sql查询的结果集。
在图7.1的窗口中,”Fields”选项显示了需要打印的字段。为了能够显示这些字段,可以按”new”按钮,从而打开一个新的窗口(图7.2)
图7.2
字段被定义通过名字,类型和一个特需的描述。你不可能任意选择一个字段的类型。如果这个字段类型不在预选的类型中,就可能断言这个字段作为java.lang.Object和投射他到一个必须的类型在字段被使用的表达式地方。在表达式中你可以查看一个字段通过使用语法:
<field name>
所以你可以处理MyPerson字段作为it.businesslogic.Person对象:
((it.businesslogic.Person)$F{MyPerson})
这些字段在报表中不可能知道它的高度(也就是延伸到达数百)。为这个原因,iReport可以使用不同的工具通过精确的数据源型声明字段。
SQL查询的字段注册
这个最广泛使用工具可以断言或记录一个sql查询的字段。首先需要做的是打开ReportQueryDialog(按按钮).
查询解说的窗口将打开。它将用来填充报表(如果这个报表的创建来自于一个sql查询)
图7.3
之后要使DBMS连接起作用,就要插入一条查询语句(跳到15页查看如何做),例如:
select * from customers
iReport将运行这个sql查询,分析结果以便你去选择想要显示的字段名称。通过选择字段,他们将被注册值(图7.4)。
图7.4
注意:注册字段,就需要选择他们从这个列表中;如果查询包含一些错误,取消“AutomaticallyRetrive Fields”选择框,并按“Read fields”按钮读字段。
既然这样所有的字段将被变为String类型:一般的类型设置基于最初的sql类型,能够被String ,Integer等匹配。
JavaBean的字段注册
JasperReports中最高级的特征之一是管理datasources的可能性,不基于简单的sql查询。这是一个javabean收集的事例,记录集的概念被java对象替代。在这个用例中”fields”是对象的属性。通过选择JavaBean Datasource选项,可以注册被读取的字段,这些字段被java对象指定,这个对象是:
it.businesslogic.ireport.examples.beans.AddressBean
图7.5
按钮之后可以指定这个类的名字,这个属性被萃取和引用作为字段。
JRExtendedBeanDataSource的字段注册
从javabean收集中创建一个打印,就需要用一个名叫JRBeanCollectionDataSource的datasources(JasperReports装载的)。
iReport提供一个扩展的datasource版本,可以用这个方法来重新声明断言作为一个字段值:
person.getAddress().getStreet()
我们讨论了JRExtendedBeanDataSource。之后我们将了解一下datasource精确的方法,在“JavaBean Ext Datasource”选项卡有一个类似的工具查看JavaBean的反省(introspectionof a JavaBean)。这个工具不能返回一个清晰的列表来探究javabean,但可以通过一个树型结构可以更深的探究,简单属性(想strings和numbers)可以通过树叶显示,其他更多复杂的类型(其他bean)可以进一步的了解到。
这种方式可以到达bean的细节,在类似的java包中。
图7.6
为了添加一个字段到列表中,就需要选择树的接点和按“Add field(s)”按钮
字段和文本域
在文本元素中打印一个字段,需要设置正确表达式和textfield类型,如果需要的话,还可以为字段的格式定义恰当的模式。
可以自动的设置表达式通过从字段列表中拖拽字段到相应的band (drag ‘n’ drop feature).
参数
参数是程序用来传递给报表的一个值,创建打印时,他们能被用指导运行阶段行为和(作为应用程序在sql查询中的条件),提供额外的数据去打印,像一个图形对象包含一个字符或字符串在报表标题中。
和字段一样,参数也有类型,要在设计时提出来。这是参数类型能被选择的。
图7.8
此时这个属性“is for prompting”不被ireport使用,它和打印是无关的:它代表是一种传入机制,jasperReports允许应用程序识别用户立即使用的参数值。
我们在表达式中提及到的参数的语法:
<parameter name>
如果应用程序不直接传给报表一个参数值的话,它可以设置一个默认的值。想想由于参数是一个java对象,所以它不可能用表达式像这样的
0.123 (Wrong expression)
一个double类型的参数值,但是可以先声明一个double对象像这样:
new Double(0.123) (Right expression)
在查询中使用参数
我们有说过,可以用参数在sql查询中。假如你想打印一些信息,关于通过客户ID(在设计时并不知道)得到详细信息。我们的查询就要变一下:
select * from customers
where CUSTOMERID =
哪儿的MyCustomerId是一个Integer类型的参数。JasperReports 将传入这个查询:
select * from customers where CUSTOMERID =
它将运行这个sql用一个预编译语句通过传递MyCustomerId的值作为查询参数。如果你想避免这种参数管理,可以用特殊的语法:
<parameter name>
that 它允许我们在查询中用它的值取代它的名字。例如我们有一个名叫MyWhere的参数,它的值是“where CUSTOMERID = 5”,一个查询像这样:
select * from customers
在完成期间被传入:
select * from customers where CUSTOMERID =5
使用程序传递参数
参数被程序指令传递给打印机通过一个类,它继承java.util.Map接口。
考虑到的代码列表在27页,以下是一部分:
...
HashMap hm = new HashMap();
...
JasperPrint print =JasperFillManager.fillReport(
fileName,
hm,
new JREmptyDataSource());
...
fillReport表示所有JasperReports库中的一个键的方法,它可以创建以一个jasper文件名为参数的打印,一个datasource (一个假的datasource, JREmptyDataSource) 和一个参数map,它在这个例子中是空的,用java.util.HashMap对象表示的参数。
用这个参数包含在报表的标题中 (图 7.10 and 7.11), 我们继续这种方式:
1.首先声明这个名为NAME_REPORT,类型为java.lang.String的参数;
图7.9
2.添加一个textfield元素的标题band用这个表达式:$P{NAME _REPORT}
3. 修改程序代码:
HashMap hm = new HashMap();
...
JasperPrint print =JasperFillManager.fillReport(
fileName,
hm,
new JREmptyDataSource());
我们放这个参数map中的一个值为NAME_REPORT参数。.
图7.10 图7.11
不强制通过程序传递一个值为所有的参数在报表中声明。如果程序不明确设置一个参数值,JasperReports将用Default Value Expression考虑预先设置的参数值,empty表达式和null的意思一样。事实上,这个例子并不是很有意思的,因为这些数据类型是一些简单的string,然而可能也会提供给报表通过map,一些更复杂的对象,像图象(java.awt.Image)或者一个可用的datasource提供一个详细子报表的情况。此外,提供一个和声明的参数一样类型的对象也是很重要的,否则将会抛出一个ClassCastException异常
内置参数
JasperReports提供了一些内置的参数(报表引擎内在的),这些参数是易读的,但是不可能被用户修改。这些参数(表7.1)。
|
|
REPORT_PARAMETERS_MAP |
它是java.util.Map传递给fillReport的方法,其中包含了用户定义的参数值。 |
REPORT_CONNECTION |
它是通过sql查询创建报表时传递给报表的JDBC连接。 |
REPORT_DATASOURCE |
它是没有使用JDBC连接时创建报表时用的datasource。 |
REPORT_SCRIPTLET |
It 指创建报表时用到的脚本实例,如果没有指定脚本,参数就聚焦到net.sf.jasperreports.engine. JRDefaultScriptlet实例上。 |
表格7.1
变量
变量是一个用来存放计算结果的对象,就像小计,总计等。
图7.12
和字段参数一样,变量被打出来,必须声明一个他们要求的java类型(Variable Class Type)。
图7.12显示了如何创建一个新的变量,看一下每个字段的意思。
Variablename他是变量的名字;和字段,参数一样,我们提供下面这个表达式
<variable name>
VariableClass Type 和参数一样,不用考虑对象的类型;在选择框中包含了大多常用的类型像java.lang.Stringand java.lang.Double;
CalculationType可以预先设置的变量的类型是:
“Nothing” 不用执行任何计算JasperReports执行计算来自于datasource的每条新的记录: 执行计算变量的意思就是求它的表达式(Variable Expression);如果计算类型是noting,JasperReports就将变量的表达式赋给变量值;如果计算类型不是noting,表达式的结果将计算一个新值赋给变量。计算类型有:
|
|
Nothing |
不是计算类型,它被使用当用户指定内在的表达式时,每条记录将被赋值。 |
Count |
计算所有非null的表达式的次数,不要把它和sum搞混了,sum是计算的是数字的结果 |
Sum |
反复的迭加表达式当前的值 |
Average |
计算所有标准输入的表达式的平均值。 |
Lowest |
返回标准输入中最低的表达式的值 |
Highest |
返回标准输入中最高的表达式的值 |
StandardDeviation |
返回标准输入中规格不同的表达式值standard deviation |
Variance |
返回标准输入中不一致的表达式值 |
System |
不是一种计算方式,也不求表达式的值;使用这个后,报表引擎仅将最后一个变量值放入内存中;它可以用脚本来存储计算结果。. |
表格7.2
Reset Type 当变量值被重设Initial Value为或简单null的时需要指定;变量重设是基本的,当你想求一些组的小计或平均值时;重设类型列表(表7.2):
|
|
None |
这个Initial Value Expression总是被忽视 |
Report |
这个变量被初始化一次仅仅在报表创建的开始,用Initial Value Expression。 |
Page |
这个变量被初始化在每个新页 |
Column |
The这个变量被初始化在每个新列(或者在每页,如果这个报表页仅仅只有一列的话) |
Group |
The 这个变量被初始化在每一个新的组(我们定义这个组用Reset Group) |
ResetGroup 当组选择Group reset类型时用来指定变量的重置
CustomIncrementer Factory Class一个叫JRIncrementerFactory接口的java扩展类用来定义像总计一个非数值类型的操作;
VariableExpression 用来识别输入值的java表达式
InitialValue Expression用来给变量初始化一个值的表达式
内置变量
像参数, JasperReports安置了一些用户处置的内部变量,他们是易读的,但不能被用户修改。这些变量是:(表格7.4)
|
|
PAGE_NUMBER |
包含了当前页码,在整个报表中包含总的页数。 |
COLUMN_NUMBER |
包含当前是第几列 |
REPORT_COUNT |
指示当前正在处理的是第几条记录 |
PAGE_COUNT |
当前页中包含了几条记录 |
COLUMN_COUNT |
当前列中包含了几条记录 |
<group name>_COUNT |
以变量前缀来表示这个组记录数 |
表格7.4
iReport Bands and groups
在这章我们将介绍如何用iReport管理band和group。第四章我们已经介绍了报表的结构,看到了报表是什么样子的。这里我们将用到组,如何创建一个breaks,如何管理子报表等等。
Bands
JasperReports将报表划分成7个主要的band和一个背景(总共就是8个bands)。其他两个(the group footer 和 the group header)bands被加进去。
按按钮进入bands列表(图8.1)。
图8.1
通过这窗口可以修改band的主要的属性,它的高,用像素表达(band高),可能band就会被打乱,如果超出了这页(Split allowed)和Print When Expression,这个表达式将返回一个boolean型的对象,并终止打印。就是这个空的表达式隐含了这个表达式从而使band总是被打印。键入表达式可能是字段,变量和参数,通过指令生成一个boolean对象的结果。
甚至指定一个合法的值,band的高也可能增大,如果一个或多个元素垂直的增加(可能在textfield元素内容或子报表超出了指定的尺寸的情况下发生).的话。 JasperReports可以保证band的高永远不会这样。
In 为了能调整band可能要用到bands窗口(图8.1),立即设置一个值在band的高的地方,或者用鼠标移动指针到次的空白处,拖拽它到页的底或顶。(图8.2)
双击次的空白页可以调整band通过改变内容的高度。
图8.2
如果一个或更多个bands没有高度,可以按shift键将它朝底边的空白移动来增加它的尺寸。
移动一个元素从一个band到另一个,这个元素就会自动被这个band关联起来。
Groups
分组可以将报表的记录分开成组。通过一个表达式可以定义一个组。JasperReports求这个表达式的值:一个新的组开始当这个表达式的值改变时。
我们将解释组的用途,通过一步一步的举例。
假设有一个人员列表:我们想创建一个以人名分组的报表,人名按首写字母分组(就像一个电话簿)。运行iReport打开一个空白报表页。用sql查询从数据库中取数据(一个JDBC连接到Northwind数据库,而且这个数据库已经配置完成并测试通过)。按照你记录做第一件你认为的选择:The first thing you have to think to is the order of record
selection: JasperReports获得没有顺序的记录从datasource;为这个原因你认为如何打印这些内容?你得自己把记录排序以正确的方式。我们用这个sql查询:
select * from customers order by CONTACTNAME
通过这种方式就可以将你选择的客户按他的名字排列。选择CONTACTNAME和COUNTRY字段通过Report Query Dialog (图8.3)。
图8.3
创建组之前,务必正确完成每件事,将CONTACTNAME和COUNTRY字段插入到details:编译和创建报表。结果应该和图8.5类似。
图8.4
加点难度,我们可以将detail分成两列(查看33页)。
图8.5
继续数据分组:通过 “groups”按钮进入报表分组管理窗口。
图8.6
按New按钮插入一个名字叫“Initial”的组
图8.7
可以通过以下几个属性定义组:
Group Name 定义组的名字,这个名字将被用来命名和这个组关联的两个band:header和footer;
Start on a new column 如果这选项被选择,它允许强制在组的最后将列分开(意思就是新开一个组);如果这个报表仅有一列,这列就将被分开;
Start on a new page 如果选择这项,它允许强制在组的最后将页分开(意思就是新开一个页);
Reset page number 这个选项可以重设页码在一个新组开始时;
Print header on each page 如果选择这项,就可以在所有的页打印组头的内容(如果一个组的内容比一页内容还多时,在新页上也打印组头);
Min height to start new page 如果不是0的话,JasperReports将在每页打印组,如果有效的空间被指定为次的空白;通常这是为了避免分割(就像一整段被分开一样);
Group Expression 是JasperReports计算记录的表达式;当表达式换一个值时,一个新的组就创建,如果表达式是空的话,既然这样,这个结果就是单一的组的头和单一组的角分在第一列头之后和最后一列角之前;
Group Header Band Height it is the band height representingthe group header:
像band一样,它可以在bands窗口(图8.1)中被修改;
Group Footer Band Height it is the band heightrepresenting the group footer:它也可以被修改想bands窗口一样(图8.1);
In在我们的例子中我们命名为“Initial”(名字的首写字母)的组,我们将告诉它开始一个新的列(选择Start on a new pageoption)。我们的表达式返回这个名字的第一个字母;这个表达式是:
$F{CONTACTNAME}.substring(0,1)
并不能充分的做我们想做的事,因为没人敢保证CONTACTNAME字段是否是空值,事实上在赋值时表达式会首先抛出NullPointerException异常,其次是ArrayOutOfBoundException异常。我们测试这个内容用这两个表达式:
( ($F{CONTACTNAME} != null &&$F{CONTACTNAME}.length() > 0) ?
$F{CONTACTNAME}.substring(0,1) : "")
我们用java约束它:
( condition ) ? value1 : value2
如果条件是true就返回value1,相反就返回value2。
具体的说就是如果字段是null或它的长度为0,返回一个空的字符串,否则就返回名字的第一个字母。
添加一个新组,在下面图上有两个新的bands: InitialHeader
and InitialFooter。 用表达式在textfield插入InitialHeader band 作为组(图8.8)。结果在图8.9。
图8.8
图8.9
报表中组的数量可能是任意不确定的,一个组可能被一个父组包含,父组包含其他的子组。结果就是一个组列表。
可以修改一个组与另一个组的关系的优先权,通过点组列表框架上的“Move Up”和“Move Down”按钮(图8.6)。
改变组的优先权的意思就改变这这个组的位置。优先权越高,组bands就越远离detail。