So-net無料ブログ作成

レポート グループごとのページ数・総ページ数を付ける [レポート]

 ACCESSの標準機能では実現できないけど、需要は多い処理の一つだと思います。なのに、MicroSoftはどうして対応してくれないんだろう。ACCESS97の頃、サポート情報に参考プログラムが載っていたので、分かってるはずなのに。

 ACCESSのレポートで、ページ数・総ページ数は、PageとPagesを使うことで表示できます。
 グループごとに出力するレポートの場合、そのグループのページ数、グループの総ページ数も印刷したい場合もあると思います。
 めんどくさいので、私は打ち合わせの時に自分からは言わないようにして対処しています。
 でも、請求書とかはどうしても要るって言われるんですよね。そのときは頑張って実装します。

 グループ毎のページ数、グループ毎の総ページ数、ついでに、全体のページ数、全体の総ページ数を表示する方法を説明します。


 こんな感じのレポートです。

 最初にポイントをひとつ。
 通常、レポートの出力処理は、1ページから順番に最終ページまで行われます。通常は1回で終わります。
 レポートの出力内容に、「Pages」が含まれていると、一度最終ページまで処理を行って、総ページ数を割り出した後、もう一度最初に戻って、再度1ページ目から処理が行われます。
 つまり、2回出力処理が行われます。

 この2回処理が行われるというのを利用して、1回目の処理で、グループ毎のページ数・総ページ数を割り出す処理を行い、2回目はその内容を表示するという構造にします。


 ざっとこんな感じで作ってます。
 レポートヘッダー・レポートフッター、ページヘッダー・ページフッター、グループヘッダー・グループフッターを設けています。
 また、グループ毎に改ページされるように設定してます。
 グループヘッダーは、「セクション繰り返し」を「はい」に設定しています。
 ページフッターに、ちょっと切れてますが、「全体ページ数」の所に、「=[Page] & "/" & [Pages]」を設定して、ここに全体を通してのページ数・総ページ数が表示されるようにしています。

 プログラムは、以下の通り。

Option Compare Database
Option Explicit

Private lngF      As Long    'フォーマットフラグ
Private lngGF     As Long    'グループ終わりフラグ

Private lngGPage  As Long    'グループページカウンタ

Private lngGP()   As Long    'グループページ記録
Private lngGPS()  As Long    'グループページ記録


Private Sub Report_Open(Cancel As Integer)
'1)レポートオープン
 
'初期化
    lngF = 1

End Sub

Private Sub レポートヘッダー_Format(Cancel As Integer, FormatCount As Integer)
'2)
    If lngF = 1 Then
    'グループ終了フラグ初期化
        lngGF = 1
    End If

End Sub

Private Sub グループヘッダー0_Format(Cancel As Integer, FormatCount As Integer)
'3)
    If lngF = 1 Then
       
        'グループ終了なら、グループページ数リセット
        If lngGF = 1 Then
            lngGPage = 1
            lngGF = 0
        End If
       
        '配列にグループページ数を格納
        ReDim Preserve lngGP(Me.Page)
        lngGP(Me.Page) = lngGPage
           
    End If

End Sub

Private Sub グループフッター1_Format(Cancel As Integer, FormatCount As Integer)
'4)
    If lngF = 1 Then
        'グループ終了フラグON
        lngGF = 1
       
        ReDim Preserve lngGPS(Me.Page)
        If Me.FormatCount = 1 Then
            'グループ総ページを配列に格納
            lngGPS(Me.Page) = lngGPage
        Else
            lngGP(Me.Page) = lngGP(Me.Page - 1) + 1
            lngGPS(Me.Page - 1) = 0
            lngGPS(Me.Page) = lngGP(Me.Page)
        End If
   
    End If

End Sub

Private Sub ページフッターセクション_Format(Cancel As Integer, FormatCount As Integer)
'5)
    If lngF = 1 Then
        'グループページ数カウントアップ
        lngGPage = lngGPage + 1
    Else
        'グループページ数/グループ総ページ数
        Me.txtPAGE = lngGP(Me.Page) & "/" & lngGPS(Me.Page)
    End If

End Sub

Private Sub レポートフッター_Format(Cancel As Integer, FormatCount As Integer)
'6)
    Dim lngI As Long
    Dim lngP As Long
   
    If lngF = 1 Then
        'フォーマットフラグを更新
        lngF = 2
       
        'グループ総ページ数配列の空きを埋める
        For lngI = UBound(lngGPS) To 1 Step -1
            If lngGPS(lngI) <> 0 Then
                lngP = lngGPS(lngI)
            Else
                lngGPS(lngI) = lngP
            End If
        Next
   
    End If

End Sub


 まず、冒頭の変数宣言ですが、各セクションのそれぞれのイベントで処理を行うため、モジュールレベルのグローバル変数を使用します。用途はコメントの通り。
 配列のlngGP・lngGPSは、配列の要素番号を通しページ数と対応させて、グループ毎ページ数・グループ毎総ページ数を記録します。
 通しページ数が5ページ目のグループ毎ページ数は、lngGP(5)に格納されている、という具合です。

1)レポートオープン イベント
 レポートをオープンしたときに、最初に1回発生するので、ここで処理の準備をします。
 「lngF = 1」で、1回目の印刷処理であることを示します。

2)レポートヘッダー_Format イベント
 レポートの印刷処理の最初に発生するイベントです。
 1回目と2回目の印刷処理の最初に起こるので、1回目の時のみ、処理の準備をします。
 グループヘッダーの1回目の処理で、初期化処理が行われるように、lngGF(グループ終了フラグ)を設定しておきます。

3)グループヘッダー0_Format イベント
 グループヘッダーがフォーマットされるときに発生するイベントです。
 「セクション繰り返し」が「はい」に設定しているので、前ページで発生します。

 グループが変わったタイミングで、グループ毎ページ数のカウントをリセットします。
 配列の要素数を、ページ数に合わせて増やしながら、現在のグループのページ数を、配列に格納しています。

4)グループフッター1_Format
 グループフッターがフォーマットされるときに発生します。

 グループフッターでは、注意することがあります。
 基本的に、グループの明細出力が終わった後に1回発生するのですが、まれに、2回続けて発生することがあります。
 グループフッターが出力されることで、改ページが発生する場合に、2回イベントが発生するようです。レポートのイベントは複雑なので、必ずそうだとは言い切れないのですが、このレポートに関しては、こういう状況が起起きています。

 1回目のイベントで、グループが終わったという判断をするので、グループ終了フラグを設定して、グループ総ページ数を記録します。
 その後、次のページで、グループヘッダーのイベントが起きて、グループが変わったときの処理が行われます。
 その後に、2回目のグループヘッダーのイベントが発生します。2回目のイベントが、正しいページ位置で発生したイベントになります。
 この状況が起きると、制御のつじつまが合わなくなり、正しいページ数を記録できなくなります。

 そこで、FormatCountプロパティに、何回目のフォーマットなのかが設定されているので、1回目では無い場合は、つじつまを合わせる処理を行います。
 グループ毎ページ数(lngGP)の現在位置には、グループが変わったと判断されて「1」がセットされてしまっているので、実際にはページは続いているので、前回位置のページ数+1にセットし直します。
 グループ毎総ページ数(lngGPS)の前回位置に、グループ毎総ページ数が記録されているので、これを「0」に設定し直して、現在位置にグループ毎総ページ数をセットします。

 レポートでは、ときどき複数回フォーマットイベントが起こることがあるので、注意が必要です。レポートのイベントの発生の仕方はわかりにくいので、こういう処理の時は、入念にテストしたほうが良いです。

5)ページフッターセクション_Format イベント
 各ページの最後に発生します。
 1回目の処理の場合は、グループページ数をカウントアップします。
 2回目の処理では、ページフッターに設置されているテキストボックスへ、ページ数のセットを行います。

6)レポートフッター_Format イベント
 レポートの出力処理が終わった後に発生します。
 1回目の処理の場合に、グループ毎総ページ数(lngGPS)の設定内容を仕上げる処理を行います。

 1回目の処理が終わった直後のlngGPSの内容は、以下のようになっています。

 要素  値 
00
11
20
32
40
52
60
72
80
92
100
112
121
130
142

 各グループの最終ページの位置にしか、総ページ数がセットされていません。
 ですので、ここで、総ページ数がセットされていないページ位置にも、総ページ数をセットしておきます。

 要素  値 
00
11
22
32
42
52
62
72
82
92
102
112
121
132
142

 これで、ページ数で要素を指定すれば、そのページ位置でのグループ毎総ページ数が取り出せます。
 ちなみに、グループ毎ページ数と合わせると、こんな感じの配列になっています。

要素ページ数総ページ数
000
111
212
322
412
522
612
722
812
922
1012
1122
1211
1312
1422

 この配列を作っておくことで、後はPageの値で配列を参照すれば、グループ毎ページ数とグループ毎総ページ数が取り出せます。
 プログラムでPageの設定値をリセットしていないので、通常の全体を通してのページ数・総ページも、そのままPage・Pagesを使用できます。

 このプログラムは、この例ではちゃんとページが出ますが、グループフッターの所でも述べましたが、レポートの構成によりイベントの発生の仕方が変わる可能性があります。
 その場合は正しく表示できなくなりますので、ご了承下さい。



【2万円から3万円の、格安ホームページ作成サービス】

nice!(0)  コメント(2)  トラックバック(0) 

nice! 0

コメント 2

まらいや

こんばんわ!お元気ですか
ADOの排他制御の件でコメント差し上げたものです。
最近になっていよいよシステム作りのスタートに立ったところであります。 SQLサーバも2012になってしまったので、今のうちに2008R2のデペロッパエディションを購入しておきました。

 記載されておられる、グループ毎にページ数を振るというのは結構需要があり、類似ページも結構あるのですが。
 グループ数を必要な単位で改ページしたい!と思い結構さがしたのですが、需要ないようで記事がなく紹介しておきます。
 
 私の場合は、3グループ毎に荷物を分けてコンテナに格納する明細書を発行したかったのですが、グループ単位に分けられるユニークキーがありません。例えば送り先が異なったらグループを分けよう等です。
 
 それで、グループフッターのテキストBOXに”=1”を追加して、フォーマットイベントで、 連番 MOD 3 =0 だったと思うのですが、こいつで改ページコントロールをON、OFFさせました。
 結果は簡単だったんですが、数時間費やして考えちゃいました。涙
 
 グループ毎に改ページさせよう!は山のようにヒットします。指定数で改ページは、需要ないんでしょうかね。笑
by まらいや (2012-06-01 22:51) 

NZ

 お久しぶりです、コメントありがとうございます。

 今回参考になる記事が無かったようですが、ご自分で工夫されて処理を作られたようですね。グループをさらにグループでまとめるような処理なんでしょうか。
 改ページコントロールを使われたようですが、私はあまり使ったことがありません。
 なので、私が考えると、事前にグループの基準となる項目をプログラムで生成しておくとかやりそうです。
 まらいやさんの方法も、参考になりました。ありがとうございます。
by NZ (2012-06-06 07:39) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。
※URL(リンク)は記述できません。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。