現在Access VBAの勉強をしています。教材はオデッセイコミュニケーションズ社の「VBA エキスパート 公式テキスト Access VBA ベーシック」を使用しています。Formatイベントのところが全然分からないので、質問させていただきたいです。
■コード部分
Private Sub グループヘッダー_Format(Cancel As Integer, FormatCount As Integer)
Me.PrintSection = False
End Sub
Private Sub ページヘッダーセクション_Format(Cancel As Integer, FormatCount As Integer)
Me.改ページ.Visible = False
Me.カウント.Value = 0
End Sub
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
If Me.単価.Value >= 10000 Then
Me.詳細.BackColor = vbYellow
Else
Me.詳細.BackColor = vbWhite
End If
If Me.カウント.Value = 10 Then
Me.改ページ.Visible = True
Else
Me.改ページ.Visible = False
End If
Me.カウント.Value = Me.カウント.Value + 1
End Sub
そして、以下のように解説が書かれています。
■解説部分
*上のコードは、まずグループヘッダーのFormatイベントで、PrintSectionプロパティにFalseを設定しています。これにより印刷時にはグループヘッダーが印刷されなくなります。
次に、ページヘッダーセクションのFormatイベントで、詳細セクションに配置された[改ページ]コントロールのVisibleプロパティをFalseに、[カウント]テキストボックスの値を0に設定しています。
詳細セクションのFormatイベントで、[単価]フィールドが10000以上のレコードは、背景色を黄色に設定しています。さらに、[カウント]テキストボックスの値が10のとき、改ページコントロールのVisibleプロパティをTrueにしてレポートを改ページさせています。*
分からないのは以下の5点です。
①ページヘッダーセクション_Formatイベントで、詳細セクションに配置された[改ページ]コントロールのVisibleプロパティをFalseにする理由は何ですか?
②また、[カウント]テキストボックスの値を0にする理由は何ですか?
③さらに、詳細セクションに配置されている[改ページ]コントロールの設定を、ページヘッダーセクション_Formatに記述する理由は何ですか?
④同様に、グループヘッダーに配置されている[カウント]テキストボックスの設定を、ページヘッダーセクション_Formatに記述する理由は何ですか?
⑤[単価]フィールドが10000以上のレコードは、背景色を黄色に設定されるはずですが、参考書の通りにコードを入力しても、一部(商品コード:S001、S004)が黄色に設定されません。何が考えられますか?
①と②は、ただ単に初期化しているということなのですかね?
③と④は、詳細セクションに書いてしまうと、レコードを1行1行参照するたびに[カウント]テキストボックスの値が0になってしまうからという認識で正しいでしょうか?ただその理論で行くと、レポートヘッダーに書いても良さそうですが、そこに記述すると改行がされませんでした。何故なのでしょうか?
⑤は、自己解決しました。プロパティシートにて、詳細セクションの[書式]タブの、[代替の背景色]に、「#FFFFFF」が設定されていて、それを「色なし」にすると解決しました。[代替の背景色]=「詳細セクションの偶数行のレコード」が強制的に白色に塗られてしまっていたようです(商品コード:S001、S004は偶数行のレコード)。これは、VBAでのBackColorに対する命令より、プロパティシートの代替の背景色の設定の方が優先されるということなのですかね?
ご教示のほどよろしくお願いいたします。
※レポートのデザインビュー(コントロール名付き)、元のテーブルのスクリーンショットを添付いたします。※必要であれば.accdbファイルを上げることも可能です。
その教材はみたことないのでコードからの推測です。
プレビュー時でも印刷時でもグループヘッダーは出力されませんね。
何のためにしているのかはわかりません。グループヘッダーの「可視」プロパティを「いいえ」にしても同じことのような気がします。
詳細セクションの[改ページ]コントロールがTrueだとレコード毎(1行毎)に改ページされてしまうからです。
これらのコードでやっていることは、10レコード(10行)毎に改ページするということだと推測します。
(教材に目的が書いてありますよね。)
下記の点を理解することが必要ですね。
ページヘッダーセクションのフォーマット時イベントはページが出力される一番最初に1回発生してヘッダーを出力する。
詳細セクションのフォーマット時イベントはレコード毎に発生して1行分出力する。
つまり、
最初にページヘッダーのフォーマット時イベントが発生してヘッダーが出力される。
そのときに、改ページを非表示にして1行毎に改ページしないようにする。
「カウント」テキストボックスは現在1ページ内で何行目かを取得するものなのでまずは初期化しておくす。
詳細セクションのフォーマット時で「カウント」の数値にプラス1をする。これによって現在、1ページ内で何行目を出力するのが分かる。
その数値が10なら10行目ということなので、改ページを表示させることで改ページして次のページに移動する。
ということです。
⑤に関してはその理解であってます。
レポートのイベントの発生メカニズムはかなり複雑です。
下記がその理解を深めるのに役立つと思いますので一度目を通しておくことをお勧めします。
レポートのイベントの発生メカニズムの研究 - hatena chips
レポートのイベントの発生メカニズムの研究 その2 - hatena chips
「代替の背景色」とは何ぞや?という話なんですが、英語でプロパティ名をみると「Alternatebackcolor」となってます。「Alternate」には「代わりの~」という意味があるのでそれをもって「代替の背景色」と日本語を充てることはできますが、「交互の~、1つおきの~」という意味を使うべき案件ですね。つまり「偶数行の背景色」を設定するプロパティなわけです。
結果からしたら認識されている通りで構わないんですが、偶数行なら通常の背景色(BackColor)よりも代替の背景色が優先されるので「[代替の背景色]に、「#FFFFFF」が設定されて」いるとVBAであろうとなかろうとBackColorを変更しても影響が出ない状態になってるよ、ということです。
VBAの命令「
Me.詳細.BackColor =
」は実際に色を塗る作業をしているわけではありません。背景色プロパティの値を変えているだけだと理解できると「じゃあ、実際に色を塗るタイミングでは何が起きているのか(偶数行だから代替の背景色が使われているな)」とつながると思います。hatenaさん
解説ありがとうございます。解説を基に色々コードをいじって確認してみました。
整理しますと自分の疑問点は結局以下に集約されます。
①[改ページ]コントロールのVisibleプロパティをFalseにする理由
②[改ページ]コントロールに関する設定を、ページヘッダーセクションに記述する理由
③[カウント]テキストボックスの値を0にする理由
④[カウント]テキストボックスの設定を、ページヘッダーセクションに記述する理由
①をTrueに設定してみました。確かにレコード毎に改行されてしまいました。だからFalseに設定する。ただ、この記述自体、Me.改ページ.Visible = Falseを無くしてしまっても問題無く動作します(10行毎にちゃんと改行される)。にも関わらず、わざわざ書く理由は可読性を考慮しているからなのですかね?
②に関しては、詳細セクションに記述してもきちんと動作しました。ただ、
との事ですから、レコードの数だけVisible = Falseを設定することになり、明らかに冗長な処理となることから、ページ毎に1回だけイベントが発生するページヘッダーセクションに記述するのが合理的という解釈で良いのですかね?
③に関しては、Me.カウント.Value = 0をコメントアウトすると、改行がされませんでした。イミディエイトウィンドウで値を確認してみるとNull値が入ってしまいカウントアップが働いていませんでした。なので初期化は必須ということが分かりました。ただ、この手の変数の設定は初期化を省略した場合、自動的に0が設定されて問題無く動くような気がしたのですが、この認識自体間違いですかね?例えば、以下のコードだと0が返ります。
④は、詳細セクションに記述してしまうとレコード毎に毎回最初に0がセットされてしまい、カウントが1以上から先に進まないことが確認できました。故にページヘッダーセクションに記述する必要があると理解出来ました。
以上より、①~③はまだ少しモヤモヤしています。ご回答いただけると幸いです。
hirotonさん
丁寧に解説ありがとうございました。
考えられている通り、詳細_Format側を弄ればいいんじゃないかなと思います
初期化処理については、VBAで
Dim i As Long
とした場合は変数宣言のルールによりiには0が入っていますが、今回はフォーム上に[カウント]テキストボックスを設置していますので、フォーム上のコントロールの設定(規定値プロパティ)に従ってMe![カウント]
の値はNull
になっているのだと思います。VBAの初期化を使いたいのならモジュール先頭でのように変数を用意すればいいと思います。
また、データ件数が10件を超える場合、2ページの描画処理に入ったタイミング(のページヘッダー)で行数カウントをリセットしないと2度と
Me.カウント.Value = 10
がTrue
になることがないので困ったことになります。(このコードなら20件までは問題ないように動きますが)今回の件では変数の初期値自体は二の次の話ですね。
hirotonさんが丁寧に解説されているので、感想だけ。
確かに冗長な部分があるコードだと思います。
行数をカウントするのに変数を使わずにテキストボックスを使うとか。
改ページをコントロールするのも、改ページコントロールの可視を変更するというのも、私は使いません。
改ページコントロールの位置が最下部からずれると想定外の動作になったりするので。
ForceNewPageプロパティで改ページを制御しますね。
前にACCESS本体をバージョンアップしたらなんかおかしくなったってのを見たことがありますが、セクション最下部に置いた改ページコントロールの下に隙間ができるようになったってのがありました。
2ページ目以降なぜか最上部にわずかな隙間ができて、ページごとの合計がどうも1行分ずれているらしいというのでいろいろ見ていたら前のページの最終行が次のページの先頭の行として重複するようになったって感じでした
今回の例題はセクションの最上部に改ページがあるタイプなので同様の問題が起こることはなさそうですが、行単位で制御したいなら改ページコントロールを使うことにいいことはなさそうですね
hirotonさん
ありがとうございます。ほぼ疑問は解消出来たと思います。
色々とコードまで例示くださり、大変分かり易かったです。
初期値のところは知識の整理になりました。
標準モジュールでの変数宣言とフォーム上のコントロールの値の設定は、初期値を明示的に設定しなかった場合ルールが異なるということですね。
hatenaさん
こちらの掲示板をご案内いただきありがとうございました。
Access、AccessVBAはほぼ初心者に近いのでまた質問させていただく機会があるかと思います。その時はまたよろしくお願いいたします。
ありがとうございました。