2014
8
04

Excel2013のVBAでカレンダーコントロールを自作する

Office2003だった頃、Access付属のmscal.ocxというカレンダーコントロールを使ってたのですが…。2010からもう使えないとのこと…!!どうにか2013でも似たようなことは出来ないものかと思って、つくってみました。


完成図

140804-22

このようなフォームでボタンを押すと、

140804-27

あらかじめテキストボックスに入っていた日付(空欄だったら本日)に色がついたカレンダーフォームが表示され、

140804-28

クリックした日付をテキストボックスに入力します。

ダウンロード

記事中に解説がありますが、クリックされた日付を取得する際にフォームモジュール内で完結する方法(CalenderForm1.xlsm)と、クラスを作ってクリックイベントを利用する方法(CalenderForm2.xlsm)の、ふたつのファイルが入っています。

2014/8/18追記

コメント欄でリクエストいただいたので、和暦表示の方法も記事中に追記しました。DL用に用意してあるのは西暦表示のみなので、必要な際は部分的に差し替えてご使用ください。

祝日対応はしておりません。というか、祝日を対応させようとすると自作するには結構大変なので、後述するアドインツールを使わせてもらうのが一番だと思います!

自力で簡単にどうにかするなら、専用シートをひとつ作って、月と日のマトリクス表を書いて、祝日の日に 1 とか書いてフラグ化しておいて、カレンダーを読み込む際にそこを参照してフラグが立ってたら文字を赤くする、っていう手も、あるかなぁ、と。

これだったら好きな日を赤くできるので、祝日だけじゃなくて会社がお休みの日も設定できたり、結構自由度が高いんじゃないかなぁと。年始めとかに今年の休日を全部設定する、的な手間は必要ですが。

せっかくなのでそちらの方法も解説してみました。

参考サイト

こちらを参考にさせていただいて作りました。厚く御礼申し上げます!

頑張って自作しなくても

こちらのサイトでは、暦や祝日の複雑なロジックを組み込んだカレンダーなどが利用できるアドインツールを公開されています。

2013以降ならば「コンテンツアプリ」というものが利用できます!こちらのアプリは祝日も含まれているし、デザインも可愛くてとっても素敵です♡

やっぱり同じことを考えて自作してる人がいらっしゃいました…! こちらはフォームへのテキストボックスだけでなく、シート上のセルへも直接日付を入れられるので便利そうですね(*´ω`*)

起動ボタンをつくる

それでは、ここからは「自分で作ってみたい!」という方むけ。

140804-01

まずは新規のシートに、後でModule1に書くプロシージャを起動させるボタンを作っておきます。

ボタンの作り方や、起動の結びつけ方はこちらをご参照下さい。

日付選択のフォームをつくる

140804-02

Visual Basic Editorを開いて、新しくユーザーフォームを作ります。

140804-03

UserForm1というのが出来るので、ツールボックスを使って(出ていない場合は「表示」→「ツールボックス」)テキストボックスとボタンをひとつずつ作ります。TextBox1CommandButton1というオブジェクト名で出来るはずなので、そのままにしておいてください。

140804-04

必須ではありませんが、プロパティウィンドウのCaptionで、フォームの表示名を変更できます。(出ていない場合は、「表示」→「プロパティウィンドウ」)

モジュールをつくる

140804-05

今作ったフォームを表示させるための標準モジュールを新しく作ります。

140804-06

Module1が出来たので、こう書きます。

2,3行目は、これからユーザーフォームを跨いで使うためPublicで宣言しておきます。

宣言についてはこちら

上記のコードではテキストボックスを空欄で表示しますが、初期値として何かの日付を入れておくことができます。例えば本日の日付をあらかじめ入れておきたい場合は、

3, 4行目のように書いてからフォームを表示します。(実際に使う場合はどちらかひとつにしてください。)応用して「本日より1週間前」とか「本日より1週間後」とか、いろいろできます。

この記事ではテキストボックスが空欄のまま進めますが、startというプロシージャを、最初にシートに作ったボタンから起動するように設定すると、

140804-07

このようにユーザーフォームが表示されます。

日付選択フォームのコードを書く

140804-08

さっき作ったUserForm1を右クリックして、「コードの表示」をして、そこにこう書きます。

西暦表示

追記:和暦表示

CommandButton1を押すと、TextBox1に入っている日付(空の場合は本日)を、さっきModule1でPublic宣言したclndr_dateという変数に入れて、UserForm2を開く、というコードです。(UserForm2にはこの後カレンダーを実装する予定ですが、この時点ではまだ存在しないので動かすとエラーになっちゃいます。)

8行目でカレンダーを開き、それが開かれている間はこのコードは中断します。カレンダーが閉じると、このコードの9行目が実行されるので、そこでクリックされた日付をTextBox1に上書きしてやる、という流れです。

カレンダーを作る

「挿入」→「ユーザーフォーム」から、UserForm2を作ります。

今回は例としてUserForm2にカレンダーを作りますが、もちろん違うフォームでも構いません。オブジェクト名を変えてCalenderFormなど、固有の名前にしておいてテンプレートとして残しておくと、今後必要なときに使いまわすことができて便利かも。
140804-09

ツールボックスのラベルを選んで、

140804-10

試しにひとつ作ります。ここには、カレンダーの日付が入るので、表示確認のために一番大きな数字を入れてみます。

140804-11

プロパティウィンドウで、文字の大きさなどが変えられます。

140804-12

文字をセンタリング(中央寄せ)にしたり、幅や高さも指定できます。

あと、ここでオブジェクト名が確認できるので、このオブジェクトがLabel1であることを確認して下さい。

140804-13

ラベルの中身(Captionというプロパティ)を消して、コピーして横に7個並べます。このとき、オブジェクト名の数値が図のように左から順番に並ぶようにしてください。

140804-14

横に7個並んだら、その1行をコピーして下に更に並べます。これも左から順番になるようにチェックしてください。

わたしの環境だけかもしれませんが、複数コピペしたら8番が一番右にいっちゃったりして、順番通りになるように並べ替えが必要でした。

140804-15

横に7列、縦に6行分になるまで繰り返します。

140804-16

ラベルのオブジェクト番号は、このようになっているはず。

実はこれ、ほんとはLabel37までで足りるなー、と後で気づきました。このあと42個で進めてますが、お好みで37個に読み換えていただいて構いません。
140804-17

では、今度はコンボボックスを選んで、

140804-18

ふたつ設置します。ComboBox1には年が、ComboBox2には月が入る予定です。

140804-19

42個並んだラベルの、最左列を全て選択して、

140804-20

プロパティウィンドウで、文字色を赤にしておきます。同じ手順で、最右列は青にします。

カレンダーフォームのコードを書く

140804-21

UserForm2を右クリックして、「コードの表示」をして、そこにこう書きます。

西暦表示

Visual Basic Editorにコピペするとわかりますが、4つのブロック(プロシージャ)に分かれています。今回の肝はその月の1日をどの位置から始めるかというところでして、そこの鍵がハイライトしてある35行目です。

指定日の曜日を 日→1, 月→2, … 土→7 のように、数値で取得してくれるWeekday()という関数を利用して、ComboBox1ComboBox2から「年/月/1」と合成した、その月の1日の曜日番号を取得します。これを -1 したものを日付に足せば、曜日分ずらしたラベルの位置が割り出せるんです。

このアイデアは、冒頭で紹介させていただいた参照サイトより、お知恵を拝借しました!ありがとうございますー!

追記:和暦表示

ハイライトされてる部分が、西暦表示と違うところです。和暦は「平成」などの文字列がつくので、それに合わせて「年」「月」「日」を使って日付を生成します。

では、文章だけだとイマイチ分かりにくいので、動作確認してみましょう!

140804-22

起動させて、このボタンを押してみると…

140804-23

カレンダーが表示されました! 月を変更すると、日付や曜日が対応して表示されるはずです。UserForm1のテキストボックスで指定されていた日(空欄だった場合は本日)に色がつくようになっていますが、これはさっきのコードの39行目で色を変えられます。(RGB(255, 255, 0)は黄色です。)

140804-24

見栄えを整えました。このサンプルは文字の大きさが11, 各ラベルのWidthが18, Heightが12, 指定日の背景色はRGB(189, 231, 255)にしています。

もちろんお好みでいいんですが、最初からこの大きさで作れば良かったなぁと軽く後悔したので、よろしければご参考になさってもらえたら_(´ω`_)⌒)_

コンボボックスの後ろに付けた「年」「月」と、曜日の「日~月」はラベルで作っています。Label1~42は日付部分で使うので、43以降の数値になるように作ってください。

クリックされた日付を取得する

さて、それっぽくなってきましたが、このままだとただカレンダーが表示されるだけで、日付をクリックしても何も起こりません。クリックされた日付を取得する方法は、2つあります。

方法1

さっきのUserForm2のコードの後ろに、これを追記します。

西暦表示

追記:和暦表示

Label1をクリックされたときに起動する、クリックイベントというやつです。日付が入っていないラベルもあるので、空なら中止というエラー処理の後、予めPublic宣言してあったclndr_dateという変数に年と月を合成した日付を格納してカレンダーを閉じます。

これだけ見ると簡単なのですが、問題は、これをLabel○の数値部分を変えて、ラベルの数だけ書かなければならないということ…!42個!!!

処理部分を分離してみました。(和暦にしたい場合は5行目を差し替えてください。)42個書くことには変わらないですが、ちょっとは省コードになるかと。

ラベル数全てベタ書きは気持ち悪いですが、ひとつのユーザーフォームだけでカレンダーが完結するので、ひとつ作っておいてコピーして使い回したい時なんかにはこっちのが楽ですね。

方法2

とはいえ42個も…書きたくないな…_(:3 」∠)_ と思うのはもっともですよねw クラスを作って共通化させて書く、という方法もあります!

UserForm2のコードに、ハイライト部分を追記します。(和暦も同じです。)

ここで書いた「1から42」という番号のラベルのみ、クリックイベントを拾います。先ほどのサンプルだと、「年」「月」、曜日の「日~月」というラベルは43番以降なので、これらをクリックしても何も起こりません。

140804-25

クラスモジュールを新規作成します。

140804-26

新しく出来たClass1に、以下のコードを書きます。

西暦表示

追記:和暦表示

細かい解説はこちらの記事をご参照ください。

動作検証

140804-27

起動させて、カレンダーの20日をクリックしてみます。

140804-28

カレンダーが閉じて、今クリックした日付がテキストボックスに入れば成功です!

140804-29

ちなみに、こんな感じにUserForm1に複数作っても、

UserForm1のコード画面でこのように書いてやれば、ひとつのカレンダーを使いまわせます。違うユーザーフォームからでも、そちらに同じように書けば呼び出せます。

140804-30

こんな感じで、それぞれ違う日付をカレンダーで取得できます。何日~何日、みたいに複数の日付を指定するとき、カレンダーが見えると曜日とか営業日とか考えながら日付を選べて結構便利なんですよねー。

おまけ

140804-31

カレンダーにスピンボタンをつけてやって、

140804-32

場所はお好みですがこのあたりとか。

140804-21

で、カレンダーを描いたフォーム(今回の例ではUserForm2)のコードに、

西暦表示

追記:和暦表示

こんなコードを追加してやると、

140804-33

こんなボタンが実装されて地味に便利ですよ!!というおまけ。

以上です!どなたかのお役に立てたら幸いですー!

  • このエントリーをはてなブックマークに追加
  • follow us in feedly 618
  • RSSを登録

公開日:2014/08/04
更新日:2016/03/09


10件のコメント

  • ウエダ
    2014年8月15日 11:50 PM

    VBAを始めて1年弱の新参者です。大変わかりやすい解説で理解が深まり感謝しております。他のサンプルコードの解説や書籍を読みあさっていますが、変数の理解が今ひとつです。
    カレンダーコントロールについてですが、テキストボックスやセルの貼り付けなど西暦から和暦にすることはできますが、カレンダーコントロールの年表示が、なぜか西暦ばかりで、特にコンボボックスに格納されている西暦を和暦にすることができません。機会がございましたら、コンボボックス・コンボボックスに格納されている西暦を和暦にする方法を記載していただけないでしょうか?

    • *you
      2014年8月18日 10:11 AM

      ウエダさん、コメントありがとうございます。

      わたしも和暦は一度も使ったことがないです!でも公的機関はみんな和暦ですもんね。本文に追記してみましたので、お試し下さい。

  • sota
    2014年10月4日 3:28 PM

    私も小さな会社でこつこつと自作のプログラムで
    業務の効率化をはかっております。
    大変参考になりました。ありがとうございました。

    • *you
      2014年10月6日 8:37 AM

      sotaさん、コメントありがとうございます!お役に立てて光栄ですー(*´ω`*)

  • sota
    2014年10月6日 7:40 PM

    これからも頑張って下さい(^o^)/
    PS私も子育てと仕事を楽しんでます(*^_^*)

    • *you
      2014年10月7日 9:49 AM

      ありがとうございます!sotaさんもお子さんがいらっしゃるんですね!一緒にがんばりましょうー\\└(‘ω’)┘//

  • tuka
    2016年1月11日 2:14 PM

    A列でダブルクリックするとここで紹介された自作カレンダーが表示され、クリックしたラベルの日付がA列の任意のセルに入力されるようにするにはどうしたら良いかご教授願います。

    • *you
      2016年1月12日 8:06 AM

      tukaさん、コメントありがとうございます。

      こちらの記事の最後のほうの「Public変数を利用する」を参考に、入力したいシートのコード画面に、

      Moduleの頭に、

      それと、カレンダーをクリックして日付を取得する部分、

      という記述の直後に

      と書けば実装できると思います。お試しください。

  • hhgm
    2016年8月5日 6:49 PM

    startというプロシージャを、最初にシートに作ったボタンから起動するように設定すると、

    この部分の設定の仕方がわかりません、教えていただきたいです

    • *you
      2016年8月5日 7:32 PM

      hhgmさん、2項目上の「起動ボタンをつくる」の部分をご覧ください。

コメントを残す




*印は必須項目です。コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にですがスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)


back to top