ExcelVBA自作カレンダーコントロールへ祝日・休日設定する
前回のカレンダー作成のときに書いた「専用シートを作ってフラグを立てといて参照する」というのを、頭の中にせっかく浮かんだんだから、書いてみようかなーと思いました。
前置き
こちらの記事の続きです。
今回は、表示の度に日付の色をリセットするので、フォームでの色設定はデフォルトのままでOKです。
前回設定したこの手順がいらなくなります。
休日リストをつくる
シート名はなんでも良いですが、このように作ってみます。行が月、列が日で31まで。休みにしたい日に 1 を入れてみます。
コード
UserForm2
(カレンダーを描いたフォーム)のコード画面に、前回こういうプロシージャを書いているはず。
Private Sub clndr_set() 'カレンダーの作成と表示 Dim yy As Integer, mm As Integer, i As Integer, n As Integer, endDay As Integer If Me.ComboBox1 = "" Or Me.ComboBox2 = "" Then Exit Sub '年か月どちらか入ってなければ中止 yy = Me.ComboBox1 '年 mm = Me.ComboBox2 '月 For i = 1 To 42 'ラベルの初期化 Me("Label" & i).Caption = "" Me("Label" & i).BackColor = Me.BackColor Next n = Weekday(yy & "/" & mm & "/" & 1) - 1 'その月の1日の曜日番号に、マイナス1したもの endDay = Day(DateAdd("d", -1, DateAdd("m", 1, yy & "/" & mm & "/" & "1"))) '月末日の算出 For i = 1 To endDay Me("Label" & i + n).Caption = i '日を入れる If CDate(yy & "/" & mm & "/" & i) = the_date Then Me("Label" & i + n).BackColor = RGB(255, 255, 0) 'TextBoxの日と同じなら色をつける Next i End Sub
ここに、以下のハイライト部分を追記します。
Private Sub clndr_set() 'カレンダーの作成と表示 Dim yy As Integer, mm As Integer, i As Integer, n As Integer, endDay As Integer Dim fnd As Range If Me.ComboBox1 = "" Or Me.ComboBox2 = "" Then Exit Sub '年か月どちらか入ってなければ中止 yy = Me.ComboBox1 '年 mm = Me.ComboBox2 '月 For i = 1 To 42 'ラベルの初期化 Me("Label" & i).Caption = "" Me("Label" & i).BackColor = Me.BackColor If i Mod 7 = 1 Then '日曜 Me("Label" & i).ForeColor = RGB(255, 0, 0) '赤 ElseIf i Mod 7 = 0 Then '土曜 Me("Label" & i).ForeColor = RGB(0, 0, 255) '青 Else 'それ以外 Me("Label" & i).ForeColor = RGB(0, 0, 0) '黒 End If Next n = Weekday(yy & "/" & mm & "/" & 1) - 1 'その月の1日の曜日番号に、マイナス1したもの endDay = Day(DateAdd("d", -1, DateAdd("m", 1, yy & "/" & mm & "/" & "1"))) '月末日の算出 For i = 1 To endDay Me("Label" & i + n).Caption = i '日を入れる If CDate(yy & "/" & mm & "/" & i) = the_date Then Me("Label" & i + n).BackColor = RGB(189, 231, 255) 'TextBoxの日と同じなら色をつける With Sheets("休日リスト") Set fnd = .Range("A2:A1000").Find(yy) '年を検索 If Not fnd Is Nothing Then '見つかったら If .Cells(fnd.Row + mm - 1, i + 2) = 1 Then Me("Label" & i + n).ForeColor = RGB(255, 0, 0) '赤 End If End With Next i End Sub
12~18行目でカレンダーの日付の色をリセットしています。数値を変えれば好きな曜日を好きな色に出来るので、土日休みじゃないお仕事の方にもいいかも。26~31行目が、さっき作ったシートから該当の日付セルを探してフラグが立ってるか参照している部分です。
まず、A列に該当の年があるか探して、見つかった時だけ処理します。該当の行番号は、年の入っていた行 + 月の数字 -1 なので、fnd.Row + mm - 1
となり、該当の列番号は、日付の数値 +2(A, B列分) で、i + 2
となります。
そこのセルに 1 が入ってたら、この日はお休みなので、ラベルの文字色を赤くします。(29行目)
これで走らせると、休日設定した部分が赤くなります。
休日出勤日も設定してみる
ここは祝日休みなんだけど、この土日は稼動日なんだよなー!なんてことも出来ます。
さっきは 1 にしてましたが、こんな感じに「休」「出」など好きな文字を入れておいて、
Private Sub clndr_set() 'カレンダーの作成と表示 Dim yy As Integer, mm As Integer, i As Integer, n As Integer, endDay As Integer Dim fnd As Range If Me.ComboBox1 = "" Or Me.ComboBox2 = "" Then Exit Sub '年か月どちらか入ってなければ中止 yy = Me.ComboBox1 '年 mm = Me.ComboBox2 '月 For i = 1 To 42 'ラベルの初期化 Me("Label" & i).Caption = "" Me("Label" & i).BackColor = Me.BackColor If i Mod 7 = 1 Then '日曜 Me("Label" & i).ForeColor = RGB(255, 0, 0) '赤 ElseIf i Mod 7 = 0 Then '土曜 Me("Label" & i).ForeColor = RGB(0, 0, 255) '青 Else 'それ以外 Me("Label" & i).ForeColor = RGB(0, 0, 0) '黒 End If Next n = Weekday(yy & "/" & mm & "/" & 1) - 1 'その月の1日の曜日番号に、マイナス1したもの endDay = Day(DateAdd("d", -1, DateAdd("m", 1, yy & "/" & mm & "/" & "1"))) '月末日の算出 For i = 1 To endDay Me("Label" & i + n).Caption = i '日を入れる If CDate(yy & "/" & mm & "/" & i) = the_date Then Me("Label" & i + n).BackColor = RGB(189, 231, 255) 'TextBoxの日と同じなら色をつける With Sheets("休日リスト") Set fnd = .Range("A2:A1000").Find(yy) '年を検索 If Not fnd Is Nothing Then '見つかったら If .Cells(fnd.Row + mm - 1, i + 2) = "休" Then Me("Label" & i + n).ForeColor = RGB(255, 0, 0) '赤 If .Cells(fnd.Row + mm - 1, i + 2) = "出" Then Me("Label" & i + n).ForeColor = RGB(0, 0, 0) '黒 End If End With Next i End Sub
「休」なら赤、「出」なら黒、というように色をつけてあげます。
走らせると、こんな感じ。
所感
休日リストのシートはひとつのブックで独立なので、汎用性はありません。少人数、少ブックでやるのなら、って感じでしょうか。ネット環境がなくても動く、自由に設定出来る、というメリットの反面、使い方は限定的になっちゃいますが、こういう方法もあるということで。
ExcelVBAに興味をお持ちの方は、こちらの記事もどうぞ!
- これからExcelのマクロを始めたいという方に!簡単な練習問題作りました。
- 私がExcelVBAでよく使う便利なコード・スニペットまとめ
- プログラム初心者さんへ贈る、エラーが起きたら試してみて欲しいこと
- ExcelVBAのクラスモジュールって何?という人向けの使い方まとめ
書籍を執筆しています。
11件のコメント
休日リストのA列にだけ日付を入れて休日指定したいのですが
どのようにしたら良いかご教示頂けますでしょうか?
teruさん、コメントありがとうございます。「休日リスト」シートから休日を検索する部分を、
こうすればいいんじゃないかなーと思います。
ありがとうございます。
ちょっと気になる点がありまして、コンボボックスで西暦を手入力すると
追加したSet fndの行でエラーになってしまいます。
使用には差し支えないのですが何がいけないのでしょうか?
DLした方は問題ないです(4桁まで)
ああー、コンボボックスの手入力は考えてなかったです。
.Find
は日付の検索に不安定な動きをすることがあるので、それかもしれませんね。A列の最終端を取得して、ループで回すほうが確実かもしれません。昔書いたコードなので宣言とかイケてないなと思って、プロシージャごと書き直してみました。
これで動くと思います。ただ、コンボボックスに4桁より大きい数値を入れるとか、文字列入れちゃうとか、そういうエラー処理はしておりませんのでご了承ください。
教えて頂きましたコードにて業務で使える最高の
カレンダーツールとなりました。
分かりやすくてとても参考になります。
ありがとうございました。
お役に立てまして光栄ですー! (*´∀`) コンボボックスに日付として認識されない数や文字列が直接入力された場合のエラー処理、気になったので追記しました。
こちらのページのコメント欄に書きましたので、ご参照ください。
とても分かりやすいご説明で、助かりました。form1をアレンジし、オプションボタンとコマンドボタン、フレームで、異なる国のカレンダーを表示できるようになりました。気になるのは、祝日のフォントのみ太字にどうにか設定できないかな、ラベルクリックで何の祝日なのかを表示できないかと模索しています。
Mimiさん、コメントありがとうございます。本文中に示したマトリクス状の「休日リスト」で、休日のセルに「1」の代わりに「祝日の名称」が入っているものと仮定すると、こんな感じでしょうか。
ラベルコントロールの
Tag
というプロパティに、セルの内容を入れておきます。あとは、クリックで走るプロシージャにてこのように、該当ラベルコントロールの
Tag
の内容をメッセージボックスで表示できます。ありがとうございます。残念ながらまだ休日表示ができていません。フォーム1のUIを変更したのが原因なのかと思い、1から組み直してみたりしていますが実装にいたっておりません。
素晴らしいコードの提供ありがとうございます。とても使いやすいです。
dtpickerがなくなり途方に暮れておりました。
伊藤さん、コメントありがとうございます。お役に立ててとっても嬉しいです!
コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)
YouTubeでQ&Aコンテンツを企画しています
運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。