Visual Basicユ―ザーのための Accessプログラミングソリューション
Access97 Tips集 part 1
首都圏コンピュータ技術者協同組合
秋月 巌 AKIZUKI,Iwao
さて,Access97の登場に合わせて,今月からリニューアルされたこの連載では,プログラミングのポイントをTips形式で紹介していきます.
いくら同じ言語エンジンを利用しているといっても,Visual Basicの開発環境に慣れたユーザーはAccessの混乱した開発スタイルに,最初,とまどいを感じるのではないでしょうか.だったら,あまり開発環境に依存せず,できる限りVBAコードでAccessのプログラムを書いてしまおう,というのが,これから紹介するプログラミングスタイルです.
オブジェクトの操作,データベースの操作など,プログラミングには欠かせないトピックを,できる限りシンプルなコードで説明します.普通はプロパティウィンドウで設定できる操作も,VBAコードから操作して動的に設定することで,新しいプログラミングの可能性が生まれます.
●VBAコードを簡単に表示する
図1-a:クリックするだけでVBAコードを表示
(ツールボタンをクリックする前)![]()
図1-b:クリックするだけでVBAコードを表示
(ツールボタンをクリックした後)![]()
ツールボタンをクリックするだけで,簡単にプロシージャの表示編集ができます.
●プロシージャを連続して表示する
図2-a:プロシージャの表示方法切替え
(プロシージャをひとつずつ表示)![]()
図2-b:プロシージャの表示方法切替え
(プロシージャを連続して表示)![]()
図2-c:プロシージャの表示方法切替え
(図2-b の部分拡大です)
コードウィンドウ左下部ボタンのクリックで,プロシージャを連続して表示するか,ひとつずつ表示するかを切り替えることができます.
●フォームから別のフォームを開く
図3-a:別のフォームを開く
(ボタンクリック前)![]()
図3-b:別のフォームを開く
(ボタンクリック後)![]()
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:クリックによりフォームが開く
(ボタンクリック前)![]()
図4-b:クリックによりフォームが開く
(ボタンクリック後)![]()
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:クリックによりコントロールを作成
(ボタンクリック前)![]()
図5-b:クリックによりコントロールを作成
(ボタンクリック後)![]()
次のコードでは,ボタン(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:レコードセレクタを消去
(レコードセレクタが表示されています)![]()
図6-b:レコードセレクタを消去
(レコードセレクタが表示されていません)![]()
レコードセレクタは,フォームにレコードを表示した場合に選択されているレコードを指示するために使われます.選択されているレコードは削除コピーなどの編集操作の対象となります.しかし,フォームのビューが単票の場合や,あるいはレコード単位での編集をおこわないときには,レコードセレクタを表示する必要はありません.
レコードセレクタが必要ない場合には,次のようなコードを用います.最初からレコードセレクタのないフォームを作るには,同じコードをFormのLoadイベントに記述します.
Private Sub CommandButton1_Click() Form.RecordSelectors = False End Sub
ただ,マルチユーザー環境で使用している場合,レコードセレクタはデータのロック状態を表示する機能も持っています.レコードセレクタを非表示にすると,他のユーザーがデータをロックしていても,書き込みにゆくまでは知ることができません.
●移動ボタンを表示しないフォーム
図7-a:移動ボタンを消去
(移動ボタンが表示されています)![]()
図7-b:移動ボタンを消去
(移動ボタンが表示されていません)![]()
移動ボタンはデータベースのレコードを移動するために使用しますが,デフォルトの設定ではデータと連結していなくても表示されてしまいます.また,サブフォームで利用する場合などは,移動ボタンが複数表示されてしまい,フォームの下部が複雑になります.
移動ボタンが必要ない場合には,次のようなコードを用います.最初から移動ボタンのないフォームを作るには,同じコードをFormのLoadイベントに記述します.
Private Sub CommandButton1_Click() Form.NavigationButtons = False End Sub
NavigationButtonsプロパティにはTrue,またはFalseの値を設定することができます.
●他のフォームが開いているかどうか確認する
図8-a:他のフォームのステータスを通知
(Form2は既に開いています)![]()
図8-b:他のフォームのステータスを通知
(Form2が開いている事を通知しています)![]()
複数のフォームを非同期で使用しているとき,別のフォームが開いているかどうか確認してから,処理を実行したいときがあります.このサンプルではボタンをクリックしたときに別のフォーム(Form2)が開いているとメッセージを表示します.
Private Sub CommandButton1_Click() If SysCmd(acSysCmdGetObjectState, acForm, "Form2") <> 0 Then MsgBox "Form2は開いています" End If End Sub
フォームが開いているかどうか確認するために,SysCmd関数を使用しています.SysCmd関数を使うことで,データベースのオブジェクトのステータスを取得できます.
次のような構文を用います.
オブジェクトの状態 = SysCmd(実行するアクション, オブジェクトのタイプ][, オブジェクト名])
フォームの状態を取得するためには引数「実行するアクション」にacSysCmdGetObjectState,引数「オブジェクトのタイプ」にacFormを指定します.
●コンボボックスのリストにテーブルの内容を設定する
図9:コンボボックスを利用 ![]()
データ入力のときに選択できるコンボボックスのリストの値を,テーブルから参照することはリレーショナルデータベースの性質上,よくあることです.これを実装するにはいくつかの方法がありますが,コードで設定する方法を次に示します.
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:表示するデータを制限
(コンボボックスに条件が設定されていません)![]()
図10-b:表示するデータを制限
(コンボボックスに設定されている条件のデータを表示しています)![]()
コンボボックスに選択されている値を条件にして,表示するデータを制限したいことがあります.次のコードではコンボボックス(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:レコードセットから抽出
(検索前です)![]()
図11-b:レコードセットから抽出
(抽出されたデータを表示しています)![]()
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:フォームに表示されいてない項目を検索条件に設定
(検索前です)![]()
図12-b:フォームに表示されいてない項目を検索条件に設定
(抽出されたデータを表示しています)![]()
次のサンプルコードでは,フォームに表示されていない項目(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 ホームページ