今回はフォーム上のコントロールの形式的検証のうち,未入力のコントロールをチェックするコードを紹介します.フォーム上に入力・選択可能なコントロールとしては以下が挙げられます.
- チェックボックス
- オプションボタン
- コンボボックス
- リストボックス
- テキストボックス
オプションボタンおよびチェックボックスはフレーム内に配置してあるものとし,一つのフレーム内にオプションボタンとチェックボックスは混在していないと仮定しています.
未入力のコントロールを検証する関数を共通化する
フォーム上のコントロールの未入力のチェックは複数のコマンドボタンから共通して呼び出される機能であるため,共通化したほうがコーディングの重複をなくせます.そのため標準モジュールを追加して関数として実装することにします.下記の関数で戻り値を 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)