さて、残す項目もとりあえずあと1個です。ボタンをクリックしたときの動作が設定されているのですが、これがどのような処理で定義されるのかを見てみましょう。
ボタンをクリックしたときの処理
これまでフォームのプロパティを表示して埋め込まれたVBAを見てみました。今回はボタンに設定されたモジュールを見てみます。見方は基本的に同じで、デザインビューの状態からボタンをダブルクリックします。
プロパティが表示されたらイベントタブをクリックして「クリック時」の動作を見てみましょう。すると
=HandleButtonClick(1)
というふうに記載されているのがわかります。これが何を意味するかというと「フォーム内で定義された関数を引数:1で実行するよ」といったところでしょうか。ではこの関数、一体どうやって定義されたんでしょ?
フォームに埋め込まれた関数
この関数がどこで定義されているかというと、前回まで見てきたVBEの画面で見ることができます。
アクセスを起動した状態で「Alt + F11」キーを押すとVBEが起動します。クラスオブジェクトの「Main Switchboard」をダブルクリックすると
Private Function HandleButtonClick(intBtn As Integer)
で始まる記述があると思います。
この「Private Function~」以下の記述こそ、フォーム内で定義できる関数なんです。
余談ですが、Privateなので文字通りフォーム内でのみ有効な関数となっており、標準モジュール内などで「Public Function ~」と定義すればMDB内のどこからでも呼び出せる自作の関数が作成できます。
この関数の概要は
- クリック時の動作に番号を付与し、定数として宣言する
- Switchboard ItemsテーブルのデータをADOレコードセットとして取得
- レコードセット内のCommandレコードの値によって動作を選択して実行
という流れになります。それでは順番にコードを読んでいきましょう。
宣言セクション
まずは関数名:HandleButtonClick(intBtn As Integer) と定数の宣言から。
Private Function HandleButtonClick(intBtn As Integer)
' This function is called when a button is clicked.
' intBtn indicates which button was clicked.
' Constants for the commands that can be executed.
Const conCmdGotoSwitchboard = 1
Const conCmdOpenFormAdd = 2
Const conCmdOpenFormBrowse = 3
Const conCmdOpenReport = 4
Const conCmdCustomizeSwitchboard = 5
Const conCmdExitApplication = 6
Const conCmdRunMacro = 7
Const conCmdRunCode = 8
Const conCmdOpenPage = 9
' An error that is special cased.
Const conErrDoCmdCancelled = 2501
1行目で関数名を定義したのち、Const~で動作ごとの番号を定義しています。例えば・・・
- 別のメニューに移動するのは「1」
- フォームを追加モードで開くのは「2」
- フォームを編集モードで開くのは「3」
- レポートを開くのは「4」
- メニューの編集は「5」
- アプリケーションの終了は「6」
- マクロを起動するのは「7」
- モジュールの読み込みを行うのは「8」
- データアクセスページを開くのは「9」
という具合に設定されています。実際に使うなら、使用する機能以外は削除するのもアリではないでしょうか?
レコードセットを作成
前回に引き続きADOレコードセットを取得します。
Dim con As Object
Dim rs As Object
Dim stSql As String
On Error GoTo HandleButtonClick_Err
' Find the item in the Switchboard Items table
' that corresponds to the button that was clicked.
Set con = Application.CurrentProject.Connection
Set rs = CreateObject("ADODB.Recordset")
stSql = "SELECT * FROM [Switchboard Items] "
stSql = stSql & "WHERE [SwitchboardID]=" & Me![SwitchboardID] & " AND [ItemNumber]=" & intBtn
rs.Open stSql, con, 1 ' 1 = adOpenKeyset
' If no item matches, report the error and exit the function.
If (rs.EOF) Then
MsgBox "There was an error reading the Switchboard Items table."
rs.Close
Set rs = Nothing
Set con = Nothing
Exit Function
End If
ADOを利用してSwitchboard Itemsの値をレコードセットに格納しています。データが空の場合エラーメッセージを返して関数を終了するように設定されていますね。
具体的には「現在のメニュー画面が保持しているSwitchboardIDとボタンが保持しているItemNumberに該当するデータを抽出しています。つまり、テーブルの中からクリックしたボタンに該当する行を抜き出して、そのデータに該当するCommand列の値を取得するのが目的です。
Commandに格納された値によって処理を分岐
Select Case ~ End Selectによって処理を分岐します。
条件になるのはレコードセットに格納されたCommandフィールドの値です。
Select Case rs![Command]
' Go to another switchboard.
Case conCmdGotoSwitchboard
Me.Filter = "[ItemNumber] = 0 AND [SwitchboardID]=" & rs![Argument]
' Open a form in Add mode.
Case conCmdOpenFormAdd
DoCmd.OpenForm rs![Argument], , , , acAdd
' Open a form.
Case conCmdOpenFormBrowse
DoCmd.OpenForm rs![Argument]
' Open a report.
Case conCmdOpenReport
DoCmd.OpenReport rs![Argument], acPreview
' Customize the Switchboard.
Case conCmdCustomizeSwitchboard
' Handle the case where the Switchboard Manager
' is not installed (e.g. Minimal Install).
On Error Resume Next
Application.Run "ACWZMAIN.sbm_Entry"
If (err <> 0) Then MsgBox "Command not available."
On Error GoTo 0
' Update the form.
Me.Filter = "[ItemNumber] = 0 AND [Argument] = 'Default' "
Me.Caption = Nz(Me![ItemText], "")
FillOptions
' Exit the application.
Case conCmdExitApplication
CloseCurrentDatabase
' Run a macro.
Case conCmdRunMacro
DoCmd.RunMacro rs![Argument]
' Run code.
Case conCmdRunCode
Application.Run rs![Argument]
' Open a Data Access Page
Case conCmdOpenPage
DoCmd.OpenDataAccessPage rs![Argument]
' Any other command is unrecognized.
Case Else
MsgBox "Unknown option."
End Select
' Close the recordset and the database.
rs.Close
このように処理を分岐して該当する動作を実行した後レコードセットを閉じて処理が終了となります。
お片づけ
以下は宣言した変数の初期化とエラー時の処理及び関数の終了を明記しています。
HandleButtonClick_Exit:
On Error Resume Next
Set rs = Nothing
Set con = Nothing
Exit Function
HandleButtonClick_Err:
' If the action was cancelled by the user for
' some reason, don't display an error message.
' Instead, resume on the next line.
If (err = conErrDoCmdCancelled) Then
Resume Next
Else
MsgBox "There was an error executing the command.", vbCritical
Resume HandleButtonClick_Exit
End If
End Function
まとめ
いかがでしょうか?VBAに慣れた人であれば特別難しいことはないんでしょうが、自分のように独学でVBAの知識も薄かったりすると「何をどうしたらこんな処理になるんだ!?」というような感じではないでしょうか?
このままでも十分使えそうな感じがしますが、お仕事で使用するシステムなどであればボタンを増やしたり必要な処理を追加したり逆に不要な処理を削ったりすることで更に使い勝手の良いメニュー画面が構築できそうですね。
ということでこのフォームの構造を根幹にしつつ自分でメニュー画面を一から作成してみようと思います。