Chapter 5 モジュールを作る(2)

5-1.標準モジュールを作る
     ・Declarationsセクション
     ・smp_Mainプロシージャ
     ・smp_GetFormListプロシージャ
     ・smp_GetPropListプロシージャ


5-1.標準モジュールを作る

標準モジュールの全体構造図やっとこのサンプルアドインの中心である標準モジュールの説明に入れるようになりました。個々のコードを説明する前に、標準モジュールの全体構造を簡単に説明します。

アドインが起動されると、まずsmp_Mainプロシージャが呼び出されます。これがこのアドインの処理フローのメインとなるもので、この中からさらに同じ標準モジュール内のsmp_GetFormListとsmp_GetPropListの2つのFunctionプロシージャを呼び出します。そして最後にこのsmp_Mainプロシージャを抜けたらアドイン全体の処理が完了します。

それでは、標準モジュールにあるDeclarationsセクションと3つのプロシージャ、それぞれについて説明していきたいと思います。

■Declarationsセクション
ここではエラー処理におけるエラー番号を定数として宣言しています。それぞれのエラーがどんなときに発生するかは以降のプロシージャのコードを参照してください。("Option Explicit"も忘れずに!)
Option Compare Database
Option Explicit

'削除テーブルが存在しないときのエラー
Const ERR_TABLENOTEXIST = 7874  
'フォームが見つからないときのエラー
Const ERR_NOTFINDFORM = 2450
'デザインビューでプロパティを参照できないエラー
Const ERR_CANTPROPREF = 2186



■smp_Mainプロシージャ
サンプルアドインの「スタートアッププロシージャ」です。
Public Function smp_Main()

  On Error GoTo Err_smp_Main

  'フォームの一覧を取得する
  If smp_GetFormList() Then
    'フォーム選択ダイアログを開く
    DoCmd.OpenForm "smp_frmSelectForm", , , , , acDialog
    With Forms!smp_frmSelectForm
      If .OKCancelFlg Then
        'OKボタンがクリックされたときすべてのプロパティを取得
        If smp_GetPropList(.SelectFormName) Then
          'プロパティ一覧のフォームをデータシートで表示
          DoCmd.OpenForm "smp_frmPropList", acFormDS
        End If
      End If
    End With
    'フォーム選択ダイアログを閉じる
    DoCmd.Close acForm, "smp_frmSelectForm"
  End If

Exit_smp_Main:
  Exit Function

Err_smp_Main:
  If Err.Number = ERR_NOTFINDFORM Then
    'フォーム選択ダイアログがフォームの[閉じる]ボタンで
    '閉じられたときはエラーを無視してそのまま終了
  Else
    Beep
    MsgBox Err.Description, vbOKOnly + vbCritical
  End If
  Resume Exit_smp_Main:

End Function


このアドインでは、フォームを選択する"smp_frmSelectForm"で[OK]ボタンがクリックされたときの処理を、そのフォームのクラスモジュールではなくこのsmp_Mainプロシージャで行うようにしています。このプロシージャでは、フォームを開く操作からプロパティ一覧の取得処理まで、サンプルアドインのすべての処理を集中的にコントロールしています。

このプロシージャでは、アドインの起動とともにsmp_GetFormList()プロシージャを呼び出し、カレントデータベース上のすべてのフォームをリストアップします。その処理が正常に返ってきたら、そこで取得されたデータ、つまりフォーム一覧を表示するフォーム"smp_frmSelectForm"を開きます。ここでは"DoCmd.OpenForm"の6ケ目のパラメータに組み込み定数"acDialog"を指定することによって、フォームを「ダイアログ」として開きます。そしてそのダイアログが非表示になるまで待機します。

"smp_frmSelectForm"フォームでOKが押されたかキャンセルが押されたかの判断については、すでに概略説明していますので、ここでは特に説明は要らないでしょう。"smp_frmSelectForm"フォームで[OK]ボタンがクリックされた場合には、そのリストボックスで選択されたフォームのプロパティ一覧を取得します。リストボックスで選択されたフォームは、リストボックスコントロールを直接参照するのではなく、"smp_frmSelectForm"フォームのPublic変数"SelectFormName"から得ます。そしてそのフォーム名を引数として、フォームのプロパティを調べるプロシージャ"smp_GetPropList"を呼び出します。

エラー処理を行うルーチン "Err_smp_Main:" の部分では、もしもダイアログが[OK]または[キャンセル]ボタンではなく、ウィンドウの[閉じる]ボタン(右上の×)で閉じられた場合、"With Forms!smp_frmSelectForm"の部分でエラーとなるので、そのトラップを行います。ここでのエラーはすでに閉じられたフォームを参照しようとするために起こるもので、[OK]または[キャンセル]ボタンがクリックされた場合にはフォームが非表示になるだけで閉じるわけではないので、このエラーは発生しません。



■smp_GetFormListプロシージャ
このプロシージャは、カレントデータベースのフォームの一覧を取得し、テーブル"smp_tblObjList"にその結果を出力します。出力前にはテーブルの既存レコードの削除(実際にはテーブルの再生成)も行います。
Private Function smp_GetFormList() As Boolean
'フォームの一覧を取得する
  Dim dbsCd As Database
  Dim dbs As Object
  Dim aObj As AccessObject
  Dim rst As Recordset

  On Error GoTo Err_smp_GetFormList

  DoCmd.Hourglass True

  DoCmd.SetWarnings False
  '既存テーブルを削除
  DoCmd.DeleteObject acTable, "smp_tblObjList"
  'テーブルを作成する定義クエリーを実行
  DoCmd.OpenQuery "smp_qdefObjList"
  DoCmd.SetWarnings True

  'フォーム一覧をコードDBのテーブルに書き出し
  Set dbsCd = CodeDb
  Set rst = dbsCd.OpenRecordset("smp_tblObjList")

  Set dbs = Application.CurrentProject
  For Each aObj In dbs.AllForms
    With rst
      .AddNew
        !ObjectName = aObj.Name
      .Update
    End With
  Next aObj


  smp_GetFormList = True

Exit_smp_GetFormList:
  rst.Close: Set rst = Nothing
  dbsCd.Close: Set dbsCd = Nothing
  Set dbs = Nothing
  DoCmd.Hourglass False
  Exit Function

Err_smp_GetFormList:
  If Err.Number = ERR_TABLENOTEXIST Then
    '削除テーブルが存在しない時のエラー
    Resume Next
  Else
    smp_GetFormList = False
    Beep
    MsgBox Err.Description, vbOKOnly + vbCritical
    Resume Exit_smp_GetFormList:
  End If

End Function



CurrentProjectオブジェクトの説明図ここでの大きなポイントは、太字で示した "Application.CurrentProject"オブジェクト"For Each...Next"ステートメントです。CurrentProjectオブジェクトはAccess2000から追加されたオブジェクトで、カレントデータベース内のAccessオブジェクト(フォームやレポート、マクロなど)のコレクションを持っています。つまり、このオブジェクトを使うことによって、データベース内にどんなフォームがあるか、あるいはどんなレポートがあるかなどを調べることができるのです。それを具体的に実行しているのが、"For Each...Next" で囲まれた部分です。ここでは、CurrentProjectオブジェクトの持つ"AllFormsコレクション" から、1つずつフォームを"aObj"というオブジェクト変数に取り出し、さらにそこからNameプロパティつまりフォーム名を取得しテーブルに書き出しています。

なおこの操作を行うために、次のような変数、特に"As"の右にある型を宣言していることに注意してください。

  Dim dbs As Object
  Dim aObj As AccessObject



■smp_GetPropListプロシージャ
引数に指定されたフォームのプロパティ一覧を取得するFunctionプロシージャです。その結果は"smp_tblObjPropList"テーブルに出力されます。
Private Function smp_GetPropList(strFormName As String) As Boolean
  Dim dbsCd As Database
  Dim dbs As Database
  Dim rst As Recordset
  Dim frm As Form
  Dim prp As Property

  On Error GoTo Err_smp_GetPropList

  DoCmd.Hourglass True

  DoCmd.SetWarnings False
  '既存テーブルを削除
  DoCmd.DeleteObject acTable, "smp_tblObjPropList"
  'テーブルを作成する定義クエリーを実行
  DoCmd.OpenQuery "smp_qdefObjPropList"
  DoCmd.SetWarnings True

  '指定フォームをデザインビューで開く
  DoCmd.OpenForm strFormName, acDesign
  Set frm = Forms(strFormName)

  'フォームのコントロール一覧をコードDBのテーブルに書き出し
  Set dbsCd = CodeDb
  Set dbs = CurrentDb
  Set rst = dbsCd.OpenRecordset("smp_tblObjPropList")
  '指定フォームのすべてのプロパティを列挙するループ
  For Each prp In frm.Properties
    With rst
      .AddNew
        !PropertyName = prp.Name
        !PropertyValue = CStr(Nz(prp.Value))
      .Update
    End With
  Next prp

  smp_GetPropList = True

Exit_smp_GetpropList:
  '指定フォームを閉じる
  DoCmd.Close acForm, strFormName, acSavePrompt
  rst.Close: Set rst = Nothing
  dbsCd.Close: Set dbsCd = CodeDb
  dbs.Close: Set dbs = CurrentDb
  DoCmd.Hourglass False
  Exit Function

Err_smp_GetPropList:
  If Err.Number = ERR_TABLENOTEXIST Then
    '削除テーブルが存在しない時のエラー
    Resume Next
  ElseIf Err.Number = ERR_CANTPROPREF Then
    'デザインビューでプロパティを参照できないエラー
    rst!PropertyValue = "<参照不可>"
    Resume Next
  Else
    smp_GetPropList = False
    Beep
    MsgBox Err.Description, vbOKOnly + vbCritical
    Resume Exit_smp_GetpropList:
  End If

End Function


フォームのプロパティはフォームが開かれていないと調べることができません。そこでまず、プロパティ値を調べる前に対象フォームを開きます。フォームを開くのは、デザインビューでもフォームビューでも、あるいは非表示でもかまいません。ただ、フォームビューで開くとそのフォームのモジュールに含まれるプログラムも実行されることになりますので、ユーザーの作ったモジュールによってはどんな動作が始まってしまうか分かりません。そこでここではモジュールが実行されることのない「デザインビュー」としてフォームを開くようにします。そして開いたフォームを、フォームのオブジェクト変数である"frm"変数にセットします。

さて、このプロシージャの最も重要なところは、For Each prp In frm.Properties〜Next prp の、フォームのすべてのプロパティを取得するループの部分です。"For Each prp In frm.Properties"の記述は、frmオブジェクトのPropertiesコレクションに含まれるすべてのプロパティを、1つずつプロパティを表す変数"prp"に代入することを意味します。つまり、特定のプロパティ名を指定するのではなく、とにかくフォームが持つプロパティを全部列挙するというものです。このループの中の"prp.Name"の部分では、ループ内の現在のプロパティの名前を取得します。例えば、"Visible"や"Caption"や"Name"などの文字列が得られます。一方、"prp.Value"はそのプロパティの値です。プロパティによってはこの値がNullの場合もありますので、エラーにならないようにNZ関数で置き換えを行います。また、プロパティの値は文字列データの場合も数値データの場合もありますが、ここではすべてCStr関数で文字列に置き換えた上でテーブルに書き込むようにしました。

ところで、プロパティの中にはデザインビューでは取得できないものもあります。例えば、"SelTop"プロパティはレコードセレクタで複数選択されているレコードの先頭のレコード番号を返すプロパティで、フォームの実行時にしか取得できません。このようなプロパティ値を参照しようとするとエラーが発生しますので、ここではその種のエラーをトラップし、"<参照不可>"という文字列をテーブルに書き出すようにしています。

最後に、プロパティを取得し終わったらそのフォームを閉じます。しかし、これは必ずしも必要なわけではありません。もし、フォームのデザインを変更するようなアドインを作る場合には、変更のあったフォームはデザインビューのままにしておいた方がいいかもしれません。また、すべての変更を強制的に保存した方がよいアドインもあるかもしれません。これは作るアドインによって判断すればよいでしょう。


以上で今回のサンプルアドインのフォームやモジュールなど、必要なオブジェクトの作成作業は完了しました。次回では、サンプルアドインのテスト、そして最終形であるMDAへの移行作業を行います。

ページのトップへ

| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved