FastReport之单元格纵向合并

最近在做一个报表,客户坚持要报表实现行合并,使用了TextObject的Duplicates属性,设置为Merge。但是效果不太好,相邻的相似就合并,显得报表很杂乱,效果如下:

而客户想要的效果是这样的:

网上搜了一下关于fastreport单元格合并的文章,有说改源码的,有说写脚本的,还有人卖修改后的控件的,总之没有找到现成的方法。所以在客户的压力下不得不自己想办法解决,首先想着改源码,可是没有源码啊!!!反编译出来的又太杂乱,编译错误一大堆,所以就改为从脚本入手了。

其实要实现客户这种效果,只要解决不同“层级”间即使内容相同也不合并就可以了。怎样使不同“层级”的单元格,即使内容相同也不合并呢,这里用Duplicates属性设置为Merge显然不能实现了,所以我想到了之前做项目遇到过的不可见字符的问题。在ASCII码中有很多特殊字符,比如“(char)0”,它就是一个不显示的字符,如果相邻“层级”的数据按奇偶行的模式分别在前面加上空字符串("")和不可见字符(((char)0).ToString()),岂不是在不同“层级”间就不合并了!

    private void Text5_BeforePrint(object sender, EventArgs e)
    {
      DataSourceBase dsb= Report.GetDataSource("BOMLIST");
      if(lasttext1==""||dsb["LAYER"].ToString()!=lasttext1)
      {
        lasttext1=dsb["LAYER"].ToString();
        lastadd = lastadd==""?((char)0).ToString():"";
      }
      Text5.Text=lastadd+Text5.Text;
    }

因为不同“层级”间“层级”和“物料编号”不会相同,所以选择最左边会出现相同的“物料名称”的BeforePrint事件来做这一动作。由于报表数据加载是从左到右、自上而下,所以后面的TextObject只需要把lastadd加上就可以了。

详细代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Data;
using FastReport;
using FastReport.Data;
using FastReport.Dialog;
using FastReport.Barcode;
using FastReport.Table;
using FastReport.Utils;

namespace FastReport
{
  public class ReportScript
  {

    private string lasttext1="";
    private string lastadd="";
    private int loadcount=0;
    private void Text9_BeforePrint(object sender, EventArgs e)
    {
        Text9.Text=lastadd+Text9.Text;
    }

    private void Text5_BeforePrint(object sender, EventArgs e)
    {
      DataSourceBase dsb= Report.GetDataSource("BOMLIST");
      if(lasttext1==""||dsb["LAYER"].ToString()!=lasttext1)
      {
        lasttext1=dsb["LAYER"].ToString();
        lastadd = lastadd==""?((char)0).ToString():"";
      }
      Text5.Text=lastadd+Text5.Text;
    }

    private void Text7_BeforePrint(object sender, EventArgs e)
    {
       Text7.Text=lastadd+Text7.Text;
    }

    private void Text19_BeforePrint(object sender, EventArgs e)
    {
        Text19.Text=lastadd+Text19.Text;
    }

    private void Text21_BeforePrint(object sender, EventArgs e)
    {
       Text21.Text=lastadd+Text21.Text;
    }

    private void Text23_BeforePrint(object sender, EventArgs e)
    {
        Text23.Text=lastadd+Text23.Text;
    }

    private void Text25_BeforePrint(object sender, EventArgs e)
    {
        Text25.Text=lastadd+Text25.Text;
    }

    private void Text27_BeforePrint(object sender, EventArgs e)
    {
        Text27.Text=lastadd+Text27.Text;
    }

    private void Text29_BeforePrint(object sender, EventArgs e)
    {
         Text29.Text=lastadd+Text29.Text;
    }

    private void Text31_BeforePrint(object sender, EventArgs e)
    {
        Text31.Text=lastadd+Text31.Text;
    }
  }
}

这样就可以实现客户想要的效果了。

:首先是要分组,因为如果不分组,想合并的列与其它列会自动打印。这样,只能使用FR自带的隐藏重复数据的功能,但很多类似报表都是要求合并行居中的,这点FR就不能自动实现了。 2:要全并的列放在分组脚中,其它放在分组数据BAND中,这样,打印完分组数据BAND后,动态改变分组脚中要合并列的TOP和HEIGHT就可以了。而且这样打印,因为要合并的行实际上只打印了一遍,因此应该效率更高。所以这就需要在打印分组数据BAND后有一个可记录此分组已打印高度的功能。 3:代码解释 procedure MCOnAfterData(Sender: TfrxComponent); begin if =1 then MC.Tag:=Int(MC.Height) else MC.Tag:=MC.Tag+Int(MC.Height); end; 因为FR的在每次分组后重新计数,使用MC.Tag保存现在数据BAND上的所有不合并行的总高度。当然也可以使用一个变量,但放着这么多TAG不用,多浪费呀。况且使用TAG的语法也比使用变量简单,使用变量使程序看上去很难懂。 if >=1 then 这样的写法看起来多痛苦呀。 procedure MBBOnAfterData(Sender: TfrxComponent); begin MBB.Tag:=GetStandHeight(MBB.CalcHeight); //这一句是为了保持行高的一致性,如果不需要直接 MBB.Tag:=MBB.CalcHeight; //这样可能计算的行高不是标准行高的整数倍。 MBB.Visible:=False; end; procedure MD1OnBeforePrint(Sender: TfrxComponent); begin if =1 then MBB.Visible:=True; end; 上二句只是为了不多次统计CalcHeight,但不能直接设可视性为假,否则不会触发MBBOnAfterData事件。 计算此例中可能会很高的列的计算高度,这是在宽度已经确定的情况下计算的。 因为此例中的第二列单行高度可能大于其它列的总高度。如果没有此例中的特殊情况,可以省略。 4:如果此例中没有第二列单行高度可能大于其它列的总高度的话,MBB是不需要的。 5:如果不是要求空行为多行多列显示的话,GFOnBeforePrint也是不需要的,只需要在GF上放二个MEMOVIEW,宽高和左边距分别与上方的二个相同,调用我例子中注释掉的代码改变它们的TOP和HEIGHT即可。 6:TAG是所有Tcomponent的属性呀,这是我最常使用的一个属性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值