【入門編】DAOのRecordsetCloneとブックマーク:サブフォームとの同期を完璧に制御するUI操作の極意 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

「指先」を制御せよ:RecordsetCloneとBookmarkで実現する、完璧なUI同期の極意

こんにちは。Access VBAの深淵へようこそ。

マクロの記録から一歩踏み出し、「自分の手でプログラムを動かしたい」と願うあなた。その意欲こそが、素晴らしいエンジニアへの第一歩です。

Accessの開発を進めていると、必ずと言っていいほど直面する壁があります。それは「ユーザーの操作感(UI/UX)をどうコントロールするか」という問題です。

例えば、「メインフォームで顧客を選択したら、サブフォームのデータも瞬時にその顧客のレコードへ移動してほしい」といった要望。これ、実は「リンク親フィールド/リンク子フィールド」の設定だけで解決する場合もありますが、より複雑な条件や、高度な検索結果を表示したい場合には、標準機能だけでは限界が来ます。

そこで登場するのが、DAO(Data Access Objects)の真髄である「RecordsetClone」と「Bookmark」です。

今日は、この2つの武器を使いこなし、メインフォームとサブフォームの選択行を完璧に同期させる「極限のUI制御」を伝授しましょう。ここをクリアすれば、あなたのAccessアプリは「ただのツール」から「プロ仕様のシステム」へと昇華します。

1. 概念の理解:影(Clone)と栞(Bookmark)

コードを書く前に、まずは頭の中に「イメージ」を作ってください。ここを飛ばすと、後で必ず迷子になります。

RecordsetClone(レコードセット・クローン)とは?

一言で言えば、「現在表示されているデータの『影(分身)』」です。

通常、フォーム上のレコードを移動すると、ユーザーが見ている「表示位置」が変わってしまいます。しかし、`RecordsetClone`を使えば、「画面上の表示位置は変えずに、裏側でこっそりレコードを検索したり、移動したりする」ことが可能になります。

Bookmark(ブックマーク)とは?

これは、「特定のレコードに付けられた『魔法の栞(しおり)』」です。

「5番目のレコードに移動せよ」という命令は、レコードが削除されたり並べ替えられたりすると、すぐにズレてしまいます。しかし、「このブックマークが付いている場所に移動せよ」という命令であれば、データの状態が変わっても、正確にそのレコードを指し示すことができます。

2. 実装:メインとサブを同期させる黄金のパターン

では、具体的なシナリオを想定しましょう。
「メインフォーム(顧客一覧)で選択したレコードに合わせて、サブフォーム(注文履歴)の特定のレコードへカーソルを移動させる」という処理です。

※ここでは、メインとサブが同じデータソース、あるいは密接に関連したデータセットであることを前提とします。

実装コード例

メインフォームのモジュールに記述するコードです。

Option Compare Database
Option Explicit

''' <summary>
''' メインフォームのレコードが移動したときに発生するイベント
''' </summary>
Private Sub Form_Current()
    On Error GoTo ErrorHandler

    ' 1. サブフォームのオブジェクトを確認
    ' ※「ChildSubform」は、メインフォーム上に配置したサブフォームの「コントロール名」です
    Dim subFormCtrl As Control
    Set subFormCtrl = Me.ChildSubform

    ' 2. サブフォームが読み込まれていない、またはレコードがない場合は終了
    If subFormCtrl.Form.Recordset.RecordCount = 0 Then Exit Sub

    ' --- ここからが同期の核心 ---

    ' 3. メインフォームの「影(Clone)」を使って、同期したいレコードを探す
    ' ※ここでは例として、メインとサブが同じIDを持つレコードを同期させるロジックを想定
    Dim rsClone As DAO.Recordset
    Set rsClone = Me.RecordsetClone

    ' 4. サブフォーム側のレコードセットを操作する
    ' メインフォームの現在のIDを使って、サブフォーム側で一致するレコードを探す
    ' ※直接Bookmarkを渡すのは同じRecordsetの場合のみ。
    ' 異なるテーブルの場合は、ID(主キー)を用いて検索するのが定石です。
    
    Dim targetID As Long
    targetID = Me.CustomerID ' メインフォームの主キー

    ' サブフォームのレコードセットを操作するために、サブフォームのRecordsetを取得
    Dim rsSub As DAO.Recordset
    Set rsSub = subFormCtrl.Form.Recordset

    ' 5. サブフォーム内で一致するIDを探し、見つかったらBookmarkを適用する
    rsSub.FindFirst "[CustomerID] = " & targetID

    If Not rsSub.NoMatch Then
        ' 見つかった場合、サブフォームの表示位置をそのレコードへ移動
        subFormCtrl.Form.Bookmark = rsSub.Bookmark
    Else
        ' 見つからない場合は、サブフォームの先頭へ(あるいは何もしない)
        ' subFormCtrl.Form.GoToRecord , acFirst
    End If

    ' 後片付け
    Set rsSub = Nothing
    Set rsClone = Nothing

ExitProcedure:
    Exit Sub

ErrorHandler:
    ' ユーザーにエラーを知らせる(本番環境ではログ出力などが望ましい)
    MsgBox "同期処理中にエラーが発生しました: " & Err.Description, vbCritical
    Resume ExitProcedure
End Sub

3. アーキテクトの視点:なぜこの書き方なのか?

ここで、単なる「動くコード」ではなく、「なぜこう書くのか」という本質的な理由を解説します。

なぜ `Me.RecordsetClone` なのか?

もし、`Me.Recordset`(直接のレコードセット)を操作して検索を行ってしまうと、ユーザーが今見ている画面のカーソルまで勝手に動いてしまいます。 ユーザーからすれば「えっ、勝手に画面が飛んだ!」というストレスになります。
`RecordsetClone`(影)を使うことで、ユーザーの視界を邪魔せずに、裏側で静かに計算・検索ができるのです。

なぜ `Bookmark` を使うのか?

`rsSub.FindFirst` でレコードを見つけた後、そのレコードへ移動させるために `subFormCtrl.Form.Bookmark = rsSub.Bookmark` としています。
これは、「検索で見つけた位置(栞)」を、「サブフォームの表示位置(栞)」にコピーしている作業です。これが最も高速で、かつ確実な移動方法です。

4. 陥りやすい「3つの罠」と回避策

初学者が必ずと言っていいほどハマるポイントをまとめておきます。これを知っているだけで、デバッグの時間は半分になります。

罠①:コントロール名とフォーム名の混同

`Me.SubformName.Form.Recordset` と書くとき、`SubformName` は「サブフォームそのものの名前」ではなく、「メインフォーム上に配置された『枠(コントロール)』の名前」である必要があります。ここを間違えると「オブジェクトが必要です」というエラーで止まります。

罠②:データがない時の「NoMatch」

`FindFirst` メソッドを使った際、条件に合うデータが見つからないと、エラーにはなりませんが `NoMatch` プロパティが `True` になります。これを確認せずに `Bookmark` を適用しようとすると、「実行時エラー ‘3021’: カレントレコードがありません」という絶望的なエラーに直面します。
必ず `If Not rsSub.NoMatch Then` のチェックを入れてください。

罠③:型の不一致(数値 vs 文字列)

`rsSub.FindFirst “[ID] = ” & targetID` の部分です。

  • `targetID` が数値なら:`”[ID] = ” & targetID`
  • `targetID` が文字列なら:`”[ID] = ‘” & targetID & “‘”` (シングルクォーテーションが必要!)

これを忘れると、構文エラーでプログラムが止まります。

まとめ:制御の感覚を掴もう

いかがでしたか?

`RecordsetClone` で「影」を操り、`Bookmark` で「位置」を固定する。
この感覚を掴むと、Access VBAの自由度は飛躍的に向上します。

最初はエラーが出るかもしれません。しかし、エラーメッセージはあなたを責めているのではなく、「ここを直せばもっと良くなるよ」と教えてくれているガイドなのです。

「ユーザーの操作を邪魔せず、かつ意図通りに導く」

この哲学を持ってコードを書いてみてください。それが、伝説的なエンジニアへの道です。
応援していますよ。頑張ってください!

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