Microsoft Access2003

Page 1 (2004/12)

ページジャンプ
Page 10 11 12 13 14 15

自家用の業務アプリケーションをMS−DOSベースのdBASEからWindowsのMS Access97へ移行してずいぶん時間が経ちましたが、幸いトラブルもないため、ほとんどプログラムの知識も忘れてしまいました。
その間に、Access97はバージョンアップを繰り返して、いつのまにかAccess2003になっていたりします。
現状の97でなにも不都合は無いのですけど、ある程度は新しいものに触れておかないとマズイか?ということで2003をちょっと前に買ったのですが、あまりめざましい改良は無さそう、ということでそのままにしてしまいました。
が、ちょっと思い立ってイタズラしてみることになりました。

仕事を除けばプライベートでデータベースを必要とすることなどほとんど無いのですが、DVDのコレクションが少しずつ増えてきているので、これをAccess2003のデータにしてみようと思い立ちました。
でも、データの数は知れたもの。プログラムを使うまでも無い・・と思ったのですが、やり始めるとそうも行かなくなります。
メインのデータファイル(テーブル)は下図の通り単純なものです。
メインのテーブル「DVD」の他に、これにリンクするテーブルがいくつか。「監督名」と「俳優名」そしてTV録画かテープからのダビングかなどデータソースを分類するため「データソース」という3個のテーブルです。
いずれもシンプルなもので、いくつかテスト的にデータを入れてあります。
メインのテーブル「DVD」のなかのフィールドで文字列なのはDVDのタイトルだけ。あとはリンクテーブルのキーフィールド、IDだけが入っています。
視覚的には上図のように、リンク先の文字列が表示されますが・・・。
左の図はテーブル間のリレーションのイメージです。監督名も俳優名は何度も登場するのでマスターファイルとしています。
映画の出演者は5人まで登録できるようにしました。
これはとりあえず安直に作ったフォームです。
データを直接いじる連結フォームはあまり使わないようにしているのですが、さほど重要なデータではないので、お手軽にテーブル「DVD」に連結しています。

監督名と出演者はそれぞれのテーブルにリンクしているので、新しいデータを入力するときはあらかじめそれらのテーブルに追加登録してから、ということになるのですが、これがなんとも面倒。
たとえまれにしか使わないとはいっても、使いやすい方がいい。

ということで、このフォームでデータを入力しながらマスターデータを追加してゆくのには?と考え初めてドツボにはまりこんでゆくわけで(/_;)
ComboBox、LimitToListプロパティ
監督名や出演者の名前にはコンボボックス(ComboBox)を使っています。
すでに登録されているデータについては、ここでドロップダウンリストから簡単に登録できるわけですが、登録されていないデータはどうするのか?
コンボボックスには「入力チェック(LimitToList)」というプロパティがあります。これにはYes(True)とNo(False)のどちらかの設定値が入ります。デフォルトはNoで、登録されていないデータでも入力はできます。
問題は、ここでリスト外のデータが入力できたとしても、それはこのコントロールのレコードソース、この場合はテーブル「DVD
」のフィールドに登録されるというだけで、マスターファイルである「監督名」テーブルに追加登録されるのではない、ということです。
それではどうすればいいのか?と考えると、結局VBAを使わざるを得ない。
NotInListイベント(リスト外入力時)
コンボボックスが「入力チェック」=Yesの状態でリストに登録されていないデータを入力すると、NotInListイベントが発生します。
ここにデータ登録のコードを書くわけですが、VBAはすっかり忘れてしまったので大変でした(/_;)
ヘルプファイルの中の使用例を参考にして、ひとつひとつ理解しながらなんとかそれらしい動きをするようにはなりました。
Private Sub 監督名_NotInList(NewData As String, response As Integer)
  Dim db As Database
  Dim rs As Recordset
  Dim Msg As String

  If NewData = "" Then Exit Sub

  Msg = "'" & NewData & "' は未登録です。" & vbCr & vbCr
  Msg = Msg & "追加登録しますか?"
  If MsgBox(Msg, vbQuestion + vbYesNo) = vbNo Then
    response = acDataErrContinue
    MsgBox "Please try again."
  Else
    Set db = CurrentDb
    Set rs = db.OpenRecordset("監督名", dbOpenDynaset)
    rs.AddNew
    rs![監督名] = NewData
    rs.Update
    response = acDataErrAdded
  End If
End Sub
単純に、リストに登録されていない値を入力したときは、そのテーブルを開いてデータを追加登録する、というだけのことなのですけど・・・、長いこと触ってないと、これだけのことでもずいぶん四苦八苦するものです(/_;)
もっとも、このNotInListような処理は使ったことが無かったので、もともと知識として持ってはいなかったのも確かですけど。

引数NewDataは文字通り、コンボボックスに入力した値をテキストとして受け取ります。
数値型の引数responseは、戻ったあとの処理法を指定する。
ここでは使ってませんけど、デフォルト値はacDataErrDisplay。これは、リストに登録されている値を入力してくださいというメッセージを出すらしい。acDataErrContinueはデフォルトの代わりにユーザーの指定したメッセージを表示させる。
acDataErrAddedは新しいデータを登録した後、コンボボックスのリストをリフレッシュします。
しかし、改めてコードを眺めてみると、Accessのヘルプで紹介されている使用例そのまま(^^ゞ
まっ、使用パターンはだいたいこのようなものなのでいじりようがないとも言えますけど。
OnNotInListプロパティ
ややこしいことに、NotInListにはプロパティとイベントとあります。
コンボボックスのプロパティ・ウィンドウのなかにイベントのタブがありますが、これがOnNotInListプロパティらしい。
このプロパティは、NotInListイベントが発生したあとの処理方法を指定する。
通常は今回の例のようにイベント・プロシージャを指定するけど、そのほかにマクロや式などが選択できます。
つまり、このプロパティから、指定されたNotInListイベントプロシージャが実行される、という仕組みらしい。

ちなみに、入力チェックがYesの状態でプロシージャなどの対処法をなにも記述しないと、デフォルトのメッセージであるacDataErrDisplayが表示されるという具合。下の図がそれです。
フォーム「DVD」には監督名のほかに出演者1から出演者5までのコンボボックスがありますが、この五つはどれも同じなので、共通のイベント・プロシージャにしてしまいます。同じコードをコピー&ペーストで貼りつけるというのも芸がないので・・。
フォームのプロシージャファイルの一番下にNewActorという名前の汎用プロシージャ?を作ります。
パラメーターはNotInListのパラメータをそのまま使ってしまいます。

Sub New_Actor(NewData As String, response As Integer)
  この間のコードは監督名のとほとんど同じ・・・
End Sub
呼び出す側は下のようにパラメータ付きでCallします。

Private Sub 出演者1_NotInList(NewData As String, response As Integer)
  New_Actor NewData, response
End Sub

NotInListの処理を汎用化するのなら、テーブル名とフィールド名もパラメータにしてモジュールのなかに置いておけば、他のフォームでも使えるかも知れません。
ControlSource(コントロールソース)とRowSource(値集合ソース)
考えてみるとコンボボックスで使用するイベントプロシージャというのはこれぐらいしかなさそう。
数多いプロパティの中で、最初のうちは呑み込みにくいものに、ControlSource(コントロールソース)とRowSource(値集合ソース)との関係があります。

上の例で言いますと、コンボボックス「監督名」はフォームに連結されたテーブル「DVD」のフィールド「監督名」をコントロールソースとしていますので、レコードをスキップするとそれぞれの値が表示されます。
一方、このコンボボックスの値集合ソースはテーブル/クエリーを指定しています。
データをテーブルの並びでコンボボックスに表示するのならテーブル「監督名」を設定。監督名の名前順に並べ替えてリスト表示するのなら、下のようなSQLステートメントが値集合ソースとなります。

SELECT 監督名.監督名ID, 監督名.監督名 FROM 監督名 ORDER BY 監督名.監督名;

コンボボックスのリストはテーブルないしクエリーの値から選択できますから、値を変更するたびに、コンボボックスの値はくるくると変わります。
なかなかイメージとして理解しにくいところがありますね(。。;)ゞ

ところで、もうひとつ分かりにくい部分というと、この例のコンボボックスは文字列フィールド「監督名」を表示し、それを追加登」録できるようにしているのですが、コンボボックスのRowSourceにはオートナンバー数値型のフィールド「監督名ID」も含まれいて、表示しないようにしています。これを設定するのがColumnWidths(列幅)プロパティ。
テーブルに連結されているのは、実はこちらの数値型フィールドなのです。文字列の監督名を表示、編集しても、連結されているのは数値型の監督名IDのフィールドなのですね。
この連結する列を指定するプロパティがBoundColumn(連結列)プロパティです。
それでは、コンボボックスに監督名だけではなく監督名IDのフィールドも表示したらどうなるか?というと、これがややこしくなります。
具体的には、新しい監督名の追加入力ができなくなってしまう・・・・。
ということで、この程度のプリミティブなデータベースでもコードを使わずに・・・というのは無理。やはり細かな制御やエラーチェックなどをしょうとすると短いプログラムを書かなくてはならない。
それでも、この程度で済む。とは言えますけどね。

NotInList以外ではテキスト・コントロールの「タイトル」には、将来、重複登録などが起こり得るので、登録済みデータを検索して重複登録を排除するようにしました。
タイトル名が空白でも意味がないので、こちらのチェックも入れましたが、どの部分でチェックを入れるかを注意しないと、フォームを閉じるたびにエラーチェックでひっかかったりします。


Page Topへ戻る