Chapter 4 モジュールを作る(1)

4-1.フォームモジュールを作る
4-2.アドインでのモジュールの留意点
     ・スタートアッププロシージャ
     ・モジュールのメモリ上での扱われ方
     ・プロシージャやPublic変数・定数の命名
     ・データベースのオープン
     ・アドインの終了


4-1.フォームモジュールを作る

フォームの骨組みができたところで、いよいよモジュールの作成に入っていきます。

まず、smp_frmSelectFormフォームです。以下がこのフォームのすべてのコードです。
Public OKCancelFlg As Boolean
Public SelectFormName As String

Private Sub cmdCancel_Click()
'[キャンセル]ボタン
  Me.Visible = False

End Sub

Private Sub cmdOK_Click()
'[OK]ボタン
  OKCancelFlg = True
  SelectFormName = Me!lstObject
  Me.Visible = False
    
End Sub

Private Sub Form_Load()
'フォームが[閉じる]ボタンで閉じられた場合への対処
  OKCancelFlg = False

End Sub

行数は少なくてコーディングは簡単なのですが、プログラムの仕組みは若干分かりづらいかもしれませんね。このフォームを開くコードは標準モジュール側で実行しますが、そちらをまず多少説明する必要があるかもしれません。このフォームを開く部分を抜粋したコードが次のものです。

    DoCmd.OpenForm "smp_frmSelectForm", , , , , acDialog
    If Forms!smp_frmSelectForm.OKCancelFlg Then
      **** ここでOKボタンがクリックされたときの処理を行います ****
    End If

まず1行目でsmp_frmSelectFormフォームをダイアログとして開きます。ダイアログで開いた場合には、そのフォームが閉じられるまで次の行は実行されません。つまり、標準モジュール側ではフォームが閉じられるのをずっと待機している状態になります。そして2行目で、そのフォームでOKボタンが押されたのか、あるいはキャンセルボタンが押されたかを調べ、もしOKボタンだったら所定の処理を実行します。ここでポイントとなるのが、フォームでクリックされたボタンを調べるために、

   Forms!smp_frmSelectForm.OKCancelFlg

という変数を参照している点です。これはsmp_frmSelectFormフォーム内で宣言されたPublic変数を参照していることを意味します。フォームで宣言された変数でも、DeclarationsセクションにPublicで宣言された変数は、他のフォームモジュールや標準モジュールかも参照できるのです。したがって、フォーム側ではOK/キャンセルのどちらのボタンが押されたかを閉じる前にその変数にセットしておく必要があります。

ところで、ダイアログの場合にはそのフォームが閉じられるまで次の行は実行されないといいましたが、実はフォームが完全に閉じられてしまうとフォーム内で宣言されたPublic変数も参照できなくなってしまうのです。そこがもう一つのポイントです。ダイアログでは、閉じたときだけでなく、フォームが非表示つまり[Visible]プロパティが"False"になったときにも同じように次の行に実行ステートメントが移るのです。しかも、その場合にはあくまでもフォームは開いたままですので、Public変数も参照することができます。

以上の説明で、smp_frmSelectFormフォームに書かれたコードの概要は理解できたでしょうか?。以下がそのポイントです。
  • 他のモジュールからの参照用として、DeclarationsセクションにPublicで2つの変数を宣言します。1つは、OK/キャンセルのどちらがクリックされたかを示すブール型変数"OKCancelFlg"(OKのときTrueとします)。もう1つは、フォームのリストボックスで選択されたフォーム名を示す文字列型変数"SelectFormName"です。

  • OKボタンがクリックされたら2つのPublic変数にそれぞれ所定の値をセットして、フォームを非表示にします。

  • キャンセルボタンがクリックされたらそのままフォームを非表示にします。ここではフォームが[閉じる]ボタン(ウィンドウ右上端の×のボタン)で閉じられた場合を考えて、あらかじめ読み込み時イベントプロシージャでOKCancelFlgをFalseにしていますので、そのまま閉じてしまえばFalseが保持された状態となります。
短いコードのわりには説明が長くなってしまいましたが、以上でsmp_frmSelectFormフォームのモジュールについては終わりです。プログラムの内容としては、いかにもアドインというところはまったくありませんでしたね。実際にテストしてみたいところですが、OK/キャンセルどちらを押してもフォームが非表示になるだけですので、後でじっくりテストしてみることにしましょう。

もう一つのフォーム smp_frmPropListフォーム はかなり手抜きをしています。単純にデータシートビューでレコードを表示するだけのものですので、モジュールはいっさい使っていません。

ページのトップへ



4-2.アドインでのモジュールの留意点

smp_frmSelectFormフォームのモジュールでは特にアドインとして注意しなければならないようなコードはありませんでした。しかし一般的なアドインのモジュールでは、これから説明する当サンプルアドインの標準モジュールも含めて、普通のデータベースアプリケーションの開発ではあまり使わないような関数、オブジェクト、コレクションなどがいろいろ出てきます。しかし、それはあくまでも使う必要がないので使っていないだけで、決してアドインだけで使うものというわけではありません。これらのオブジェクトは、どんなアドインを作るかにもよりますが、主にデータベースの内部解析に使うようなものが多いと思います。また、本来はマウス操作だけで済んでしまうようなこと、例えば新規フォームを作るなどのことをプログラムを組んで実行させる場合もあります。ここでは、サンプルアドインの標準モジュールについて実際のコードの説明をする前に、それらのポイントを整理しておきたいと思います。なお、データベースの内部解析については、『Access Study Vol.1 T'sKitでAccess解剖!』が参考になるかもしれません。ただし、こちらはAccess97を対象に記述されていますので、ここで作成するサンプルアドインでは若干異なる部分もあります(おそらく97のコードはそのまま2000でも動作すると思いますが)。


スタートアッププロシージャ

さて、今回作成するサンプルアドインの機能を考えたときに、一番最初に行わなければならない処理は何だと思いますか?。それは、カレントデータベースにあるフォームの一覧を取得することです。そしてそれが完了したら、最初のフォームである"フォーム名を一覧表示するフォーム"を開いて、そこで取得されたデータ、つまりフォーム名を表示するという手順になります。通常であれば、メニューの[ツール]-[起動時の設定]の[フォームの表示]、つまりそのデータベースのスタートアップフォームにそのフォームを指定して、フォームの"読み込み時イベント"で処理するパターンになるところでしょう。しかし、アドインの場合にはこの"スタートアップフォーム"は使うことができません。また"AutoExecマクロ"を使うこともできません。したがって、アドインを起動する際に最初に実行されるプロシージャは、少し特別な扱いをしてやらなければなりません。

まず、その「スタートアッププロシージャ」は標準モジュールに任意の名前で作成します。スタートアップといっても、Visual Basicの"Sub Main()"やC言語の"main関数"のように決められた名前にしなければいけないわけではありません。自由に名前を設定してください。ただし、返り値を持つわけではありませんが、"Functionプロシージャ"として作成しなければなりません。これは後で説明しますが、ちょうどフォームのコントロールの[コントロールソース]プロパティやクエリーの演算フィールドで関数を使うように、"=Functionプロシージャ"の形式で呼び出せるようにしておかなければならないからです。

プロシージャ名を決めて、スタートアッププロシージャの外枠ができたら、そこにコードを書き込みます。ここにスタートアップフォームを開くコードを記述します。もちろん、フォームを開く前に前処理が必要であればそれを記述しますし、もしもフォームを必要としないアドインだったら必要な処理の実行部だけを記述します。そのアドインがウィザードのように、いったんフォームを開けば後のすべての処理はフォームモジュール内だけで完結するようなものであれば、このスタートアッププロシージャに記述するのは"フォームを開く"コードだけでよいことになります。

ここでは、アドインが起動されると、Accessは指定されたスタートアッププロシージャを真っ先に実行するということをポイントとして覚えておいてください。どのプロシージャがスタートアッププロシージャかをAccessに対して指示する方法については後で説明します。


モジュールのメモリ上での扱われ方

ここでは、アドインのモジュールあるいはそこで定義されているプロシージャやPublic変数・定数が、Accessあるいはユーザーが作成しているデータベースから見てどのように扱われるかという「通用範囲」について説明します。

結論からいうと、「ユーザーが作成しているデータベースもアドインも、メモリ上はまったく区別なく扱われる」ということです。つまり、アドインが開かれていれば、ユーザーのデータベースで標準モジュールのプロシージャや変数・定数を呼び出すのとまったく同じように、アドイン内に定義されたそれらを呼び出すことができるのです。

ここで、普通に作られるデータベースでの通用範囲を思い出してみてください。

例えば、
  • 標準モジュールにPublicで宣言された(あるいはPrivate指定がない)プロシージャ・変数・定数はデータベースのどこからでも参照できる。
  • 標準モジュールにPrivateで宣言されたプロシージャ・変数・定数は、そのモジュール内でしか参照できない。
  • フォームなどのクラスモジュールでも、Publicで宣言されたプロシージャ・変数・定数はデータベースのどこからでも参照できる。
などは、ユーザーが作っているカレントデータベースとアドインの関係にも、まったく同じことがいえるのです。例えば、アドインの標準モジュールにPublicで宣言されたプロシージャはアドイン内からはもとより、ユーザーのデータベースからでも参照できるわけです。


プロシージャやPublic変数・定数の命名

前項で説明したように、メモリ上はユーザーのデータベースもアドインも区別ありません。そこで注意しなければならないのがプロシージャやPublic変数・定数の命名です。かといって、特別なルールがあるわけではありません。"できる限りユニークな名前を付ける"ということだけです。もしアドイン内で"GetTableData"という名前のプロシージャを作ったとします。この名前というのは、いかにも多くの人が付けそうな名前だとは思いませんか?。もしアドイン上にこのプロシージャがあり、ユーザーのデータベースにも同じ名前のプロシージャが作られたとすると、同じプロシージャ名が重複して存在することとなり、もちろんエラーとなります。どちらのデータベースにあるプロシージャかということはAccessは区別してくれないのです。オブジェクトブラウザを使えば、たとえプロシージャ名が重複しても、アドイン内でどんなプロシージャが定義されているか確認することは可能です。しかし、エラーを待って名前の重複をユーザーに知らせるのは不親切です。そのようなことから、アドインではあらかじめユニークな名前を付けるわけです。

では、どのように名前を定義すればよいのでしょうか?。なにも"GetTableData"を"kio_q4_2fe"なんて名前にする必要はありません。慣例的には、一般的に名付けれたらプロシージャ名や変数・定数名の頭にユニークな文字をいくつか付けるという方法が多いようです。例えば、このサンプルアドインでは"SamplAd.MDA"という名前から、"smp_"を頭に付けるようにしています。これなら、"smp_GetTableData"という名前を付ける人はそうめったにはいないでしょうから、おそらく大丈夫でしょう。


データベースのオープン

ところで、メモリ上、カレントデータベースとアドインの区別がないなら、データベースを開く際はどのようにして2つを区別すればよいのでしょうか?。

  Dim dbs As Database
  Set dbs = CurrentDb

とすれば、アドインからこれを実行した場合にはアドインにとっての"カレント"、つまりMDAファイルが開かれると思われるかもしれません。しかし、実際にはアドインからこれを実行すると、ユーザーが作っているデータベース(.MDB)の方が開かれてしまいます。つまり、絶対的に"カレント"なデータベースはユーザーが作っている側のデータベースなのです。そこで登場するのが「CodeDb関数」です。これを使うことによって、この関数を実行しているデータベースつまりアドイン自身のデータベースを開くことができるのです。使い方はCurrentDb関数と同じです。

  Dim dbsCd As Database
  Set dbsCd = CodeDb

とすればよいのです。

なお、このアドインでは、カレントデータベースにあるAccessオブジェクト(具体的にはフォーム)の一覧を調べる際に次のようなコードを使っています。これもまた、ユーザーが作っている側のデータベースを操作する方法の1つです(Access2000から使えるようになった方法です)。

  Dim dbs As Object
  Set dbs = Application.CurrentProject


アドインの終了

Accessで作る一般的なデータベースアプリケーションでは、その終了方法にもいくつかのパターンがあると思います。例えば、
  • メインメニューのようなフォームを閉じるだけ(DoCmd.Close acForm,.......
  • カレントデータベースを閉じる(Application.CloseCurrentDatabase)
  • Accessも終了させる(Docmd.Quit)
  • Windowsまで終了させる(WindowsAPI)
それではアドインの場合にはどのような方法で終了すべきでしょうか?。ここで認識しなければならないのは、アドインを使う場合には、必ずユーザーが作成中のデータベースも開いているということです。うかつにアドインを終了させればそちらも終了してしまいます。ですから、上記の3つ目と4つ目はもう論外でしょう。それでは、2つ目のCloseCurrentDatabaseメソッドを使った方法はどうでしょうか?。「CurrentDatabase」というだけあって、アドインからこれをじっこうすればアドインのデータベースだけが閉じそうです。しかし、実はこれもデータベースを開く場合と同じで、ユーザーが作成中のデータベースを"カレントデータベース"と見るのです。したがって、これをアドインから実行すると、そのアドインを利用している他のユーザーや開発者に怒られるのは必至です。ということで、1つ目の方法、つまりフォームを閉じるだけで終わり、という方法を使うことにならざるを得ません。

ただ、フォームを閉じるだけという行為にはちょっといやな点があります。データベースやモジュールが完全にアンロードされるわけではないので、モジュールの「参照設定」にそのアドインへの設定が残ってしまうことです。これについては、もしデバッグや導入後に問題となるようでしたら、以下の方法で対処してみてください。
Private Sub Form_Load()
  Dim ref As Reference

  On Error Resume Next
  '参照設定を追加(アドインのファイルのフルパスを指定します)
  Set ref = Application.References.AddFromFile("C:\Windows\Application Data\Microsoft\AddIns\SamplAd.MDA")
  Set ref = Nothing

End Sub

Private Sub Form_Close()
  Dim ref As Reference

  '参照設定を解除
  On Error Resume Next
  Set ref = Application.References("アドインのテスト")
  '「アドインのテスト」は、アドインのVBAのプロジェクト名です
  If Err.Number = 0 Then
    Application.References.Remove ref
    Set ref = Nothing
  End If

End Sub

ページのトップへ

| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved