Visual Basicユ―ザーのための Accessプログラミングソリューション

Access97 Tips集 part 1



首都圏コンピュータ技術者協同組合
秋月 巌 AKIZUKI,Iwao


さて,Access97の登場に合わせて,今月からリニューアルされたこの連載では,プログラミングのポイントをTips形式で紹介していきます.
いくら同じ言語エンジンを利用しているといっても,Visual Basicの開発環境に慣れたユーザーはAccessの混乱した開発スタイルに,最初,とまどいを感じるのではないでしょうか.だったら,あまり開発環境に依存せず,できる限りVBAコードでAccessのプログラムを書いてしまおう,というのが,これから紹介するプログラミングスタイルです.
オブジェクトの操作,データベースの操作など,プログラミングには欠かせないトピックを,できる限りシンプルなコードで説明します.普通はプロパティウィンドウで設定できる操作も,VBAコードから操作して動的に設定することで,新しいプログラミングの可能性が生まれます.



●VBAコードを簡単に表示する


図1-a:クリックするだけでVBAコードを表示
(ツールボタンをクリックする前)
400×257

図1-b:クリックするだけでVBAコードを表示
(ツールボタンをクリックした後)
400×258


 ツールボタンをクリックするだけで,簡単にプロシージャの表示編集ができます.


●プロシージャを連続して表示する


図2-a:プロシージャの表示方法切替え
(プロシージャをひとつずつ表示)
400×258

図2-b:プロシージャの表示方法切替え
(プロシージャを連続して表示)
400×258

図2-c:プロシージャの表示方法切替え
(図2-b の部分拡大です)
82×58


 コードウィンドウ左下部ボタンのクリックで,プロシージャを連続して表示するか,ひとつずつ表示するかを切り替えることができます.


●フォームから別のフォームを開く


図3-a:別のフォームを開く
(ボタンクリック前)
400×266

図3-b:別のフォームを開く
(ボタンクリック後)
400×266



 Accessで作成したアプリケーションはMDIアプリケーションです.MDIアブリケーションはひとつの親ウィンドウの中に,複数の子ウィンドウをオープンすることができます.Accessでフォームを開くには,Showメソッドではなく,DoCmdオブジェクトのOpenFormメソッドを使います.たとえばフォームForm1から,別のフォームForm2を開くボタンのClickイベントプロシージャは次のようになります.

Private Sub CommandButton1_Click()
    DoCmd.OpenForm "Form2"
End Sub

 DoCmdオブジェクトは,Accessの操作をコードから行なうためのプログラミングオブジェクトです.たとえば,「フォームを開く」という操作を手動で行なう場合,データベースウィンドウからフォームを選択してダブルクリックすることで実行できます.同じことをVBAから行なう際に,Access側が提供するインターフェイスがDoCmdオブジェクトです.
 DoCmdオブジェクトはプロパティを持ちません.用意されているメソッドは,それぞれがマクロのアクションに対応します.つまり,マクロ操作をVBAから行なうが,DoCmdオブジェクトのメソッドだということができます.
 DoCmdオブジェクトのOpenメソッドの構文は次のようになっています.

DoCmd.OpenForm フォーム名[, ビュースタイル][, データソース][, データの抽出条件][, データの編集モード][, ウィンドウスタイル][, 引数]


●プログラムで動的にフォームを作成し,オープンする


図4-a:クリックによりフォームが開く
(ボタンクリック前)
400×266

図4-b:クリックによりフォームが開く
(ボタンクリック後)
400×265


 AccessのVBAでフォームを作成することができます.次のコードでは,ボタン(CommandButton1)をクリックしたときに,新しくフォームを生成して表示します.

Private Sub CommandButton1_Click()
    Dim frm As Form
    Set frm = CreateForm
    DoCmd.OpenForm frm.Name
End Sub

 フォームの作成にはCreateForm関数を使用します.次のような構文で利用します.

CreateForm([データベース名[, テンプレートになるフォーム名]])

 引数「データベース名」はフォームを作成するデータベース名を指定します.引数「テンプレートになるフォーム名」に指定したフォームを元に,新しいフォームを作成します.
 引数は両方とも省略することができます.省略した場合は現在使用しているデータベースに,デフォルトのフォームを作成します.
 開く前にプロパティを設定し,フォームの体裁を整えることもできます.次のサンプルでは,オブジェクト変数frmを使用して,Captionプロパティを設定しています.

Private Sub CommandButton1_Click()
    Dim frm As Form
    Set frm = CreateForm
    frm.Caption = "商品"
    DoCmd.OpenForm frm.Name
End Sub


●プログラムで動的にコントロールを作成する


図5-a:クリックによりコントロールを作成
(ボタンクリック前)
400×266

図5-b:クリックによりコントロールを作成
(ボタンクリック後)
400×266


 次のコードでは,ボタン(CommandButton1)のクリックをトリガにして,フォームとテキストボックスコントロール(ctlText)を動的に生成します.テキストボックスコントロールにはテーブル(Syohin)の「商品名」項目(syohin_mei)のデータを表示します.

Private Sub CommandButton1_Click()
    Dim frm As Form
    Set frm = CreateForm
  
    frm.RecordSource = "Syohin"
    frm.DefaultView = 1 '帳票フォーム
  
    Dim ctlText As Control
    Set ctlText = CreateControl(frm.Name, acTextBox, , "", "", 1000, 100)
    ctlText.ControlSource = "syohin_mei"   
    DoCmd.OpenForm frm.Name
End Sub

 フォームのReocorsSource,DafaultViewプロパティをVBAコードで設定しています.次にフォーム上にコントロールを作成し,データを表示するためにControlSourceプロパティを設定します.
 プログラムで動的にコントロールを生成するには,CreateControl関数を利用します.
 CreateControl関数は引数の設定により,多くのオプションが設定できます.

CreateControl(フォーム名, コントロールの種類[, コントロールの配置場所[, 親コントロール[, 連結フィールド名[, 位置(左)[, 位置(上端)[, 幅[, 高さ]]]]]]])

 引数「コントロールの種類」と引数「コントロールの配置場所」は,定数を使って指定することができます.


●レコードセレクタを表示しないフォーム


図6-a:レコードセレクタを消去
(レコードセレクタが表示されています)
400×266

図6-b:レコードセレクタを消去
(レコードセレクタが表示されていません)
400×265


 レコードセレクタは,フォームにレコードを表示した場合に選択されているレコードを指示するために使われます.選択されているレコードは削除コピーなどの編集操作の対象となります.しかし,フォームのビューが単票の場合や,あるいはレコード単位での編集をおこわないときには,レコードセレクタを表示する必要はありません.
 レコードセレクタが必要ない場合には,次のようなコードを用います.最初からレコードセレクタのないフォームを作るには,同じコードをFormのLoadイベントに記述します.

Private Sub CommandButton1_Click()
    Form.RecordSelectors = False
End Sub

 ただ,マルチユーザー環境で使用している場合,レコードセレクタはデータのロック状態を表示する機能も持っています.レコードセレクタを非表示にすると,他のユーザーがデータをロックしていても,書き込みにゆくまでは知ることができません.


●移動ボタンを表示しないフォーム


図7-a:移動ボタンを消去
(移動ボタンが表示されています)
400×266

図7-b:移動ボタンを消去
(移動ボタンが表示されていません)
400×265


 移動ボタンはデータベースのレコードを移動するために使用しますが,デフォルトの設定ではデータと連結していなくても表示されてしまいます.また,サブフォームで利用する場合などは,移動ボタンが複数表示されてしまい,フォームの下部が複雑になります.
 移動ボタンが必要ない場合には,次のようなコードを用います.最初から移動ボタンのないフォームを作るには,同じコードをFormのLoadイベントに記述します.

Private Sub CommandButton1_Click()
    Form.NavigationButtons = False
End Sub

 NavigationButtonsプロパティにはTrue,またはFalseの値を設定することができます.


●他のフォームが開いているかどうか確認する


図8-a:他のフォームのステータスを通知
(Form2は既に開いています)
400×250

図8-b:他のフォームのステータスを通知
(Form2が開いている事を通知しています)
400×244


 複数のフォームを非同期で使用しているとき,別のフォームが開いているかどうか確認してから,処理を実行したいときがあります.このサンプルではボタンをクリックしたときに別のフォーム(Form2)が開いているとメッセージを表示します.

Private Sub CommandButton1_Click()
    If SysCmd(acSysCmdGetObjectState, acForm, "Form2") <> 0 Then
        MsgBox "Form2は開いています"
    End If
End Sub

 フォームが開いているかどうか確認するために,SysCmd関数を使用しています.SysCmd関数を使うことで,データベースのオブジェクトのステータスを取得できます.
 次のような構文を用います.

 オブジェクトの状態 = SysCmd(実行するアクション, オブジェクトのタイプ][, オブジェクト名])

 フォームの状態を取得するためには引数「実行するアクション」にacSysCmdGetObjectState,引数「オブジェクトのタイプ」にacFormを指定します.

●コンボボックスのリストにテーブルの内容を設定する


図9:コンボボックスを利用
400×237


 データ入力のときに選択できるコンボボックスのリストの値を,テーブルから参照することはリレーショナルデータベースの性質上,よくあることです.これを実装するにはいくつかの方法がありますが,コードで設定する方法を次に示します.

Private Sub Form_Load()
    Forms!Form1.Controls!combo1.RowSourceType = "Table/Query"
    Forms!Form1.Controls!combo1.RowSource= "SELECT DISTINCT category from Syohin"
End Sub

 このコードはフォームのLoadイベントプロシージャに設定されています.つまり,フォームのオープン時に,リストに値が設定されます.任意のイベントプロシージャに設定することで,動的に設定の変更ができます.
 テーブルの内容を設定するには,RowSourceTypeプロパティを「"Table/Query"」に設定します.次にRowSourceプロパティに設定するリストの条件として,SQL文かテーブル名を指定します.
 RowSourceTypeプロパティとRowSourceプロパティは協調して動作します.RowSourceTypeプロパティに「"Table/Query"」を設定した場合,RowSourceプロパティには,SQL文,または,クエリー/テーブル名を指定します.


●コンボボックスで選択されている条件のレコードだけをフォームに表示する


図10-a:表示するデータを制限
(コンボボックスに条件が設定されていません)
400×300

図10-b:表示するデータを制限
(コンボボックスに設定されている条件のデータを表示しています)
400×301


 コンボボックスに選択されている値を条件にして,表示するデータを制限したいことがあります.次のコードではコンボボックス(Combo1)が選択されたときに,フォームのレコードを制限し,テキストボックス(Text1)に商品名(Syohin_mei)項目の値を出力します.

Private Sub Combo1_Change()
    Dim SQLcmd As String
    SQLcmd = "SELECT * FROM Syohin " & " WHERE category = '" &  =>
                    Forms!Form1.Controls!Combo1.Text & "'"
    Forms!Form1.RecordSource = SQLcmd
    Forms!Form1.Controls!Text1.ControlSource = "Syohin_mei"
End Sub

=>:640×480で表示できるように折り返しています

 コンボボックスのChangeイベントプロシージャで動的にSQL文を生成し,データの絞り込みをおこないます.生成したSQL文をRecordSourceプロパティに設定することで,クエリーが実行されます.
 RecordSourceプロパティにはSQL文,またはクエリー/テーブル名を指定します.


●フォームのレコードセットからデータを検索する


図11-a:レコードセットから抽出
(検索前です)
400×266

図11-b:レコードセットから抽出
(抽出されたデータを表示しています)
400×274


 SQLによるデータの絞り込みではなく,フォームのレコードセット内からデータを検索して値を表示したいことがあります.次のコードではボタン(CommandButton1)をクリックすると,特定の商品(「いちごコーヒー」)をレコードセットから検索します.

Private Sub CommandButton1_Click()
    Me.RecordSource = "Syohin"
    Text1.ControlSource = "syohin_mei"
    Text1.SetFocus
    DoCmd.FindRecord "いちごコーヒー", acStart, True, acSearchAll, True
End Sub

 フォームのレコードセットから値を検索するにはDoCmdオブジェクトのFindRecordメソッドを使います.FindRecordメソッドにオプションを指定することで,検索の方法を指定できます.
 構文は次のようになっています.

DoCmd.FindRecord 検索文字列[, 条件一致のタイプ][, 大文字小文字の区別][, 検索方向][, 書式化データの検索][, 検索する項目を特定][, 先頭レコードから検索]

 サンプルコードでは,先頭の文字列が「いちごコーヒー」という商品名項目(syohin_mei)のデータを先頭レコードから,検索することを指示しています.
 FindRecordメソッドでレコードを検索するには,検索対象の項目にフォーカスが設定されている必要があります.そのため,検索の直前でテキストボックス(Text1)にフォーカスを移動しています.


●フォームに表示されていないデータを,レコードセットから検索する


図12-a:フォームに表示されいてない項目を検索条件に設定
(検索前です)
400×270

図12-b:フォームに表示されいてない項目を検索条件に設定
(抽出されたデータを表示しています)
400×270


 次のサンプルコードでは,フォームに表示されていない項目(furigana)を条件にして,検索を実施しています.検索結果には商品名(syohin_mei)項目のデータが表示されます.

Private Sub CommandButton1_Click()
    Dim rs As Recordset
    Me.RecordSource = "Syohin"
    Text1.ControlSource = "syohin_mei"
    Set rs = Me.RecordsetClone
    rs.FindFirst "furigana = 'ナポレオン'"
    Me.Bookmark = rs.Bookmark
    rs.Close
End Sub
※コード中の「ナポレオン」は実際には半角カタカナです

 DoCmdオブジェクトのFindRecordメソッドを使ってレコードセットから検索する場合,検索項目にフォーカスが設定されている必要があります.そのため,フォームに表示されていない項目を条件にした検索は,FindRecordメソッドではできません.この制限をクリアするには,RecordSetCloneプロパティと,RecordsetオブジェクトのFindFirstメソッドを利用します.
 まず,Recordsetオブジェクト(rs)にフォームのRecordsetCloneプロパティを代入します.RecordsetCloneプロパティを格納したRecordsetオブジェクトは,フォームのレコードセットのコピーです.どちらかに加えられた変更は,もう一方に反映されますが,レコードポインターは独自に持つことができます.
 Recordsetオブジェクトはレコードを操作するためのメソッドを,Formオブジェクトよりも豊富に備えています.RecordsetオブジェクトのFindFirstメソッドを使って検索を実行します.
 Recordsetオブジェクト(rs)の検索結果を,フォームのカレントレコードにするために,BookMarkプロパティをフォームの同プロパティに代入します.


VB Magazine ライブラリ | Visual Basicコースホームページ
int21 ホームページ | PCDN ホームページ


PCDN LOGO