日付入力を標準コントロールのみで行う。

以前,VBAのフォームで日付入力を簡単に行わせる方法を調べていたところ,Accessのカレンダーコントロールを用いる方法などが見つかりました。簡単にできて見栄えもいいので,これを使って作ったアプリケーションを配布したところ,Accessのライセンスを持ってないPCを使っている方からエラーが出ると言われました。
当たり前といえばそうなのですが,それを無理やりできるようにするのはライセンス違反のようなので,この方法と比べるとちょっと不便かもしれませんが,簡単な日付入力を標準コントロールのみ組み合わせて作って対応したので紹介します。

UserFormを追加


まず,VBEでUserFormを追加し,ツールボックスからコンボボックスを3つ配置します。必要に応じて説明用のラベルを入れます。(下の例では「日付」と区切りのスラッシュを入れています。)
コンボボックスの名前は,それぞれ,cmb年,cmb月,cmb日などとし,リスト選択だけで任意の入力ができないように,Styleプロパティを2-fmStyleDropDownListにします。

date_input_1

続いて,このフォームのコードを書いていきます。まず,フォームの空いているところをダブルクリックすると,それに応じたコードウィンドウが開きます。すなわちUserFormオブジェクトのデフォルトのイベントClickのコードが表示されますが,それは消して良いので,Initializedイベントを選択します。

date_input_2

これは,このフォームが呼び出された時に,実行されるイベントで,主にフォームの初期化などに用います。この場合は,コンボボックスのドロップダウンリストの選択肢を準備します。

UserForm_Initializeのコード

〔8,15行目〕
ループ条件にしたがって,年・月のドロップダウンリストを準備しています。
〔11,19行目〕
リストボックスの選択状態を現在の年月に設定します。ListIndexは0から始まるので,1900年から現在年までのリストとした場合,現在年yは,y-1900番目となります。同様に現在月mはm-1番となります。
そして,このコード中ではまだ日付のドロップダウンリストの準備はしません。なぜなら,選んだ年月によって,月末日が変わりますし,うるう年の考慮も必要となります。そこで,年・月を選んだ(変更した)時に日数の範囲を決定するようにします。
なお,19行目でcmb月.ListIndexを変更することにより,Changeイベントが発生し,下記に示すコードが実行されますので,結局フォームの初期化時(UserForm_Initialze)に日のドロップダウンリストも準備されます。
VBEのフォームで月のコンボボックスをダブルクリックすると,cmb月オブジェクトChangeイベントのコードウィンドウが表示されるので,そこに次のように書きます。

cmb月_Changeのコード

〔9~11行目〕
処理のため現在の年・月・日を取得します。ここで,日だけValueでなくListIndexを使うのは,最初にUserForm_Initializeで呼ばれたときには,まだ日のリストボックスが準備されていない(Itemがない)状態なので,Valueはエラーとなりますが,ListIndexは何も選択していない状態の場合,-1を返すのでエラーが発生しません。
次に月によって月末日を判定します。
〔13~16行目〕
Select文で大の月,小の月,2月に処理を分岐します。

〔17~25行目〕
コード中の説明(緑色の字)の通り,うるう年の判定を行なっています。

〔29行目〕
月を変更したため月末日が変わっている可能性があるので,いったん日のドロップダウンリストをクリアします。

〔31行目〕
変更した月の月末日までのドロップダウンリストを作成し直します。

〔34~38行目〕
日の選択状態を元に戻す必要がありますが,月末日のチェックを行います。例えば,3月31日の状態から4月を選択すると,4月31日にならないよう,末日の4月30日に変更しなければなりません。したがって,元の日付と変更した月の月末を比べて,超えていたら月末日に,超えていなければ元の日にします。

なお,上記は年を変更した場合も起こる可能性があります。2月を選択している状態で,年を変更すると,うるう年で月末日が変わる可能性があります。例えば,2012年2月29日を選択している状態で,2013年に変更した場合,ドロップダウンリストを28日までに変更して,表示も2013年2月28日にする必要があります。そのため,年を変更するcmb年_Changeイベントに以下のように書きます。

cmb年_Changeのコード

〔5行目〕
2月の場合に,「2月」という値は変更しないが,cmb月_Changeイベントを連鎖させます。

関連記事