【実務・中級編】フォームの「Control.SetFocus」エラーを回避する、安全なフォーカス移動の設計 – Access VBA解析バイブル

スポンサーリンク

Access VBAの「SetFocus地獄」を終わらせる:堅牢なUI制御の極意

Accessで業務アプリを組んでいると、必ず一度は遭遇する壁がある。それが「実行時エラー 2110:このコントロールにフォーカスを移動することはできません」だ。

「なぜ動くはずのコードが落ちるのか?」と悩む時間は、エンジニアにとって最も生産性の低い浪費だ。非表示のコントロール、使用不可(Enabled=False)のフィールド、あるいはフォームが閉じられた後のイベント発火……。これらを場当たり的に `On Error Resume Next` で誤魔化すのは、自ら時限爆弾を埋め込んでいるに等しい。

真のアーキテクトは、エラーを握りつぶすのではなく、「安全に移動できる状態か」を確約する設計を好む。今回は、あなたのAccessアプリを一段上の安定感へ導く、極限のフォーカス制御術を伝授する。

なぜ「直書き」が失敗を招くのか

多くの初心者は、フォームのイベント内に直接 `Me.txt_Input.SetFocus` と書いてしまう。しかし、Accessのフォームは動的なオブジェクトだ。

  • 状態の変化: 権限やロジックによって `Enabled` や `Visible` がリアルタイムに切り替わる。
  • イベントの競合: フォーカスが未確定の状態で別の処理が割り込む。

これを回避するには、「SetFocusの実行権限」を抽象化し、関数に委譲するのが鉄則だ。

堅牢性を担保する:SafeSetFocus関数

以下は、私がプロジェクトの共通モジュールで必ず定義する「安全なフォーカス移動関数」だ。単なるエラー回避ではなく、「移動が可能か」を判定してからアクションを起こす、というガード節の思想に基づいている。

‘ —————————————————————————–
‘ 機能:指定したコントロールに安全にフォーカスを移動する
‘ 引数:ctrl – 移動対象のコントロールオブジェクト
‘ 戻り値:成功した場合はTrue、失敗した場合はFalse
‘ —————————————————————————–
Public Function SafeSetFocus(ByRef ctrl As Control) As Boolean
On Error GoTo Err_Handler

‘ 1. オブジェクトが有効かチェック
If ctrl Is Nothing Then Exit Function

‘ 2. 物理的にフォーカスを受け取れる状態かを確認
‘ Visible = False または Enabled = False の場合はスキップ
If ctrl.Visible And ctrl.Enabled Then
ctrl.SetFocus
SafeSetFocus = True
End If

Exit Function

Err_Handler:
‘ 予期せぬエラー(フォームが閉じた直後など)も握りつぶさずログに出力すべきだが、
‘ アプリを止めないことを優先し、ここではFalseを返して制御を戻す
Debug.Print “Focus Error: ” & Err.Description
SafeSetFocus = False
End Function

この設計の肝

  • `ByRef Control` の採用: フォーム固有のコントロールを汎用的に受け取る。これにより、コードの再利用性が飛躍的に向上する。
  • ガード節による判定: 「移動できる状態か?」を事前にチェックする。`Visible` と `Enabled` を個別に確認することで、エラーの発生源を物理的に遮断している。

実務での活用シーン:マスタ登録画面の例

例えば、保存ボタンを押した後に「入力欄の先頭に戻したい」という要件があった場合、以下のように記述する。

Private Sub btn_Save_Click()
‘ データ更新処理(省略)

‘ 先頭の入力項目へ安全に戻る
If Not SafeSetFocus(Me.txt_ItemCode) Then
‘ 必要に応じて、フォーカスを移動できなかった場合の警告をここに書く
MsgBox “入力項目が非表示のため、フォーカスを移動できませんでした。”, vbExclamation
End If
End Sub

プロフェッショナルへの道:さらなる高みへ

このコードを使いこなす段階に至ったなら、次の視点を持ってほしい。

1. データベース連携とUIの関係:
`CurrentDb` での直接的なデータ更新とUI上のフォーカス移動を混同してはならない。データ更新処理はビジネスロジック層に分離し、UIの制御はプレゼンテーション層として分離する。これにより、コードの保守性は劇的に向上する。

2. イベントの連鎖を断つ:
`AfterUpdate` イベントで `SetFocus` を使うのは、無限ループの温床だ。どうしても必要な場合は、`Screen.ActiveControl` を利用して動的に判断するか、あるいはUI設計そのものを見直すべきだ。

結びに代えて

Accessは古臭いツールではない。オブジェクトモデルを正しく理解し、そのライフサイクルを制御下に置くことができれば、これほど高速に業務ツールを構築できる環境は他にない。

「動けばいい」コードから「壊れない」コードへ。あなたが書くその1行が、現場の運用担当者のストレスを確実に減らす。その責任と誇りを持って、設計を突き詰めてほしい。

質問があればいつでも歓迎する。だが、まずはこの `SafeSetFocus` を自分のツールに組み込み、エラーログから「2110」の文字を消し去ることから始めてくれ。

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