こんにちは! Accessでのシステム開発、日々の試行錯誤お疲れ様です。
マクロの記録から一歩踏み出し、「自分でVbaを書いてフォームを自在に操りたい!」そう思ってコードを書き始めたものの、こんな壁にぶぶつかっていませんか?
「フォームにある20個のテキストボックス、すべてに『空欄チェック』と『文字数チェック』を書きたいんだけど……まさか、20個分のコントロールごとに同じようなコードをコピペしなきゃいけないの?」
……もし、あなたがすべてのコントロールの「更新前処理(BeforeUpdate)」やボタンのクリック時に、似たような`If Me.Text1 = “” Then …`を延々と書き連ねているなら、ちょっと待ってください。
今回は、Access VBAの隠れた名優`ActiveControl`プロパティを使い、入力チェックのロジックをたった一つの関数に集約する「スマートすぎる汎用バリデーション構築法」を伝授します。ここをクリアすれば、あなたのVBAスキルは間違いなく中級者の領域に突入しますよ!
—
なぜ個別チェック地獄は不幸を生むのか?
プログラミングの世界にはDRY原則(Don’t Repeat Yourself=同じことを繰り返すな)という鉄則があります。
各コントロールのイベントに直接ロジックを書くアプローチ(個別チェック)には、以下のような致命的なデメリットがあります。
1. コード量が爆発する:フォームの項目が増えるたびにコードが何倍にも膨れ上がる。
2. 仕様変更の地獄:「エラーメッセージの文言を変えて」と言われたとき、20箇所のコードを修正して回るハメになる。
3. バグの温床:コピペミスによる変数の消し忘れや、条件の書き漏らしが必ず発生する。
これを解決するのが、「今、ユーザーが操作しているフォーカス上のコントロール」をピンポイントで掴み取る `Screen.ActiveControl`(または `Me.ActiveControl`)というオブジェクトです。
—
魔法の武器「ActiveControl」とは何か?
`ActiveControl` は、文字通り「現在、画面上でアクティブになっている(=ユーザーがフォーカスを当てている、または操作中の)コントロール」を指し示すオブジェクトです。
これの何が凄いかと言うと、「どのコントロールから呼ばれても、その正体を自動的に判定して処理を使い回せる」という点にあります。
イメージ図で表してみましょう。
[ ユーザーの入力 ]
↓
どのテキストボックス?
(Text1? Text2? MemoBox?)
↓
【 ActiveControl 】 ← こいつが「あ、今回はText1ですね」と動的に特定!
↓
汎用チェック関数へバトンタッチ!
個別のコントロール名を名指しせず、「いま触っているその人!」を抽象化して関数に渡すことで、完全な「汎用バリデーション」が完成するのです。
—
【実践】コピペで動く!汎用バリデーション関数の構築
それでは、実際に現場で使えるコードを見ていきましょう。
今回は、「必須入力チェック」と「最大文字数チェック」を同時にこなすスマートな汎用関数を作ります。
ステップ1:標準モジュール、またはフォームのモジュールに判定関数を置く
まずは、チェックの本体となる汎用関数を書きます。今回はフォームのコードモジュール(または標準モジュール)に以下を記述してください。
‘ =========================================================================
‘ 汎用入力バリデーション関数
‘ 引数:
‘ ctrl – チェック対象のコントロール (ActiveControlを渡す)
‘ isRequired – 必須入力か? (True / False)
‘ maxLength – 最大文字数 (制限なしの場合は 0)
‘ 戻り値:
‘ True = チェックOK, False = エラーあり
‘ =========================================================================
Public Function ValidateControl(ctrl As Control, isRequired As Boolean, Optional maxLength As Long = 0) As Boolean
‘ デフォルトはOK(正常)としておく
ValidateControl = False
‘ 1. 必須チェック
If isRequired Then
‘ Nullまたは長さが0の文字列(””)の場合
If IsNull(ctrl.Value) Or Trim(CStr(ctrl.Value)) = “” Then
MsgBox “「” & ctrl.Tag & “」は必須入力です。”, vbExclamation, “入力エラー”
ctrl.SetFocus ‘ エラーのコントロールにフォーカスを戻す
Exit Function
End If
End If
‘ 2. 最大文字数チェック(値が入っている場合のみ)
If maxLength > 0 And Not IsNull(ctrl.Value) Then
If Len(CStr(ctrl.Value)) > maxLength Then
MsgBox “「” & ctrl.Tag & “」は ” & maxLength & ” 文字以内で入力してください。” & vbCrLf & _
“(現在 ” & Len(CStr(ctrl.Value)) & ” 文字)”, vbExclamation, “文字数オーバー”
ctrl.SetFocus
Exit Function
End If
End If
‘ すべての関門を突破したらTrueを返す
ValidateControl = True
End Function
ここがエンジニアのこだわりポイント!
コードの中に `ctrl.Tag` という見慣れないプロパティが登場しています。
Accessの各コントロールには「プロパティシート」の「その他」タブに「タグ(Tag)」という何にでも使えるメモ欄のようなプロパティがあります。ここに `「顧客名」` や `「メールアドレス」` と日本語名を設定しておけば、エラーメッセージに「『顧客名』は必須入力です」と動的に表示させることができるのです。これがスマートなフォーム設計の極意です。
—
ステップ2:フォームのイベントから呼び出す
では、実際にフォーム上のコントロールでこの関数を呼び出してみましょう。
例えば、テキストボックス `txtCustomerName`(タグに「顧客名」と設定、最大文字数50)の「更新前処理 (BeforeUpdate)」に、以下のように一行だけ書きます。
Private Sub txtCustomerName_BeforeUpdate(Cancel As Integer)
‘ ActiveControlを使って、自分自身を汎用関数に放り込む!
If Not ValidateControl(Me.ActiveControl, isRequired:=True, maxLength:=50) Then
Cancel = True ‘ エラーがある場合は更新をキャンセルする
End If
End Sub
これだけです!
もしフォームにテキストボックスが20個あっても、それぞれの `BeforeUpdate` イベントには `If Not ValidateControl(…) Then Cancel = True` と一行書くだけ。チェックの仕様(エラーメッセージの出し方や判定基準)を変えたくなったら、ステップ1の関数を1箇所修正するだけで、フォーム全体の挙動が一瞬で変わります。
—
陥りやすい罠とエラー回避の知見
中級者がこの手法を実装する際によくハマる「罠」がいくつかあります。プロの知見として共有しておきますね。
1. `Me.ActiveControl` と `Screen.ActiveControl` の違い
- `Me.ActiveControl`: 今コードが動いている「このフォーム(Me)」の中でのアクティブコントロールを指します。基本はこちらを使いましょう。
- `Screen.ActiveControl`: Access全体の中で「今、一番手前でフォーカスを持っているコントロール」を指します。サブフォームや複数ウィンドウがある複雑な構造では、どちらを指しているか曖昧になり予期せぬエラー(実行時エラー 2448 など)を生む原因になります。フォーム内のイベントで使うなら `Me.ActiveControl`(または引数に直接 `Me.コントロール名`)が安全です。
2. データ型がNullのときのトラップ
VBAで `Len(Text1)` や `Text1 = “”` などを直接扱うと、コントロールが未入力(Null)のときに `型が一致しません` や予期せぬ挙動を起こすことがあります。上記のサンプルコードのように `IsNull(ctrl.Value)` であらかじめガードし、`CStr()` で文字列に安全にキャストしてから評価するのが、トラブルを防ぐプロの作法です。
—
まとめ
今回は、`ActiveControl` を活用した汎用入力バリデーションの構築法について解説しました。
- 個別チェック地獄からの脱却:同じコードをコピペするな!
- ActiveControlの活用:今触っている対象を動的につかまえ、関数に丸投げする。
- Tagプロパティの活用:コントロールの「名前」ではなく「日本語の項目名」をTagに持たせてエラーメッセージをリッチにする。
ここをクリアすれば、あなたのAccess開発スピードとコードの美しさは劇的に向上します。「マクロの記録の延長」から「真のVBAエンジニア」へ、また一歩階段を登りましたね。
ぜひ、次の開発案件でこの手法を試してみてください。コードのすっきりさに感動するはずです。それでは、快適なAccessライフを!
