原文:http://eclipse.org/birt/phoenix/deploy/reportScripting.php
BIRT提供了一个基于Mozilla Rhino的脚本模型。报表引擎创建报表的过程可以划分为两个阶段——生成和呈现。生成阶段利用报表设计,生成一个名为报表文档的中间文件。呈现阶段利用报表文档进行渲染,生成HTML或PDF。报表生产线既可以将两个阶段作为一个任务执行,也可以作为两个任务分别执行。如果作为一个任务,那么报表文档是生成在内存中。在设计器中选择『以HTML方式预览』时,默认是采用这种方式的。反之,如果作为两个任务分别执行,那么报表文档将被保存在磁盘中。在设计器中选择『在浏览器中预览』时,默认是采用这种方式的。
每一个阶段的事件都通过事件处理器覆盖,用以修改报表内容。既可以用JavaScript,也可以用Java。
事件
三大对象——报表对象、报表元素和数据源(集)——具有脚本事件。当前所处的阶段决定了可以定制的事件类型和对象属性。
下图描绘了包含一个表和一个数据元素的简单报表的事件触发顺序:
reportContext和this
在使用Script编辑器时,如果选择Pallette View,那么会显示选定的报表元素、指定事件中能够使用的函数和变量。例如,下图指出了某个数据元素的onCreate事件能够使用的函数和变量:
this可用于在事件中列出元素的所有方法和属性。
reportContext则可以用于访问和修改报表一级的属性。开发人员可用它来设置全局变量。例如:
报表的onInitialize事件
reportContext.setPersistentGlobalVariable("testglobal", "test global string");
用Persistent版本的方法能让变量跨持久化。变量是Object类型的,具有高度的灵活性。
某个表中一个标签的onPrepare事件
this.text = reportContext.getPersistentGlobalVariable('testglobal');
全局变量可以通过绑定编辑器赋给数据元素。只需在给定列的表达式构建器中引用该变量即可。例如,如果绑定编辑器中有一列,其值从数据库取回。那么可以通过以下的表达式,在原值后附加上某个全局变量的值:
dataSetRow["MyString"] + "-" + reportContext.getPersistentGlobalVariable('testglobal');
reportContext也可用于访问会话级变量。
// attributeBean是Birt Viewer提供的一个会话级变量
myAttributeBean = reportContext.getHttpServletRequest.getAttribute('attributeBean');
reportDoc = myAttributeBean.getReportDocumentName();
this.text = reportDoc;
reportContext允许访问和修改脚本内使用的上下文。例如:
报表的onInitialize事件
appContext = reportContext.getAppContext();
importPackage(Packages.java.util)
myArrList = new ArrayList();
myArrList.add("one");
myArrList.add("two");
appContext.put("AppContextTest", myArrList);
这段代码读取了当前的应用上下文,并进行了一些修改。然后,可以在某个标签元素的onPrepare事件处理器中,这样使用:
appContext = reportContext.getAppContext();
myObject = appContext.get("AppContextTest");
this.text = myObject.size();
上例也可以这样实现:
reportContext.setPersistentGlobalVariable("testglobal", myArrList);
reportContext还可用于获取当前的区域信息,以及存储于资源文件中的消息。
报表级事件
afterFactory |
结束生成阶段时执行 |
afterRender |
结束呈现阶段时执行 |
beforeFactory |
开始生成阶段前执行 |
beforeRender |
开始呈现阶段前执行 |
initialize |
开始生成阶段和呈现阶段前执行 |
在initialize事件中,可以定义全局函数、变量和对象。例如,创建一个全局的函数:
function gTest(v){
return "Global Function:" + v;
}
// 仅在图表脚本中使用时需要
reportContext.setPersistentGlobalVariable("gTest", gTest);
只需这样调用:
gTest("MyTest");
或:
gTest = reportContext.getPersistentGlobalVariable("gTest");
val = gTest("Use Persistent");
在图表脚本中访问reportContext时,使用:
context.getExternalContext().getScriptable()
如,图表标题可以这样修改:
function beforeGeneration(chart, context){
importPackage(Packages.org.eclipse.birt.chart.model.type.impl);
newChartTitle = context.getExternalContext().getScriptable().getPersistentGlobalVariable("testglobal");
chart.getTitle().getLabel().getCaption().setValue(newChartTitle);
}
在beforeFactory中,有几个方法可以用于访问报表中的元素。需要对元素命名。例如,想要在动态文本元素"TestHeader"中显示数据集"orders"的查询语句,可以在beforeFactory中这样写:
query = this.getDataSet("orders").queryText
this.getDynamicText("TestHeader").valueExpr = "query;";
报表元素级事件
onPrepare |
生成阶段中,为每个报表元素调用一次。可用于修改设计。变更影响元素的所有实例,例如,所有的表行。 |
onCreate |
生成阶段中调用。可访问和修改元素的某个实例(如,每隔9行设置1行背景为红色) |
onRender |
呈现阶段中调用。类似于onCreate。不可访问数据。 |
一个非常简单的例子——某表中的明细行:
onPrepare:
this.getStyle().backgroundColor = "red"; // 影响所有行
onCreate:
if (this.getRowData().getExpressionValue(3) > 100)
this.getStyle().backgroundColor = "red"; // 只影响该行
如果该表中有100行,则onPrepare只调用1次,而onCreate和onRender将调用100次。
元素级事件实例
设置标签、文本、动态文本和数据元素的值
标签:onPrepare/onCreate
this.text = "My New Label"
文本:
this.context = "My New Text"
动态文本:
this.valueExpr = "row['CITY']";
this.valueExpr = "'my row count: ' + (row[0] + 1)";
数据元素:
使用绑定编辑器。
设置TOC
类似于值表达式,期待字符串:
this.tocExpression = "'tocbyrownumber: ' + row[0]";
使用行数据
在onCreate中可使用行数据,可用于对值进行检查。
this.getRowData().getExpressionValue(i) // 第i列的值
this.getRowData().getExpressionValue("some_expression") // 对该行套用表达式的值
例如:
if (this.getRowData().getExpressionValue(1) == "product1")
this.getStyle().backgroundColor = "red";
if (this.getRowData().getExpressionValue("row[price]" == "$30")
this.getStyle().backgroundColor = "blud";
修改超链接
可在onPrepare中修改:
this.getAction().URI = "'http://www.google.com'";
getStyle
用于定制给定元素的属性。例如:
this.getStyle().fontWeight = "bold";
getParent
用于访问父元素。例如,从数据元素获取表:
this.getParent().getParent().getParent();
getValue
满足一些基于值变更视觉外观的需求。
if (this.getValue() > 30){
this.getStyle().fontFamily = "Arial"
this.getStyle().backgroundColor = "Yellow"
}
命名表达式
是指在某个元素上创建,并给予命名的表达式。其定义可在onPrepare中修改,其值可在onCreate和onRender中访问。例如,定义一个表达式totalCreditValue,其值为Total.sum(row[?CREDITLIMIT?])。然后,就可在其他元素中用JavaScript和Java访问。
例如,在某个表上建一个表达式"RWC",值为row[0],则可在行中用以下方式访问:
rc = this.parent.getNamedExpressionValue("RWC");