【テクニカル・上級編】フォームの「KeyPreview」プロパティと「KeyDown」イベントによるショートカットキーの実装 – Access VBA解析バイブル

スポンサーリンク

Access UIの深淵:KeyPreviewで制御する「操作の不可逆な統一感」

多くの開発者がAccessのフォーム開発で陥る罠がある。それは、「各コントロールにイベントを個別に紐付ける」という愚行だ。フォームが複雑化するほど、イベントハンドラは散逸し、保守性は崩壊する。

シニアエンジニアならば、UIの操作性は「中央集権的に制御」すべきであると知っているはずだ。今回は、`KeyPreview`プロパティと`KeyDown`イベントを軸に、アプリケーション全体で一貫した操作感を提供する「ショートカットキー・アーキテクチャ」を構築する。

1. なぜKeyPreviewなのか:イベントバブリングの理解

Accessのイベントモデルにおいて、`KeyPreview`をTrueに設定すると、フォーカスを持つコントロールにキーが到達する前に、フォームがその入力を「横取り」できる。

この特性は単なるショートカット実装以上の意味を持つ。「入力のフィルタリング」と「グローバルな状態監視」の特等席だからだ。個々のテキストボックスでEnterキーの挙動を書き換えるような低次元な実装から脱却し、フォーム層で制御を完結させるのがプロの作法である。

2. 実装:堅牢なショートカット・ディスパッチャー

フォームのコードモジュールに散らかった `If KeyCode = vbKeyF1 Then…` を書くのは今日で終わりにしよう。以下は、拡張性と保守性を考慮したコマンドパターンの雛形だ。

‘ フォームのモジュールに記述
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
‘ 汎用的なショートカット制御のルーター
‘ Shift状態を組み合わせることで、複雑なキーバインドを管理可能

Select Case KeyCode
Case vbKeyF1: Call GlobalCommandHandler(“Help”)
Case vbKeyS
If (Shift And acCtrlMask) > 0 Then
‘ Ctrl + S をインターセプトして保存処理を強制
Call GlobalCommandHandler(“Save”)
KeyCode = 0 ‘ イベントのバブリングを止める(重要)
End If
Case vbKeyEscape: Call GlobalCommandHandler(“Close”)
End Select
End Sub

Private Sub GlobalCommandHandler(Action As String)
‘ アプリケーション全体で共通のインターフェースへ疎結合に橋渡し
Select Case Action
Case “Save”: If Me.Dirty Then Me.Dirty = False
Case “Close”: DoCmd.Close acForm, Me.Name
‘ ここからクラスモジュール等へ処理を移譲する
End Select
End Sub

3. レガシーの深淵:Windows APIとの連携

Access標準のイベントでは検知できない、あるいはより高度なキーフックが必要なケース(例:アプリケーションが非アクティブな状態でのグローバルホットキー)がある。この場合、`GetAsyncKeyState` APIを用いる。

ただし、API使用時のメモリ管理には細心の注意が必要だ。 特にタイマーイベント等と組み合わせる場合、オブジェクトの解放と再生成が正しく行われないと、Accessプロセスは容易にリークする。

If VBA7 Then
Private Declare PtrSafe Function GetAsyncKeyState Lib “user32” (ByVal vKey As Long) As Integer
Else
Private Declare Function GetAsyncKeyState Lib “user32” (ByVal vKey As Long) As Integer
End If

‘ フォームタイマー等で監視する場合の注意点
‘ 不要なタイミングでAPIを叩きすぎないこと。CPUサイクルを無駄に食う。

4. シニアエンジニアへの戒め:アーキテクチャの極意

このアーキテクチャを導入する上で、以下の3点を徹底してほしい。

1. イベントの遮断(KeyCode = 0): 意図しないデフォルト動作を防ぐためには、`KeyDown`イベント内で`KeyCode`をゼロクリアする癖をつけよ。これはWindowsメッセージループに対する最低限の礼儀だ。
2. ビジネスロジックの分離: `GlobalCommandHandler`の中に直接複雑な計算ロジックを書いてはならない。処理は必ず別の「サービス層(クラスモジュール)」へ追い出せ。UI層はあくまで「指示を出す場所」でなければならない。
3. ライフサイクルの管理: `CurrentDb`を多用するな。頻繁に呼び出す場合は、フォームのモジュールレベル変数に保持し、`Form_Unload`イベントで明示的に `Set db = Nothing` を実行せよ。Accessのゴミ溜めのようなメモリ管理を放置してはならない。

結びに

Accessは「古臭いツール」ではない。適切に扱えば、Windows APIと対話し、メモリを制御し、堅牢な業務システムを構築可能な強力な開発基盤だ。

フォームの`KeyPreview`を使いこなすことは、単なるショートカット作りではない。ユーザーの操作という「入力データ」を、開発者が完全に支配下に置くための第一歩なのだ。この知見を胸に、貴方のシステムをより研ぎ澄まされたものにしてほしい。

タイトルとURLをコピーしました