|
本帖最后由 t小宝 于 2009-5-30 15:39 编辑
最近又看到在关报表分组页码的帖子,也来凑下热闹。
一年前曾要使用在报表显示分组页码和页数的功能,网上苦苦寻觅而不得,于是硬着头皮研究,终于得出
两种方法。
后来才发现2004年在access中国已经有人提出这样的问题,并有解决方法,是这个帖子:
http://www.office-cn.net/forum.php?mod=viewthread&tid=19213&highlight=%D7%E9%2B%D2%B3
不过在预览报表时改变页面设置(边距、大小、方向等)后,页码显示出现错乱;
再后来又在微软网站看到一篇专门解决此问题的kb文章:
http://support.microsoft.com/kb/841779/zh-cn?spid=1265&sid=98,
其需要另建一个表,并使用记录集,显示效果比较好,但在某些情况下改变页面设置还是会出现页码显示
错乱。
而本人的方法经本人测试,改变页面设置无页码显示错乱现象,因此斗胆称为终极解决方案,请大家测试
和批评,也许还有更好的方法。
做成了类模块,有一点注释但很难讲明白,如果谁要研究实现原理可以和我交流。其实上面说的两个方法的实现原
理我也不清楚,很多事情知道用就行了。
'分组报表显示分组页码和页数(方法一)
'
'功 能:在有分组的报表的每一页上显示组页码和组页数,在预
' 览时改变页面设置后仍能正确显示。
'作 者:t小雨([email=tcl013@126.com)(t]tcl013@126.com)(t[/email]小宝)
'版 本:1.1
'创建日期:2008-05-??
'整理日期:2009-05-30
'补充说明:这个代码是一年前做的,由于实现原理和过程有点复杂,
' 当时没有添加注释,已忘得差不多,加上表达能力有限,
' 现在勉强添加了不完全的注释,但能依照说明会用就行。
' 直接把代码放到报表中也是可以。
' 做成类模块只是为了好保存,以后调用方便,但由于在
' 类模块中不能使用报表的节的事件,调用起来还是有些
' 麻烦,不过总要比直接把代码放在报表简单一点。
'
'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'实现原理:
'通过报表上的辅助文本框获得组的总行数(记录数,后同)、1页的最大行数、当前页在当前组的截止行数,
'在页面页脚_Format事件中通过计算得到分组页码和页数。
'报表设计要求:
' 1、报表应包含组页眉、页面页眉、页面页脚
' 2、在组页眉上有一文本框,有如下属性
' ControlSource(控件来源)="=Count(*)"
' RunningSum(运行总和)=0(不)
' 3、在主体有一文本框,有如下属性
' ControlSource(控件来源)="=1"
' RunningSum(运行总和)=1(工作组之上)
'调用方法,有2种:
' 第1种:
' 1、在报表用New关键字声明一个 CreateGroupPage1 类的新实例
' 2、在报表的打开事件执行实例的 Init 方法,传入全部参数
' 3、在页面页脚的 Format (格式化)事件执行实例的 FormatPageFooter 方法
' 4、在页面页脚的 Print (打印)事件执行实例的 PrintPageFooter 方法
' 这种方法在显示分组页码的标签上显示效果如 分组字段值: 1 / 2
' 在报表中的代码类似下面:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Dim newGroupPage As New CreateGroupPage1
'
' Private Sub Report_Open(Cancel As Integer)
' newGroupPage.Init Me, Me.TxtGrpRows, Me.txtRunSum, Me.LplGrpPages
' End Sub
'
' Private Sub 页面页脚_Format(Cancel As Integer, FormatCount As Integer)
' newGroupPage.FormatPageFooter
' End Sub
'
' Private Sub 页面页脚_Print(Cancel As Integer, PrintCount As Integer)
' newGroupPage.PrintPageFooter
' End Sub
'
' Private Sub 组页眉0_Format(Cancel As Integer, FormatCount As Integer)
' newGroupPage.FormatGroupLevel1Header
' End Sub
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 第2种:
' 1、在报表用 WithEvents 关键字声明一个 CreateGroupPage1 类的变量
' 2、在报表的打开事件用 Set New 语句创建新实例
' 3、在报表的打开事件执行实例的 Init 方法,不须传入最后一个参数(用于显示分组页码的标签)
' 4、在页面页脚的 Format(格式化) 事件执行实例的 FormatPageFooter 方法
' 5、在页面页脚的 Print(打印) 事件执行实例的 PrintPageFooter 方法
' 6、在组页眉的 Format(格式化) 事件执行实例的 FormatGroupLevel1Header 方法
' 7、在类的 Current 事件过程将事件参数返回的分组页码和页数赋给用于显示的标签
' 在报表中的代码类似下面:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Dim WithEvents newGroupPage As CreateGroupPage1
'
' Private Sub Report_Open(Cancel As Integer)
' Set newGroupPage = New CreateGroupPage1
' newGroupPage.Init Me, Me.TxtGrpRows, Me.txtRunSum
' End Sub
'
' Private Sub 页面页脚_Format(Cancel As Integer, FormatCount As Integer)
' newGroupPage.FormatPageFooter
' End Sub
'
' Private Sub 页面页脚_Print(Cancel As Integer, PrintCount As Integer)
' newGroupPage.PrintPageFooter
' End Sub
'
' Private Sub 组页眉0_Format(Cancel As Integer, FormatCount As Integer)
' newGroupPage.FormatGroupLevel1Header
' End Sub
'
' Private Sub newGroupPage_Current(GrpPage As Integer, GrpPages As Integer)
' Me.LplGrpPages.Caption = Me.类别名称 & " 共 " & GrpPages & " 页,第 " & GrpPage & " 页"
' End Sub
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
类模块:- Option Compare Database
- Option Explicit
- Public Event Current(GrpPage As Integer, GrpPages As Integer)
- '在此自定义事件中可以获取分组页码信息,以便自定义显示页码格式
- Dim MyRpt As Report
- Dim txtRunSum As TextBox ' 取得每个组的记录数的文本框
- Dim TxtGrpRows As TextBox ' 取得每个组的记录在组中的序号的文本框
- Dim lblShowPage As Label ' 用于显示分组页码信息的标签
- Dim inMaxRows As Integer ' 1页的最大行数(记录数)
- Dim inRptPage As Integer ' 报表本身页码
- Dim blPrint As Boolean ' 是否已经发生页面页脚的Print事件,为避免页面页脚的Format事件中的代码重复运行
- Dim blFistPage As Boolean ' 当前页是否是所在组的第一页
- Public Sub Init(rpt As Report, GrpRows As TextBox, RunSum As TextBox, Optional ShowPage As Label)
- ' 过程中的检查参数代码不是必须的,仅为了防止以后忘记如何设计报表
- Dim st1 As String
- Set MyRpt = rpt
-
- Set TxtGrpRows = GrpRows
- With TxtGrpRows
- If .Section <> acGroupLevel1Header Then
- st1 = "作为第二个参数的文本框必须在分组页眉节上!"
- ElseIf .ControlSource <> "=Count(*)" Then
- st1 = "作为第二个参数的文本框的ControlSource属性必须是""=Count(*)""!"
- ElseIf .RunningSum <> 0 Then
- st1 = "作为第二个参数的文本框的RunningSum属性必须是0!"
- End If
- End With
- If Len(st1) > 0 Then
- MsgBox st1, vbExclamation, "参数错误"
- Exit Sub
- End If
-
- Set txtRunSum = RunSum
- With txtRunSum
- If .Section <> acDetail Then
- st1 = "作为第三个参数的文本框必须在报表主体节上!"
- ElseIf .ControlSource <> "=1" Then
- st1 = "作为第三个参数的文本框的ControlSource属性必须是""=1""!"
- ElseIf .RunningSum <> 1 Then
- st1 = "作为第三个参数的文本框的RunningSum属性必须是1!"
- End If
- End With
- If Len(st1) > 0 Then
- MsgBox st1, vbExclamation, "参数错误"
- Exit Sub
- End If
-
- If Not (ShowPage Is Nothing) Then Set lblShowPage = ShowPage
-
- End Sub
- Public Sub FormatGroupLevel1Header()
- If txtRunSum = 1 Then blFistPage = True ' 为页面页脚Format事件作标记
- End Sub
- Public Sub FormatPageFooter()
- Dim inGrpPage As Integer ' 组页码
- Dim inGrpPages As Integer ' 组页数
- Dim inLastRows As Integer ' 截止当前页,所在组的所有行数
- inLastRows = txtRunSum ' 从文本框获得截止行数
- If inLastRows = 0 Then inLastRows = TxtGrpRows
-
- If MyRpt.Page = 1 Then
- '在第1页初始变量
- If MyRpt.Pages > 0 And MyRpt.Pages = inRptPage Then
- ' 这里已经是第2轮格式化第1页,报表加载时进行两轮格式化,第一轮Pages=0
- Else
- inMaxRows = 0
- End If
- inRptPage = 0
- blPrint = False
- End If
-
- If Not blPrint Then
- '仅在第1轮格式化中,获取每组第一页的行数
- If blFistPage Then
- '每组第一页的行数即是本组任一页的最大行数
- If inMaxRows < inLastRows Then inMaxRows = inLastRows
- blFistPage = False
- End If
- inRptPage = inRptPage + 1
- End If
-
- If MyRpt.Pages > 0 Then
- inGrpPages = Int(TxtGrpRows / inMaxRows + 0.9999) ' 组的总行数除以1页的行数,得到组的页数
- inGrpPage = Int(inLastRows / inMaxRows + 0.9999) ' 截止当前页的累计行数除以1页的行数,得到当前页的页码
- If Not (lblShowPage Is Nothing) Then
- lblShowPage.Caption = inGrpPage & " / " & inGrpPages
- End If
- RaiseEvent Current(inGrpPage, inGrpPages)
- End If
- End Sub
- Public Sub PrintPageFooter()
- blPrint = True
- End Sub
复制代码 |
|