zoukankan      html  css  js  c++  java
  • Access 报表打印之分组页码实现(轉)

     
    Option Compare Database
    Option Explicit

    '^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    '
    分组报表显示分组页码和页数类模块(方法一)
    '
    '
    功    能:在有分组的报表的每一页上显示组页码和组页数,在预
    '
             览时改变页面设置后仍能正确显示。
    '
    作    者:t小雨(tcl013@126.com)(t小宝)
    '
    版    本:1.1
    '
    创建日期:2008-05-??
    '
    整理日期:2008-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
    '
    '
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    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 NothingThen 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 NothingThen
                lblShowPage.Caption = inGrpPage & " / " & inGrpPages
            End If
            RaiseEvent Current(inGrpPage, inGrpPages)
        End If

    End Sub

    Public Sub PrintPageFooter()
        blPrint = True
    End Sub
     
    方法二:
     
    Option Compare Database
    Option Explicit

    '^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    '
    分组报表显示分组页码和页数类模块(方法二)
    '
    '
    功    能:在有分组的报表的每一页上显示组页码和组页数,在预
    '
             览时改变页面设置后仍能正确显示。
    '
    作    者:t小雨(tcl013@126.com)(t小宝)
    '
    版    本:1.1
    '
    创建日期:2008-05-??
    '
    整理日期:2008-05-30
    '
    补充说明:这个代码是一年前做的,由于实现原理和过程相当复杂,
    '
             当时没有添加注释,已忘得差不多,加上表达能力有限,
    '
             现在勉强添加了不完全的注释,但能依照说明会用就行。
    '
             直接把代码放到报表中也是可以。
    '
             做成类模块只是为了好保存,以后调用方便,但由于在
    '
             类模块中不能使用报表的节的事件,调用起来还是有些
    '
             麻烦,不过总要比直接把代码放在报表简单一点。
    '
    '
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    '实现原理:
    '
     报表加载后:会发生两轮从第1页到最后1页每页的格式化事件,每轮结束后发生一次打印事件,
    '
     在第一轮格式化事件中报表的Pages属性始终为0。最后还会移到第一页。
    '
     重设纸张边距、方向或大小等后也发生类似上述过程,情况相对复杂一点,就不细说了。
    '
     在这些事件中把页码信息保存到数组中,数组元素和报表页数一样,每个元素代表一页的信息。
    '
     移动页后:也会发生一次格式化事件,在这些事件中把数组中页码的信息显示出来。
    '
     上面所说的事件都是页面页脚的事件。

    '报表设计要求:
    '
     很简单,有一个分组字段和页面页脚即可

    '调用方法有2种:
    '
     第1种:
    '
     1、在报表用New关键字声明一个 CreateGroupPage2 类的新实例
    '
     2、在报表的打开事件执行实例的 Init 方法,传入报表、分组字段和用于显示分组页码的标签
    '
     3、在页面页脚的 Format (格式化)事件执行实例的 FormatPageFooter 方法
    '
     4、在页面页脚的 Print (打印)事件执行实例的 PrintPageFooter 方法
    '
     这种方法在显示分组页码的标签上显示效果如 分组字段值: 1 / 2
    '
     在报表中的代码类似下面:

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '  Dim newGroupPage As New CreateGroupPage2
    '
    '
      Private Sub Report_Open(Cancel As Integer)
    '
          newGroupPage.Init Me, Me.类别ID, 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
    '
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


    ' 第2种:
    '
     1、在报表用 WithEvents 关键字声明一个 CreateGroupPage2 类的变量
    '
     2、在报表的打开事件用 Set New 语句创建新实例
    '
     3、在报表的打开事件执行实例的 Init 方法,传入报表、分组字段,不须传入用于显示分组页码的标签
    '
     4、在页面页脚的 Format(格式化) 事件执行实例的 FormatPageFooter 方法
    '
     5、在页面页脚的 Print(打印) 事件执行实例的 PrintPageFooter 方法
    '
     6、在类的 Current 事件过程将事件参数返回的分组页码和页数赋给用于显示的标签
    '
     在报表中的代码类似下面:

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    '  Dim WithEvents newGroupPage As CreateGroupPage2
    '
    '
      Private Sub Report_Open(Cancel As Integer)
    '
          Set newGroupPage = New CreateGroupPage2
    '
          newGroupPage.Init Me, Me.类别ID, 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 newGroupPage_Current(GrpPage As Integer, GrpPages As Integer)
    '
          Me.LplGrpPages.Caption = Me.类别名称 & " 共 " & GrpPages & " 页,第 " & GrpPage & " 页"
    '
      End Sub
    '
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    ' 这种方法在显示分组页码的标签上显示效果是自定义的


    Public Event Current(GrpPage As Integer, GrpPages As Integer)
    '在此自定义事件中可以获取分组页码信息,以便自定义显示页码格式

    Dim MyRpt As Report
    Dim ctrGroup As Control
    Dim lblShowPage As Label

    Dim blPrint As Boolean            ' 是否已经发生页面页脚的Print事件,为避免页面页脚的Format事件中的代码重复运行
    Dim stGroupText As String         ' 分组字段值

    Dim inRptPage As Integer          ' 报表页号
    Dim inGrpPage As Integer          ' 组页号

    Dim ainGrpPage() As Integer       ' 保存组页号的数组,用于显示
    Dim ainGrpPages() As Integer      ' 保存每个组的总页数的数组,用于显示

    Dim ainGrpPageTmp() As Integer    ' 保存组页号的数组,临时
    Dim ainGrpPagesTmp() As Integer   ' 保存每个组的总页数的数组,临时


    Public Sub Init(rpt As Report, Group As Control, Optional ShowPage As Label)
    'rpt      :报表本身,必须
    '
    Group    :用于分组的字段,必须
    '
    ShowPage :用于显示分组页码的标签,可选

        Set MyRpt = rpt
        Set ctrGroup = Group
        If Not (ShowPage Is Nothing) Then Set lblShowPage = ShowPage

    End Sub


    Public Sub FormatPageFooter()

    Dim inShowGrpPage As Integer           ' 显示的组页码
    Dim inShowGrpPages As Integer          ' 显示的组页数
    Dim i As Integer, j As Integer

    If MyRpt.Page = 1 Then
    ' 在第1页初始变量

        If inRptPage > 0 And inRptPage = MyRpt.Pages Then
        ' 报表加载后第一轮格式化完毕发生
            For j = inRptPage - inGrpPage + 1 To inRptPage   ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                ainGrpPagesTmp(j) = inGrpPage                '
            Next                                             '
            ReDim ainGrpPage(1 To inRptPage)                 ' 这一段代码与后面一段代码一样,因为后面无法判断加载完成
            ReDim ainGrpPages(1 To inRptPage)                '
            For i = 1 To inRptPage                           '
                ainGrpPage(i) = ainGrpPageTmp(i)             '
                ainGrpPages(i) = ainGrpPagesTmp(i)           '
            Next                                             '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        End If
        
        inRptPage = 0
        inGrpPage = 0
        stGroupText = ""
        blPrint = False
    End If

    If Not blPrint Then
    '仅在第一轮格式化中获取页位置,保存到临时数组
        inRptPage = inRptPage + 1
        ReDim Preserve ainGrpPageTmp(1 To inRptPage)
        ReDim Preserve ainGrpPagesTmp(1 To inRptPage)
        
        If stGroupText = ctrGroup Then                      ' 当前页与上一页在同一组
            inGrpPage = inGrpPage + 1                       ' 累计本组页数,也即获得当前页在当前组中的页码
        Else                                                ' 当前页与上一页不在同一组,换组
            For j = inRptPage - inGrpPage To inRptPage - 1  ' 循环上一组的每一页
                ainGrpPagesTmp(j) = inGrpPage               ' 每个元素都储存总页数,页在组中的最大序号即总页数
            Next
            inGrpPage = 1                                   ' 重新开始累计本组页数
            stGroupText = ctrGroup
        End If

        ainGrpPageTmp(inRptPage) = inGrpPage                ' 每个元素都储存页在组中的页码
    End If

    If MyRpt.Page = MyRpt.Pages Then
    '报表已打开后重设纸张边距大小方向等会发生
        If inRptPage = MyRpt.Pages Then
        '仅在最后一页把临时数组中的页码信息更新到用于显示页码的数组
            For j = inRptPage - inGrpPage + 1 To inRptPage
                ainGrpPagesTmp(j) = inGrpPage               ' 这个循环代码与上面有重复,因为上面无法判断最后一页
            Next
            
            ReDim ainGrpPage(1 To inRptPage)                ' 数组大小为报表页数
            ReDim ainGrpPages(1 To inRptPage)
            For i = 1 To inRptPage
                ainGrpPage(i) = ainGrpPageTmp(i)
                ainGrpPages(i) = ainGrpPagesTmp(i)
            Next
        End If
    End If

    On Error Resume Next

    If MyRpt.Pages > 0 Then
        inShowGrpPages = ainGrpPages(MyRpt.Page)   '
        inShowGrpPage = ainGrpPage(MyRpt.Page)    '
        If Not (lblShowPage Is Nothing) Then lblShowPage.Caption = _
            ctrGroup & "" & inShowGrpPage & " / " & inShowGrpPages
        RaiseEvent Current(inShowGrpPage, inShowGrpPages)
    End If

    End Sub

    Public Sub PrintPageFooter()
    ' 区分两轮格式化
        blPrint = True
    End Sub
     
     
  • 相关阅读:
    CSS3 渐变 透明 圆角
    使用JSON作为函数的参数(转载)
    如何让输入的单词首字母大写
    mysql 修改表/字段 增加/删除表索引
    Jquery Mobile 客户端验证
    如何写出漂亮的js代码(转载)
    GoogleMap添加一个Marker
    Log4j的使用【转载】
    Google Map 自定义infowindow
    MYSQL重装出现could not start the service mysql error:0处理(已验证可以使用)
  • 原文地址:https://www.cnblogs.com/Tonyyang/p/2256843.html
Copyright © 2011-2022 走看看