Step 7で作成した個人情報を入力・表示する部分のプログラムを作ってみましょう。
図11−1
“個人ID”テキストボックスに数字を入力したり削除したりしたときのプログラムを作ります。
図11−2
入力の後に実行するプログラムですから[更新後処理]のイベントプロシージャにプログラムを作成します。
それでは、実際にプログラムの中身を見てみましょう。左の番号は、説明のために
つけてあるだけです。
01:'概要:該当する個人IDの住所を表示します
02:Private Sub txt個人ID_AfterUpdate()
03: '個人IDがNullのときは、すべての情報をクリアする
04: If IsNull(Me.txt個人ID) Then
05: call subFormAllClear
06: '住所を表示する
07: Else
08: '整数に変換しておく
09: Me.ActiveControl = CInt(Me.ActiveControl)
10: subSearchAddress '住所を表示する
11: 'サブフォームに表示する情報が“個人リスト”以外のとき家族に関する表示を行う
12: If Me.grpリストタイプ <> 1 Then SetSubFamily
13: End If
14:End
1行目はコメントをです。”’”をつけるとそれ以降は,コメントとみなされてプログラムからは外されます。 プロシージャの中でも外でもどこでも構いません。どんな処理をやるのかなどプログラムの説明をしておきます。 作っている時はいいんですが、しばらくしてプログラムを見直すと、「なぜこんな処理をしているんだろう?」って 思うことがしばしばあります。そうならないために、こまめにコメントを付けておきましょう。
4行目に、”If・・・”と言う文があります。 ”Then”までの条件が”真(True)”のとき、 5行目を実行して、それ以外なら8行目から12行目までを行うと言う意味です。
同じく4行目に“IsNull(Me.txt個人ID)”という命令があります。これは、“Me.txt個人ID”が“Null(ヌル)”で あったら“True”そうでなかったら“False”を返してくる関数です。“Null”という値は良く出てきます。これは、 その変数に有効なデータが入力されていないことを示します。
同じく4行目に“Me.txt個人ID”という命令があります。“txt個人ID”は個人IDを入力するテキストボックスの 名前ですが、“Me”は現在アクティブになっているフォームやレポートを意味します。“個人ID”を入力するときは、 “個人情報入力”フォームがアクティブになっていますから“Me”は、“個人情報入力”フォームを示します。したがって “Me.txt個人ID”とは、“個人情報入力”フォームにある“txt個人ID”を示します。 ただし、この“Me.”は省略することもできます。
したがってこの4行目の意味は、”個人IDがNullならばThen以下をやりなさい” と言うことです。
4行目では、“Me.txt個人ID”としていますが、9行目では、“Me.ActiveControl”としています。今、“txt個人ID”に入力した後のプログラムを作っているため、このプログラムが実行されるときは、“txt個人ID”がアクティブなコントロールになっているためこのように書くことが出来ます。
9行目の“Cint()”は指定された値を整数に変換する関数です。例えば、“txt個人ID”に“1.1”のような小数を入力されると具合が悪いので整数に変換しておきます。
5行目、10行目、12行目はサブプロシージャです。5行目では“Call”がついていますが、10行目ではつけていません。どちらでもかまいません。“Call”がついていると一目でプロシージャとわかりますが、標準で用意されている関数を利用するときは“Call”をつけないで記述することが一般的です。標準のものも、自分で作成したものも同じと考えて“Call”をあえてつけない場合もあります。そのときは、見分けが簡単なように“sub......”や“fnc....”などとしたりします。この辺は、どういう書き方が正解というものは無いので、何か決まりごとを作って、それに統一されていれば問題ないと思います。
5行目の“subFormAllClear”と12行目の“SetSubFamily”は、今作成しているフォーム内に作成しますが、10行目の“subSearchAddress”は標準モジュールの中に作成します。
図11−3
なぜ「モジュール」のところで作るかと言うと、ここで作ることによって、この住所録データベースのあらゆるところで使用することが出来ます。モジュール内だけでなくクエリの中でも使うことが出来ます。ただし、標準モジュール内でも“Private”で宣言するとその標準モジュール内だけでしか通用しません。
今後、特に断りがない場合“Public”で宣言しているものは、標準モジュールで作成し、“Private”で宣言するものは、それぞれのフォームやレポート内で作成しているものとします。
5行目の“subFormAllClear”内に標準モジュール内で作成する簡単なプログラムがあるので、まずそちらから見てみます。
01:'概要:入力フォームをクリアする 02:Private Sub subFormAllClear() 03: subClearIndividual '個人情報部分のクリア 04: subClearPresentAddressTab '現住所タブのクリア 05: subClearCompanyAddressTab '会社住所タブのクリア 06: subClearParentsAddressTab '実家住所タブのクリア 07: If Me.grpリストタイプ = 3 Then 08: ClearSubForm 'サブフォームのクリア 09: End If 10: Me.txt姓 = Null 11: Me.txt名 = Null 12: Me.txt姓カナ = Null 13: Me.txt名カナ = Null 14:End Sub
3行目から6行目が標準モジュール内で作成するプログラムです。次のようになっています。
01:'概要:個人情報の入力欄をすべてクリアする
02:Public Sub subClearIndividual()
03: With Form_個人情報入力
04: .txt姓 = Null
05: .txt名 = Null
06: .txt旧姓 = Null
07: .txt姓カナ = Null
08: .txt名カナ = Null
09: .cmb関係 = Null
10: .txt生年月日 = Null
11: .cmb性別 = Null
12: .txt性別 = Null
13: .cmb敬称 = 1
14: .lst印刷種類.RowSource = ""
15: End With
16: Erase gPrnKind
17: subClearFamily
18:End Sub
3行目に”With・・・”という式が出てきています。 これは”Withステートメント”と言うもので、
変数やオブジェクトの指定が長いとき、それらを省略したいような時に使います。 ”End With”で終了します。
ここをWithステートメントを使わないで書くと
Form_個人情報入力.txt姓 = Null
Form_個人情報入力.txt名 = Null
Form_個人情報入力.txt旧姓 = Null
Form_個人情報入力.txt姓カナ = Null
Form_個人情報入力.txt名カナ = Null
Form_個人情報入力.cmb関係 = Null
Form_個人情報入力.txt生年月日 = Null
Form_個人情報入力.cmb性別 = Null
Form_個人情報入力.txt性別 = Null
Form_個人情報入力.cmb敬称 = 1
Form_個人情報入力.lst印刷種類.RowSource = ""
となります。また、次の“subClearPresentAddressTab”モジュールのように“Form_個人情報入力”を変数として処理することもできます。
同じく3行目の“Form_個人情報入力”は“個人情報入力”フォームを示しています。
16行目で印刷種類用の配列を初期化しています。この配列も他のフォームで使用しますので標準モジュール内に作成します。プロシージャでないので、宣言部分(モジュールの最上部)に次の内容で作成します。配列については、Step15で説明していますので、そちらを参考にして下さい。
Public gPrnKind(cstMAXINSATSU - 1) As String '印刷種類用の配列さらに“cstMAXINSATSU”というものがあります。これについての詳しい説明は、Step15でしてあります。とりあえず、これも標準モジュールの宣言部分に作成します。
Public Const cstMAXINSATSU = 10
17行目でさらに別の“subClearFamily”というサブプロシージャを呼び出しています。これも標準モジュール内で 作成します。
次も、“Public Sub subClearIndividual()”から呼び出されているプログラムで、現住所タブ内の情報をクリアします。
01:'概要:現住所タブの内容をクリアする 02:Public Sub subClearPresentAddressTab() 03: Dim frm As Form_個人情報入力 04: Set frm = Form_個人情報入力 05: frm.txt現住所ID = Null 06: frm.txt現住所住所ID = Null 07: subClearAddress frm, "現住所" 08: subClearTextBox frm.txt現住所電話ID, frm.txt現住所電話 09: subClearTextBox frm.txt現住所携帯ID, frm.txt現住所携帯 10: subClearTextBox frm.txt現住所FAXID, frm.txt現住所FAX 11: subClearTextBox frm.txt現住所メールコード, frm.txt現住所メール 12: subClearTextBox frm.txt現住所URLID, frm.txt現住所URL 13:End Sub
3行目は、このプロシージャ内で使用する変数を宣言しています。 ”Dim”は、変数の宣言です。 ”frm”が変数名です。 別に 何でもいいんですが、解かりやすい名前にしましょう。 ”As”に続けて変数のタイプを示します。 ここでは、”Form_個人情報入力”である ことを示しています。 ただし、”As”以下は、省略可能です。 省略するとAccessの方で勝手に判断してくれます。 ですが、 なるべく明示的に宣言しておきましょう。 何の変数かを知っておくことは大切ですし、変数名を入力すると次に続くプロパティなどの候補リストが表示されますのでプログラミングも楽になります。 明示的に宣言したほうが処理が早くなるという ことも言えるみたいですが、最近のパソコンは、能力が高いのであまり期待できません。 また、Dimで宣言しなくても変数を使う ようにすることも出来ます。 ただし、これもエラーを発見しにくくするので、やはり変数は,明示的に宣言しておきましょう。変数を複数宣言する場合は、”,”で続けて書くことができます。
4行目で3行目で宣言した“frm”は“Form_個人情報入力”にすることを設定しています。
7行目の“subClearAddress”と8行目以降の“subClearTextBox”もサブプロシージャでこれも標準モジュール内で作成します。“subClearAddress”というプロシージャの名前に続いて“frm, "現住所"”とあるのが引数です。4行目で設定した“frm”と“現住所”という文字列“subClearAddress”というプロシージャに渡しています。
次も、“Public Sub subClearIndividual()”から呼び出されているプログラムで、会社住所タブ内の情報をクリアします。
01:'概要:会社住所タブのクリア
02:Public Sub subClearCompanyAddressTab()
03: Dim frm As Form_個人情報入力
04: Set frm = Forms![個人情報入力]
05: frm.txt会社ID = Null
06: subClearCompany frm
07: subClearCompanyAddress frm
08: subClearCompanyIndividual
09:End Sub
次も、“Public Sub subClearIndividual()”から呼び出されているプログラムで、実家住所タブ内の情報をクリアします。
01:'概要:実家住所タブのクリア
02:Public Sub subClearParentsAddressTab()
03: Dim frm As Form_個人情報入力
04: Set frm = Forms![個人情報入力]
05: frm.txt実家住所ID = Null
06: frm.txt実家住所ID = Null
07: subClearAddress frm, "実家"
08: subClearTextBox frm.txt実家電話ID, frm.txt実家電話
09: subClearTextBox frm.txt実家FAXID, frm.txt実家FAX
10:End Sub
次も、“Public Sub subClearIndividual()”から呼び出されているプログラムですが、これは、標準モジュール内ではなく、このフォーム内に作成します。
01:'概要:個人情報入力フォームのサブフォームをクリアする 02:Private Sub ClearSubForm() 03: Dim strSql As String 04: strSql = "SELECT 個人ID AS 番号, [姓] & ' ' & [名] AS 名前 " _ 05: & "FROM 個人情報 " _ 06: & "WHERE 個人ID Is Null;" 07: With Forms![個人情報入力] 08: .frm名簿sub.Form.RecordSource = strSql 09: .frm名簿sub.Requery 10: End With 11:End Sub
4行目から6行目が一覧表示をするためのサブフォームをクリアするためのSql(Structured Query Language)文です。6行目の“ WHERE 個人ID Is Null”は個人IDがNullの物を抽出する条件です。ですが個人情報テーブルの個人IDには、必ず番号が登録されております。つまり抽出されるデータは無いことになります。これをサブフォームのレコードソースプロパティに設定すればリストがクリアされます。
Sql文を直接プログラム内に書いていくには、Sqlの知識が必要になります。ですが、心配要りません。Accessにはクエリという強い見方があります。これを使うことでとんでもなく難しいSQLをいとも簡単に作ることが出来ます。逆にいうと、クエリをマスターして目的に合ったクエリを作ることが出来ればVBAで効率よくデータ操作をすることが出来るようになります。
図11−4
クエリを作る場合も、ウィザードを使う方法がありますが、例によって、私の場合使ったことがありません。
何度か試してみたのですが、かえって使いにくかったです。っと言うことで、「新規作成」で作ります。図11−4のような
ウィザードの選択画面が出ます。「選択クエリウィザード」と言うのと「ウィザードを使用してクエリを作成する」と言う
のは、同じです。ですから、ほとんど使うことはありません。その他のウィザードは、たまに使うことがあります。
ただ、今回の住所録では、使うことが無いと思います。
図11−5
4行目から6行目のSql文をクエリであらわすと図11−5のようになります。ここで“SQLビュー”を選択すると
図11−6のようになります。
図11−6
これをコピーしてプログラムに貼り付けます。文字列が長すぎると見難くなります。適当な場所でくぎり、
” _”(スペース+アンダーバー)と”&”で繋ぎます。
文字列を繋いだときは空白(スペース)を確認します。 例えば、1行目がSql=”SELECT ・・・
名前” _で、
2行目が& ”From・・・”となっていると”SELECT ・・・
名前From・・・”となってしまい、名前とFromが
くっついてしまい1つの文字列になってしまいます。そうならないように空白(スペース)を入れる必要があります。
8行目でサブフォームのレコードソースにSql文を設定して、9行目で再度クエリを実行させています。フォームに限らす、コンボボックスなどソースを変更する場合は、必ずリクエリしなければなりません。リクエリするまでは、いくらSql文を変更しても表示される値は、変更されません。
次は“Private Sub txt個人ID_AfterUpdate()”から呼び出されているプログラムで、個人情報、現住所、会社住所、実家住所などこのフォームのすべての方を表示します。
01:'概要:住所を表示する 02:Public Sub subSearchAddress() 03: Dim db As Database 04: Set db = CurrentDb() 05: '個人情報の表示 06: subSelectIndividual db, Form_個人情報入力.txt個人ID 07: '現住所Tabの表示 08: subViewAddress db 09: '会社住所Tabの表示 10: subViewCompanyAddressTab db 11: '実家住所Tabの表示 12: subViewParentsAddress db 13:End Sub
3行目の”Database”は、どのデータベースを使うかを宣言するときに使います。4行目でこのプロシージャ内で使用するデータベースは、今使っているデータベース、つまり住所録データベースであることを設定しています。
6行目が個人情報を表示するためのサブプロシージャで8行目が現住所タブの内容を表示するためのサブプロシージャです。10行目が会社住所タブを表示するためのサブプロシージャで12行目が実家住所タブの内容を表示するサブプロシージャです。これらもすべて標準モジュール内で作成します。
次も、“Private Sub txt個人ID_AfterUpdate()”から呼び出されているプログラムで、サブフォームに家族登録のための情報または、家族のメンバーの名前を表示します。
01:’概要:サブフォームに家族登録のための情報または、家族のメンバーの名前を表示する 02:Public Sub SetSubFamily() 03: Dim strSql As String 04: Dim frm As Form_個人情報入力 05: Set frm = Form_個人情報入力 06: frm.grp選択 = 0 07: frm.grp選択.Enabled = False 08: Select Case frm.grpリストタイプ 09: '家族リスト 10: Case 2 11: If IsNull(frm.txt家族ID) Then 12: subViewSubFamily 13: Else 14: ClearSubForm 15: End If 16: '家族内リスト 17: Case 3 18: If IsNull(frm.txt家族ID) Then 19: ClearSubForm 20: Else 21: subViewSubFamilyList 22: End If 23: End Select 24:End Sub
6行目7行目は、家族の情報のときは、絞込みをしてサブフォームに一覧を表示する必要が無いので“全、あ、か・・他”まで トグルボタンに設定されていない値をこのオプショングループに設定します。今回は“0”をセットします。 こうすることによってすべてのトグルボタンを選択していない状態にします。さらに7行目で使用不可にしてボタンを押せないように しています。このように誤った操作をしないようにするために“Enabled”はよく使います。
8行目から23行目までがSelect文です。“Select Case”で指定している条件によって実行する内容を 変更します。 If文に似ていますが、If文は、条件の真偽、つまりどちらかを行うような命令ですが、Select Caseの場合は、 条件によっていくつも分岐させることが出来ます。 その分岐となるのがSelect Caseの下に出てくる、”Case ・・”です。 今回のデータには[frm.grpリストタイプ]が2ならば”Case 2”以下から 次の”Case 3”までを行います。 同様に[frm.grpリストタイプ]が3ならば”Case 3”以下から最後の ”End Select”までを行います。今回は、2つしか分岐が無いのでIf文でも良いんですが、どういう値が入ってきたら 分岐するのかを明確にするためSelect文を使ってみました。
12行目が家族登録するための表示をするサブプロシージャで21行目が家族のメンバーを表示するためのサブプロシージャです。 これら標準モジュール内で作成します。
ここまでが、“個人情報入力”フォームにある“txt個人ID”に値を入力、もしくは空白にしたときに“個人情報入力”フォームから 呼び出されプログラムですが、それぞれのプロシージャは、さらに別のプロシージャを呼び出しています。これらの内容を見てみます。
まず、“subClearIndividual()”内で呼び出されている物が次のサブモジュールです。
01:'概要:家族ID、連名印刷をクリアし使用不可にする 02:Public Sub subClearFamily() 03: With Form_個人情報入力 04: .txt家族ID = Null 05: .cmb連名印刷 = Null 06: .cmb連名印刷.BackStyle = 0 '透明 07: .cmb連名印刷.Enabled = False 08: End With 09:End Sub
家族登録に関係ない人の場合は、家族に関係しているところをクリアして入力できないようにしています。6行目の“BackStyle = 0”は背景を透明にして入力できないことを明確にしています。
次に“subClearPresentAddressTab()”内から呼び出されているものを見てみます。
01:'概要:住所に関する入力欄をクリアする
02:Public Sub subClearAddress(frm As Form, strTab As String)
03: frm("txt" & strTab & "郵便番号") = Null
04: frm("txt" & strTab & "住所1") = Null
05: frm("txt" & strTab & "住所2") = Null
06: frm("txt" & strTab & "番地") = Null
07: frm("txt" & strTab & "住所ID") = Null
08:End Sub
2行目の“subClearAddress(frm As Form, strTab As String) ”の括弧内“frm As Form, strTab As String”を引数といいます。 呼び出し側でセットされた値をこのプログラム内で使用するときにこのように設定します。
3行目以降に”frm("txt" & strTab & "*******")”と言う式が出てきています。 住所を表示する現住所タグ、会社タグ、実家住所タグの中には、それぞれ“txt現住所郵便番号”、“txt会社郵便番号”、 “txt実家住所郵便番号”というテキストボックスがあります。これらの項目をクリアするときにそれぞれ“txt現住所郵便番号=Null”、 “txt会社郵便番号=Null”、“txt実家住所郵便番号=Null”というようにすると、例えば“住所3”という項目が増えたとき それぞれのタグ内のプログラムを修正しなければなりません。これは、面倒です。そこで住所に関する部分を一まとまりにしておけば 一箇所だけの修正ですみます。そのため、変化する部分を引数として渡してあげることによって、すべてのタブで共通に使えるように します。このプロシージャの引数で”strTab”を受け取ります。 ここに”現住所”が入ってきたら”txt現住所郵便番号”となり、 ”会社”が入ってきたら”txt会社郵便番号”となります。このような場合、通常フォーム内のオブジェクトを指定するときは “frm.txt現住所郵便番号”や“frm!txt現住所郵便番号”と言うように指定しますが、間に変数などを入れる場合は、 括弧にしなければならない点に注意してください。
次もsubClearPresentAddressTab()”内から呼び出されていますが、住所以外の項目はすべてこのプロシージャでクリアできるようになっています。
'概要:指定したテキストボックスをクリアする
'引数:txtID:IDを表示するテキストボックス
' txtName:内容を表示するテキストボックス
Public Sub subClearTextBox(txtID As TextBox, txtName As TextBox)
txtID = Null
txtName = Null
End Sub
次に“subClearCompanyAddressTab()”内で呼び出されるものを見てみましょう。
01:'概要:会社名、部署をNullにし、部署のRowSourceをクリアする 02:Public Sub subClearCompany(frm As Form) 03: frm.cmb会社名 = Null 04: frm.cmb部署 = Null 05: frm.cmb部署.RowSource = "" 06: frm.cmb部署.Requery 07:End Sub
注目したいのは、5行目、6行目です。部署名を表示するコンボボックスの値集合ソースを空白にすることによって何も表示しない ようにしています。逆に、値集合ソースにSql文を設定して部署名を表示させることも後で出てきます。
その他のプログラムは同じプロシージャを呼び出しているだけなので問題ないでしょう。
'概要:会社の住所に関する項目をクリアーする
Public Sub subClearCompanyAddress(frm As Form)
subClearAddress frm, "会社"
subClearTextBox frm.txt会社代表電話ID, frm.txt会社代表電話
subClearTextBox frm.txt会社FAXID, frm.txt会社FAX
subClearTextBox frm.txt会社URLID, frm.txt会社URL
End Sub
'概要:会社に関する個人情報をクリアします
Public Sub subClearCompanyIndividual()
Dim frm As Form_個人情報入力
Set frm = Form_個人情報入力
frm.txt会社個人ID = Null
subClearTextBox frm.txt会社電話ID, frm.txt会社電話
subClearTextBox frm.txt会社メールコード, frm.txt会社メール
frm.txt役職 = Null
End Sub
“subClearParentsAddressTab()”内で呼び出されているものは、今までと同じですので説明の必要はないでしょう。
とりあえず今回はここまでにします。作成した標準モジュールを保存しようとすると下のような画面が出ます。名前は何でもいいんですが、とりあえず”共通モジュール”とでもして保存しましょう。
もう気づいていると思いますけど、プログラムを作るときに段をつけながら作っていきます。 これは、例えば、If文はどこから どこまでがIf文の中身なのかをはっきりさせるためです。 とにかく、プログラムは、出来てしまえば何でも良い、というものではなく、 何度も見直したり、忘れた頃に修正を行ったり、大きいシステムの場合は複数の人でプログラムを作っていきますので、誰が見ても 解かりやすいようにしておかなければなりません。 それと、プログラムのこの部分を修正すると、どこに影響が出てくるかと言うことも 常に考えて作らなければなりません。なるべく間違いを起こさないようにするために同じような処理や塊として考えられるような処理はsubプロシージャやfunctionプロシージャにして分離させておくようにします。そうすることによって、何か変更がかかったときに修正する部分を明確にし最小限に抑えることができるようになります。