2019-1-17水晶报表技巧总结【二】

2019-1-16水晶报表技巧总结【一】

 

2019-1-18水晶报表技巧总结【三】

 

第一条:水晶报表分组分页且每页最多显示N条记录

第二条:一个获取记录的标记和页脚的显示

第三条:页面大小的设置。

第四条:如果要让列分上下两处显示---要用到子报表。把子报表和主报表做成一样的格式。

第五条:推拉说识 

第六条:一种根据记录数和前面一行的内容和后面一行的内容不一样而分页 

第七条:主报表和子报表共享数据 

第一条:水晶报表分组分页且每页最多显示N条记录

返回顶部

要求:1、详细节最多5条记录(不能超过5条);
           2、无论前一组是否满5条记录,每个新组都要另起一页

           3、可以显示组内分页的情况,即:显示一个组被分为几页并且当前是第几页

我们知道每页最多显示N条的控制方法,打开节专家,在详细节后面新建页公式编辑:
RecordNumber mod N = 0

RecordNumber即记录数,无论分组与否,是自动随记录递增的,所以在这里,我们不能用RecordNumber,而应该是在每个新组前要重置这个RecordNumber,用这个重置的RecordNumber来取模控制每页最多显示5条记录,于是我们很自然就想到了运行总计字段,由它来帮我们重置RecordNumber,

这样我们应该就很明朗了,接下来让我们一起去设计模板:

报表按ID分组就不用再提及了吧?(右击报表空白处->插入->组)
首先新建一>运行总计字段
汇总字段:XXX(最好选择的字段和分组字段不同)

汇总类型:计数
求值:对于每个记录
重置:组更改时
设计好后把,字段放到【详细资料】中,根据需要可以抑制显示。
点击节专家,【详细资料】-->【在后面也新建页】勾上-->设置公式
1
2
字段是刚刚建立的【运行总计字段】
{#RTotal0} mod 10=0

针对需求2,与需求1同理,只不过此时我们是在#组尾(组页脚)节在后面页新建页的公式编辑:

Not OnLastRecord

OnLastRecord意指最后一条记录,Not OnLastRecord自然是非最后一条记录,在这里就是指非最后一条记录时就在后面页新建页,最后一条记录时就不用再新建页了。若不用该公式控制的话,报表的最后一页总是空白页(没有详细节数据)
需求3:组内分页及显示页码

新建一个【公式字段】公式设置如下:

记录的组记录总数:count(一个报表参数,分组参数);前者最好是运行总计的字段。如果有汇总,请在count最后+1,因为多一行数据。!!!

组内条数和当前组内序号,这两个最可能出现有误,在序号为9或者11,就是比你设定的行数大 “1”。

方式一:注意组内数据条数当前组内序号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//每个组的总记录数
NumberVar groupRecordCount := Count ({DataTable3.Type}, {DataTable3.ID});
  
//每个组的总页数
NumberVar groupPageCount := groupRecordCount / 5;
If Int(groupPageCount) <> groupPageCount Then
(
  groupPageCount := Int(groupPageCount) + 1
);
  
//重置后的RecordNumber
NumberVar groupRecordNumber := {#RTotal0};
  
//组内当前页
NumberVar groupPageNumber := groupRecordNumber / 5;
If Int(groupPageNumber) <> groupPageNumber Then
(
  groupPageNumber := Int(groupPageNumber) + 1
);
  
//最终报表界面显示
'第' + ToText(groupPageNumber, 0) + '页 / 共' + ToText(groupPageCount, 0) + '页'
//说明:Int函数是取整函数,如Int(1.2)=1; Int(1.9)=1
//写好后将该公式字段拖放到#组头(组页眉)节即可

方式二:注意组内数据条数当前组内序号  如果有方法“RoundUp”的,可以把if直接换成此方法:p1:=RoundUp(x1/10); p2同理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
numbervar x1;
numbervar x2;
numbervar p1;
numbervar p2;
 
//x1是每个组的数据条数
x1:=count({OUT_1_DATASET.code1},{OUT_1_DATASET.Warehouse_position});
 
//得到总页码
if(x1%10=0)then
p1:=x1/10
else
p1:=INT(x1/10)+1;
 
 
 
 
//得到当前行组内序号。其实就是换页第一条的序号
x2:={#RTotal0};
 
//用序号除以每页的条数5,得到当前页码
if(x2%10=0)then
p2:=x2/10
else
p2:=INT(x2/10)+1;
 
 
//组合
'第'+totext(p2,0)+'页/共'+totext(p1,0)+'页'

  


 

第二条:一个获取记录的标记页脚的显示

返回顶部

1
2
3
4
5
6
在IDE左侧的“字段资源管理器”里的“公式字段”点击右键“新建”,新
 
建一个字段“Group”,编辑赋值:
whilereadingrecords;
true;
这里是TRUE,获取的就是“真”,否则获取的就是“假”

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
控制子报表每页显示数目,假设为10行每页,只是做一下说明,不要设置公式
注意设置的行数最好基本上能打印到页面的底部
 
拆分一个详细资料节出来,把页脚内容写上,抑制显示,设置公式为
recordnumber mod 10<>0
在这个节上进行分页控制,“在后面页先建页面”勾上,设置公式为
recordnumber mod 10=0
 
这样的话每页最下面会显示该节模拟页脚
最后一页如果不满10行的话,因为你设置了报表页脚,也可以模拟成一个页脚了
为了防止最后有一页刚好显示10行导致出现双重页脚
还需要进一步改进一下抑制显示的公式
If onlastrecord then
true
else
if recordnumber mod 10<>0 then
true
else
false
 
  
 
最后页不足,用空行填充: (Basic语法)
新增一个空白详细资料行,格式化此节,在抑制显示(无深化)打勾
公式中输入:
if not onlastrecord  then
    FORMULA = TRUE
else
   if (RecordNumber mod 5 <= 1) then  '第一个
       FORMULA = TRUE  
   else
       FORMULA = FALSE 
   end if
end if

第三条:页面大小的设置。

返回顶部

要现在本地的打印机上设置相应的纸张大小,然后应用到报表中。

本地打印机添加新的打印纸张规格:

WIN7系统中:设备和打印机-->菜单栏中【打印服务器属性】-->【表单】或者【格式】-->创建新表单-->输入相应的尺寸,点击保存即可。

在报表中,右击报表的空白处:设计-->页面设计,填写相应的尺寸。设计-->打印设置-->在纸张中选择自己新建的纸张大小就可以了。

 

第四条:如果要让列分上下两处显示---要用到子报表。把子报表和主报表做成一样的格式。如下显示:

返回顶部

合同编号:XM-003   供应商:广西中金公司
合同条款                金额       
付20%                   2000
付80%                   8000
付款日期      付款金额
2011-10-1        10000
2012-10-12       12000

折开显示,每个页面就可以固定显示,这样按分组分页,防止数据过多分页时,子报表被分开。

 特别说明!

使用子报表的方法,在数据量较大的时候,效率非常低。所以要慎重选择使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
如何将同一个表(记录集)中的字段,拆成上下两部分,每页各显示10条。
也就是这个样子。
有人可能一下子想到的就是两个子报表。
如果数据比较少,不用分页,用子报表是没问题的
但是如果要分页,子报表是做不到的(至少目前的水晶报表还不支持这个机制)。
因为显然两个子报表都要分页(或者有人是用一个主报表,一个子报表)
但是这样一个页面上就出现了两个分页需求,然目前水晶报表的解析,是用后面的规则去覆盖掉前面的规则
也就是说,虽然确实都分页了,但是因为常规分页都是在详细资料节处新起一页的。
那么第2个子报表和第1个子报表的内容会重叠起来。
而如果把子报表放在不同的节上,又会出现这样的情况。
就是第一个子报表全部分页结束,才会显示第2个子报表的内容。
这样就造成了数据不连贯(当然,也有的需求直接就这样,那就直接这么用就可以了)。
 
下面我开始示例操作
 
1:样例数据
本文以独立版本水晶报表自带的样例数据库xtreme.mdb中的Orders订单表为例。
 
 
2:数据的整理
数据必须有一个连续的ID(或者有一个分组的标志位),这是本文实现的重点。
所以特别说明一下。
我们的方案中,将以这个ID(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22...)为准进行处理。
如每10个分一页,那么我们要构造一个分组字段:(ID-1) \ 10
注意这个符号,是取整的。
这样,就把每10个归为一个组了。这个字段会出来一个0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3...
当然,如果有条件,可以之前就准备好,比如说这个ID直接就是1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3...
这里我先不讲为什么要这样做,只是你务必要注意这一点。
不要依赖于数据库本身里的ID,因为你可以有不同的过滤条件及排序条件,会导致你的本身的数据ID是不联系的
所以这个ID字段,是你自己构造的,与是原先数据并无实际的逻辑关系,只是为报表准备的。
 
比如,以Access语法为例子,为现有记录集主动加一个ID列。
SQL code
?
1
2
3
4
SELECT (
SELECT count(*) +1
FROM [Orders ] as where a.[order id]<b.[order id]) AS  myIndex, b.*
FROM Orders AS b;
 
 
其显示的结果如下
 
 
当然,我们也可以直接进去到前面说的第2种情况
SQL code
?
1
2
3
4
SELECT (
SELECT count(*)]\10
FROM [Orders ] as where a.[order id]<b.[order id]) AS  myIndex, b.*
FROM Orders AS b
 
 
其显示的结果如下
 
 
本文采用第一种方法来实现。
 
3:数据与模板怎么进行连接
我们已经知道制作模板有PULL和PUSH两种方法。
使用PUSH的话,就不用关心这个操作了。因为这个SQL是在代码中实现并传给记录集的再传给报表。
而使用PULL的时候,就这样,直接把SQL代码拷贝到“命令”就行了。
当然,你也可以使用存储过程,或者一个中间的实体结果表等。
 
 
4:制作主模板
我们先用主报表来显示前半部分字段,然后用子报表挂接后半部分字段。
两个报表可以使用同一个记录集
不过如果数据量比较大,建议还是按照实际需要拆开,这样减小数据的传输
如主报表的记录集只放前5个字段,子报表的记录集放后5个字段等。
 
我这里为了方便操作,用了同一个记录集。
 
 
<1>首先构造主表,做一个基础的明细表
 
 
 
 
 
 
<2>构造分组字段myGroup1,进行分组
如果是【2:数据的整理】中的第2种实现方法,则可以直接用ID作为分组字段了
 
myGroup1公式如下:
 
并进行分组,如果需要,把页眉放到组页眉上。
 
 
最后出来的模板是这样的
 
 
出来的数据是这样的
 
 
好了,主报表操作完毕。
 
5:制作子报表模板
 
在模板上点右键,插入子报表。
把这个子报表,拖到主报表的组页脚上。
子报表的做法跟【4:制作主模板。】一模一样。
(包括分组公式及操作)
唯一的不同就是在模板上显示的字段不同,此处省略了。
为了便于识别,把子报表上的字体全部设置为红色。
把不需要显示的节,全部抑制显示掉
 
 
 
6:设置主报表和子报表的关系
 
这个时候报表大致就是这个样子的,在子报表上点右键,选“更改子报表连接”
 
 
在出来的界面上,把两个分组字段关联起来。
(我这里两个分组字段取的名称不一样,这个不影响操作)
 
好了,再预览一下数据。这样数据就组合在一起了
 
 
7:分页设置
 
进入主报表的“节专家”,设置组页脚,勾选“在后面页新建页”就可以实现了。
如下图我们切换到第3页。

 第五条:推拉说识 

返回顶部

.【水晶报表内功心法】--序言 
.【水晶报表内功心法】--推拉之间
.【水晶报表内功心法】--PULL模式样板招式

特别说明:
因为水晶报表里不认datatime型,对于2009-06-26 9:23:15
会自动截断为2009-06-26
所以datatime型数据在xsd文件中,可设置为string型
而代码中的SQL中可把字段转换为String传入。

这里做一下说明,在【推拉之间】没有说这个xsd,是因为当时没讲到细节操作。
说了很难理解。
这个xsd,是我们自己构造的,做个比喻吧:
就是xsd比作个一个架子,它负责把水晶报表撑起来,但是是空的,没有内容
我们用 PUSH模式,把数据塞给它,把架子塞满,这样水晶报表也就能呈现出效果来


常见问题:
1:报表可以显示出来,但是没数据,
一般有以下几种情况
a:表中确实没数据
b:da.Fill(dt1, "mytable");表名称与xsd中设计的表不一致
c: 如果你用了多个表,可能是因为表默认的关联关系导致无数据

2:出现下面这个图的提示,特别是翻页、打印、导出的时候,因为这些动作都需要重新连接数据库源。
a:如果是多表的话,可能是部分表没有赋值。
    水晶报表需要对用到的每个表进行验证,即使没数据。没有的话,传个空的记录集也行。
b:代码没有放到Page_Load或Page_init里,或者是放到了,但是控制了 postback。
   因为http是无状态的,如果控制了postback,水晶报表就丢失了前面的设置,会导致出现此情况的

第六条:一种根据记录数前面一行的内容和后面一行的内容不一样而分页

返回顶部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在报表上右键-->报表-->节专家-->详细资料-->在以下内容前新建页-- >右边的小方块中新建basic公式:
 
水晶报表常规页码是以下代码的"3",满3行记录的自动换行,碰到TBUserInfo.SerialNo与上一行记录不同也换行。
 
Shared SerialNoGG as Number
Shared RecordTemp as Number
if RecordNumber = 1 then
    SerialNoGG = {TBUserInfo.SerialNo}
    RecordTemp = 1
end if
 
 
   if RecordTemp mod 3 = 0 or {TBUserInfo.SerialNo}<>SerialNoGG then
      RecordTemp = 1
      SerialNoGG = {TBUserInfo.SerialNo}
      formula =true
   else
      RecordTemp = RecordTemp + 1
      formula =false
   end if

第七条:主报表和子报表共享数据

返回顶部

使用水晶报表变量实现主报表及子报表之间的数据共享

在使用水晶报表子报表的时候,
可能根据需要在主报表之间和子报表之间共享部分数据
如子报表需要依据主报表的某些数据进行运算等

因为主报表与子报表之间的数据是独立的,所以不能直接引用对方的字段等资源
所以要得到对方的数据有些难度,
有些朋友使用在代码中传递参数等方式来实现,
其实在水晶报表中已经有了问题的解决方法,那就是公式中的共享变量

大家可能注意到了在水晶报表的公式中定义的变量是有作用域的
分别是Dim/本地(Local)/全局(Global)/共享(Shared)

使用水晶报表的共享变量即可实现在主/子报表之间的数据共享

在下面的例子中,我们以在子报表中获取主报表中的一个数据为目标来进行演示
我们使用水晶报表的自带的数据库来做演示,在主报表中获取一定的数据
然后进行汇总
在子报表中获取这个汇总数据,

以下的公式,使用Basic语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
主报表中的公式如下
公式名称:@fMain1
公式内容:
Shared myTest1 as string
myTest1={产品.颜色} '此处可以替换为任意想获取的数据
formula = myTest1
 
将该公式应用到主报表的适当位置,如果不需要显示,可以抑制显示
不影响后续数据的获取
 
子报表中的公式为:
公式名称:@fSub1
公式内容为:
Shared myTest1 as string
formula=myTest1
 
将公式应用到子报表的适当位置,即可显示出主报表的内容
 
注意:公式中的变量名称与类型需要一致!

  

返回顶部

posted @   IT苦行僧-QF  阅读(1721)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示