zoukankan      html  css  js  c++  java
  • 如何动态的给报表添加目录

    需求描述:

    在做一些类似 word 报告格式报表时,为了有更好的阅读效果,经常需要在首页增加一个目录导航页,这样就能够快速的知道关心的数据在第几页,但是报表不同于 word 文档,word 文档中格式都是固定的,所以能够方便快速的生成目录页,在报表中数据都是动态变化的,并且通常会涉及到动态扩展,这样很难固定目录项,并且由于数据动态扩展,对应的页码也很难精确获得,下面通过一个实例看下,如果在报表中动态增加目录。

    解决方案:

    报表数据是动态的,所以设计时就不能用固定的目录,需要报表计算后才能知道数据在第几页,润乾报表提供了一个报表计算侦听类,在 java 程序中可以动态获取报表计算后的结果,并能够在程序中动态更改单元格的值。

    首先,看下报表模板的设计界面:

    这个报表要对订单数据按照地区进行汇总分析,并展示详细数据,要求目录中以地区为导航进行设置,报表前 5 行是目录页,第三行中,概要分析一般是固定的,这里就写了固定一行,页码设置 2 就行。

    A4:=ds1.group(货主地区; 货主地区:1),表达式按照地区进行分组,也就是目录这块按照地区进行展示,对应 E4 单元格后续要设置成目录页,此处暂时为空。

    A5:目录通常在第一页,所以此处设置一个行后分页

    A7:就是一个固定的汇总描述,里边可以用字符串拼接方式将固定文本和动态数据拼接在一起展示。

    A8:=ds1.group(货主地区; 货主地区:1),按照地区进行分组

    A9:对该地区数据做一个汇总说明

    A10:=ds1.select(订单 ID),取数订单数据,B10 往后依次类推。

    将 A9,A10,A11,A12 单元格的左主格设置成 A8,此片数据根据 A8 进行纵向扩展,这样报表展示结果为:

    这里可以看到,目录项处列出了对应地区,接下来看下,如果给地区增加对应页码。

    从报表结果中看到,第一页中的目录名称和报表中的地区名称相同,这样就可以根据这两个名称做匹配,判断如果名称相同获取数据区域的名称所在的页码,放到对应目录行就行,如数据区域的“东北”在第 2 页,那么目录中东北的页码应该为 2,接下来看下,如何给目录设置动态的页码。

    这里就用到了之前说到的报表侦听类的使用,源码如下:

    import com.raqsoft.common.Area;
    import com.raqsoft.report.usermodel.Context;
    import com.raqsoft.report.usermodel.IPagerListener;
    import com.raqsoft.report.usermodel.IReport;
    import com.raqsoft.report.usermodel.IReportListener;
    import com.raqsoft.report.usermodel.PageBuilder;
    import com.raqsoft.report.util.ReportUtils;
    public class createmulu implements IReportListener {
    public void afterCalc(Context arg0, IReport arg2) {
    PageBuilder arg1 = null;
              try {
    arg1 = new PageBuilder(arg2);
    } catch (Throwable e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
    }
    System.out.println("报表总页数"+arg1.getPageCount());
    IReport p1;
    try {
    p1=arg1.getPage(1);//目录通常在第一页,所以获取第一页为目录页
    int page=2;//设置数据初始循环页,通常为第二页
    for(int i=3;i<=p1.getRowCount();i++){//目录行从第三行开始
    String muluName=(String)p1.getCell(i, 2).getValue() ;//报表中设置第二页为目录名称
    for(int j=page;j<=arg1.getPageCount();j++){//按照页数进行循环,分别取分页后每页报表对象
    for(int k=1;k<=arg1.getPage(j).getRowCount();k++){//每页中按照每行进行循环
    String mName=arg1.getPage(j).getCell(k,1).getValue() != null ? arg1.getPage(j).getCell(k,1).getValue().toString() : "";//本例中目录项在报表中的第一列,也就是A8单元格
    if(mName!="" && mName==muluName){//判断每页中的目录项和第一页中的目录名称是否相同
    arg2.getCell(i, 5).setValue(j);//如果相同,则设置目录页第5列对应的值为对应页码,注意,此处是arg2对象
    arg2.getCell(i, 5).setHyperlink("javaScript:toPage('report1',"+j+")");//设置超链接
    page=j;//为提高计算效率,下次在循环时,不用从第2页开始,从上次终端的页码开始就行
    break;//找到页码,跳出此处循环,提高效率
    }
    }
    }
    }
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    public void beforeCalc(Context arg0, IReport arg1) {
    }
    }

    核心思路就是在类中根据名称进行匹配,获取页码,放到对应单元格中,将编译好的类放到报表类路径中,如:应用的 WEB-INFclasses 下,注意如果有包路径,此处要要带相应的路径,放置过去后重启应用,在页面端访问报表,结果如下:

    可以看到,目录后边会生成对应的页码,word 中目录有个功能点是,点击页码,能够快速跳转到对应的页数,报表中同样可以增加对应的功能,报表提供了一个跳转页数的 js 函数,toPage,在 java 类中,在对应的页码单元格设置了一个超链接,调用这个 js 就行:

    arg2.getCell(i, 5).setHyperlink("javaScript:toPage('report1',"+j+")"); 

    这样,在页面端点击页码,就能够快速跳转到对应页数,当然,此功能要求报表在页面端分页后才有效,否则无法跳转,并且如果导出到 word 的话,只能显示页数,无法跳转。

    通过这个例子可以看到,通过拿目录项中的单元格数据和数据表中的单元格进行匹配,来获取页码,但是在实际使用中,目录页中的目录名称和报表中的数据名称可能并不完全一致,比如目录页中叫东北,报表数据中叫东北地区,很难严格匹配,这样可以换种变通的方法,报表单元格属性栏中有个注释属性,可以在这个里边写上和目录项匹配的值,然后 java 类中可以根据这个属性的值做匹配,这样能够实现更加灵活的效果,更多 api 接口可以参考报表帮助文档《程序员参考》,后续带来更多 api 在报表实际需求中的应用。

    更多报表样式类问题请看:报表样式分类导航

    * 按段分组报表制作

    * 如何开发主从报表

    * 报告式报表的制作

    * 报表中如何实现不规则布局

    * 报表工具轻松搞定卡片式报表

  • 相关阅读:
    leetcode------Rotate Array
    leetcode------Validate Binary Search Tree
    leetcode------Unique Binary Search Trees II
    [错误]集合已修改;可能无法执行枚举操作
    [转载]如何申请淘宝app_key、app_secret、SessionKey?
    [转载]JS中如何定义全局变量
    [转载]C# Double toString保留小数点方法
    jquery easyui datagrid 获取选中多行
    MongoDB { code: 18, ok: 0.0, errmsg: "auth fails" } 原因
    C# WinForm开发系列
  • 原文地址:https://www.cnblogs.com/IBelieve002/p/11611381.html
Copyright © 2011-2022 走看看