今回はフォーム上のコントロールの形式的検証のうち,未入力のコントロールをチェックするコードを紹介します.フォーム上に入力・選択可能なコントロールとしては以下が挙げられます.
- チェックボックス
- オプションボタン
- コンボボックス
- リストボックス
- テキストボックス
オプションボタンおよびチェックボックスはフレーム内に配置してあるものとし,一つのフレーム内にオプションボタンとチェックボックスは混在していないと仮定しています.
未入力のコントロールを検証する関数を共通化する
フォーム上のコントロールの未入力のチェックは複数のコマンドボタンから共通して呼び出される機能であるため,共通化したほうがコーディングの重複をなくせます.そのため標準モジュールを追加して関数として実装することにします.下記の関数で戻り値を Variant 型にしているのは未入力のコントロール名を文字列型で受けているためです.メッセージボックスを表示する必要がなければ戻り値を Boolean 型にした方がよいでしょう.また Select case 節でコントロールの種類を群別しているため case else 節でコントロール数を減算する処理を追加していますが,If … Then … ElseIf … 節で群別すればその記述は不要になります.
Option Explicit
Function CheckControls(myForm As MSForms.UserForm) As Variant
Dim Ctrl As MSForms.Control
Dim CheckCnt As Long
Dim myCnt As Long
Dim CheckStr As String
CheckControls = False
CheckCnt = 0
myCnt = 0
CheckStr = ""
For Each Ctrl In myForm.Controls
Select Case TypeName(Ctrl)
Case "ComboBox"
If Ctrl.ListIndex -1 Then
myCnt = myCnt + 1
Else
CheckStr = CheckStr & Ctrl.Name & vbCrLf
End If
Case "Frame"
If CheckFrame(Ctrl) Then
myCnt = myCnt + 1
Else
CheckStr = CheckStr & Ctrl.Name & vbCrLf
End If
Case "ListBox"
If Ctrl.ListIndex -1 Then
myCnt = myCnt + 1
Else
CheckStr = CheckStr & Ctrl.Name & vbCrLf
End If
Case "TextBox"
If Ctrl.Text "" Then
myCnt = myCnt + 1
Else
CheckStr = CheckStr & Ctrl.Name & vbCrLf
End If
Case Else
CheckCnt = CheckCnt - 1
End Select
CheckCnt = CheckCnt + 1
Next Ctrl
If CheckCnt = myCnt Then
CheckControls = True
Else
CheckControls = CheckStr
End If
End Function
Function CheckFrame(myFrame As MSForms.Frame) As Boolean
Dim FrmCnt As Long
Dim ChkCnt As Long
Dim OptCnt As Long
Dim tmpCtrl As Control
CheckFrame = False
FrmCnt = 0
ChkCnt = 0
OptCnt = 0
For Each tmpCtrl In myFrame.Controls
Select Case TypeName(tmpCtrl)
Case "CheckBox"
If tmpCtrl.Value Then
ChkCnt = ChkCnt + 1
End If
Case "OptionButton"
If tmpCtrl.Value Then
OptCnt = OptCnt + 1
End If
End Select
Next tmpCtrl
FrmCnt = FrmCnt + 1
If FrmCnt = OptCnt Or FrmCnt
コマンドボタンに関数を呼び出すコードを記述する
フォーム上のコマンドボタンには下記のコードを記述します.If ... Then 節には入力値の検証に合格した際の動作を記述します.
Option Explicit
Private Sub CommandButton1_Click()
If TypeName(CheckControls(Me)) = "Boolean" Then
Else
MsgBox Prompt:=CheckControls(Me) & "上記項目が未入力です", Title:="未入力エラー"
Exit Sub
End If
End Sub
チェックボックスは NULL を取りうる
さて,実はチェックボックスには面白い性質があります.オプションボタンでは TRUE と FALSE の 2 値しか取りませんが,チェックボックスの場合は更に NULL を加えた 3 値の真理値を取ることができます.しかしデータベース設計者にとって NULL は極めて扱いの難しい真理値であり,クエリが予想外の結果を返すことがあるためなるべく NULL を許容すべきではありません.3 値論理は関係モデルにとって急所なのです.TripleState プロパティで 3 値論理を認めるか否か変更できます.既定値は FALSE となっています.一方でオプションボタンにはそのようなプロパティは存在しません.
上記の例文ではフレーム内のチェックボックスやリストボックスの選択肢から最低でも 1 つ選択されている,という前提でチェックをかけています.では,フレーム内ではなくフォーム上にチェックボックスが存在する場合はどうでしょうか.この場合,チェックボックスの値にかかわらず検証はパスします.ですが TRUE か FALSE かを必ず選択させるために 3 値論理を導入するのは行き過ぎかと思います.
3 値論理と選択肢の設定
さらにチェックボックス,リストボックスいずれにも言えることですが,複数選択を許可するということは,どの選択肢も選択しないことをも許容することを意味します.つまり関係モデル上 1:n のリレーションのうち n = 0 も成り立つということです.とは言え,選択肢を注意深く設定することである程度は回避可能です.例えば年齢を 10 歳区分で区切る場合に両端の年代をどのように扱うかや,年収を 100 万円単位で区切る場合に最小群と最大群をどう設定するかなどです.数値で扱えない選択項目の場合,「その他」をどこまで許容するか,慎重に設計しなければなりません.一旦「その他」に放り込まれたデータを後から切り分けて取り出すことは不可能です.必要な項目を網羅した上でこれ以上はどう考えても不要である場合にのみ「その他」とする,つまり漏れがないように選択肢を設定すべきです.
参照:
インターフェースとしてのEXCEL VBAによるユーザーフォーム
Three-valued logic (Wikipedia)
