Sub MakeCal()
Range("4:6").Clear
Range("A4") = "日付"
Range("A5") = "曜日"
Dim A, B, C
A = DateSerial(Range("A2"), Range("A3"), 1) '指定月の1日
B = DateSerial(Range("A2"), Range("A3") + 1, 0) '指定月の月末
ReDim C(1 To 2, 1 To 31)
k = 0
For i = A To B
k = k + 1
C(1, k) = i '日付を入力
C(2, k) = i '日付を入力
Next
Range("B4").Resize(2, 31) = C 'セルに入力
End Sub
年と月は、入力しておきます。
年と月を入力しておく
実行すると、日付と曜日が入力されます。
日付と曜日が入力される
さらに実行すると、日付と曜日用の2行分の日付が入力されます。
日付が2行分入力される
日付が2行分入力されます。
列幅を調整するとこんな感じです。
日付と曜日用で、2行分の日付を入力できました。
書式を入力
次は、書式を入力していきます。
書式を入力するVBAコードです。
Sub SetFormat()
Range("B4").Resize(, 31).NumberFormatLocal = "d" '「日」を表示
Range("B5").Resize(, 31).NumberFormatLocal = "aaa" '「曜日」を表示
Range("A4").Resize(3, 32).Borders.LineStyle = xlContinuous '罫線
Dim A
For Each A In Range("B4").Resize(, 31)
If Format(A, "aaa") = "日" Then
'日曜日を塗りつぶし
A.Resize(3).Interior.Color = RGB(252, 228, 214)
ElseIf Format(A, "aaa") = "土" Then
'土曜日を塗りつぶし
A.Resize(3).Interior.Color = RGB(221, 235, 247)
End If
Next
End Sub
実行すると、日付を「"d"」形式の表示形式が設定されます。
日付を「"d"」形式にする
次に、曜日を「"aaa"」形式の表示形式が設定されます。
曜日を「"aaa"」形式にする
次は、罫線を引きます。
罫線を引く
日付をループして、日曜日と土曜日を塗りつぶししていきます。
日曜日と土曜日を塗りつぶししていく
日付を1か月分ループしていきます。
日曜日を塗りつぶしします。
土曜日を塗りつぶしします。
日曜日を塗りつぶしします。
土曜日を塗りつぶしします。
日曜日を塗りつぶしします。
土曜日を塗りつぶしします。
日曜日を塗りつぶしします。
土曜日を塗りつぶしします。
日曜日を塗りつぶしします。
という感じで、書式を設定していきます。
これで、祝日以外の2022年5月のカレンダーを作成できます。
2022年5月のカレンダーが作成できた
2022年5月のカレンダーを作成できました。
祝日の反映
次は、カレンダーに祝日を反映していきます。
祝日のデータを入力
祝日のデータをあらかじめ、別シートに入力しておきます。
祝日のデータを入力しておく
こちらの祝日をカレンダーに反映していきます。
祝日をカレンダーに反映
祝日をカレンダーに反映するVBAコードです。
流れは、
指定した年と月の祝日を抽出
抽出した値をループしていく
カレンダーの日付の位置を探して塗りつぶし
という感じです。
VBAコードは、次のようになります。
Sub GetHoliday()
Dim A, B
With Sheets("月")
A = DateSerial(.Range("A2"), .Range("A3"), 1) '指定月の1日
B = DateSerial(.Range("A2"), .Range("A3") + 1, 0) '指定月の月末
End With
With Sheets("祝日")
'指定月でフィルタ
.Range("A1").AutoFilter 3, ">=" & A, xlAnd, "<=" & B
.Range("A1").CurrentRegion.Copy .Range("E1") 'フィルタ結果をコピー
.Range("A1").AutoFilter 'フィルタを解除
End With
For i = 2 To Sheets("祝日").Cells(Rows.Count, "G").End(xlUp).Row
With Sheets("月").Range("A4").Offset(0, Day(Sheets("祝日").Cells(i, "G")))
'祝日を塗りつぶし
.Resize(3).Interior.Color = RGB(252, 228, 214)
End With
Next
'コピーした値をクリア
Sheets("祝日").Range("E1").CurrentRegion.ClearContents
End Sub
では、VBAコードを実行してみます。
「2022年5月」の祝日を抽出していきます。
「2022年5月」のデータを抽出する
祝日を「2022年5月」でフィルタします。
フィルタ結果を別セルにコピーします。
フィルタを解除します。
抽出した日付をループして、塗りつぶししていきます。
抽出した日付をループして塗りつぶししていく
コピーした日付をループしていきます。
日付でセル位置を取得して、塗りつぶしをします。
次の祝日に移動して、日付でセル位置を取得して、塗りつぶしをします。
同じように、次の祝日に移動して、日付でセル位置を取得して、塗りつぶしをします。
祝日をカレンダーに反映できました。
コピーした値は不要なので、クリアします。
コピーした値をクリア
これで、祝日を反映して、横型の月間カレンダーを作成できます。
祝日を反映した横型の月間カレンダーが完成
祝日を反映して、月間の横型カレンダーを作成できました。
年と月の更新で実行するイベントを作成
簡単にカレンダーを更新できるように、年と月の更新で実行するイベントを作成していきます。
年と月を更新でカレンダーを作成
年と月を更新で、カレンダーを作成するVBAコードを実行するVBAコードです。
「月」のシートモジュールに記載します。
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Range("A2:A3"), Target) Is Nothing Then Exit Sub
Call MakeCal 'カレンダーを作成
Call SetFormat '書式を設定
Call GetHoliday '祝日を反映
End Sub
Sub NextMonth()
Dim A
'1か月進める
A = DateAdd("m", 1, DateSerial(Range("A2"), Range("A3"), 1))
Range("A2") = Year(A) '年を取得
Range("A3") = Month(A) '月を取得
End Sub
↓「先月」に更新するVBAコードです。
Sub PreMonth()
Dim A
'1か月戻す
A = DateAdd("m", -1, DateSerial(Range("A2"), Range("A3"), 1))
Range("A2") = Year(A) '年を取得
Range("A3") = Month(A) '月を取得
End Sub
↓「今月」に更新するVBAコードです。
Sub ThisMonth()
Range("A2") = Year(Now()) '今年を取得
Range("A3") = Month(Now()) '今月を取得
End Sub
これで、ボタンを使ってカレンダーを更新することができます。
ボタンでカレンダーを更新
ボタンでカレンダーを更新してみます。
「翌月」ボタンで、翌月にカレンダーを更新できます。
ボタンで「翌月」を表示
「先月」ボタンで、先月にカレンダーを更新できます。
ボタンで「先月」を表示
「今月」ボタンで、今月にカレンダーを更新できます。
ボタンで「今月」を表示
ボタンでカレンダーを更新できると便利です。
データを取得する機能を追加
カレンダーに、データを取得する機能を追加すると便利になります。
データを取得する機能
データベースに登録した値を、カレンダーに反映する機能を追加してみます。
データベースの値をカレンダーに取得したい
こんな感じで、データベースからカレンダーに値を取得できます。
データベースからカレンダーに値を取得できるようになります。
データを取得する
データベースからカレンダーに、データを取得するVBAコードになります。
手順は、
指定した年と月でデータベースの値を抽出
抽出したデータをループする
日付からセル位置を取得してカレンダーに反映
という感じです。
データベースからカレンダーにデータを取得するVBAコードです。
Sub GetData()
Dim A, B
With Sheets("月")
A = DateSerial(.Range("A2"), .Range("A3"), 1) '指定月の1日
B = DateSerial(.Range("A2"), .Range("A3") + 1, 0) '指定月の月末
End With
With Sheets("DB")
'指定月をフィルタ
.Range("A1").AutoFilter 1, ">=" & A, xlAnd, "<=" & B
.Range("A1").CurrentRegion.Copy .Range("D1") 'フィルタ結果をコピー
.Range("A1").AutoFilter 'フィルタ解除
End With
For i = 2 To Sheets("DB").Cells(Rows.Count, "D").End(xlUp).Row
With Sheets("月").Range("A4")
'データを取得
.Offset(2, Day(Sheets("DB").Cells(i, "D"))) = Sheets("DB").Cells(i, "E")
End With
Next
'コピー結果をクリア
Sheets("DB").Range("E1").CurrentRegion.ClearContents
End Sub
最初に、データベースのシートを作成して、データを入力しておきます。
データベースのシートを作成してデータを入力しておく
データベースのシートを作成します。
データを入力しておきます。
では、VBAコードを実行してみます。
指定した年と月のデータを抽出する
実行すると、指定した月でフィルタされます。
フィルタ結果を別セルにコピーします。
フィルタを解除します。
これで、指定した年と月のデータを抽出できます。
次は、抽出した日付をループして値を取得していきます。
抽出した日付をループして値を取得していく
抽出した日付をループしていきます。
日付からセル位置を取得して、登録データを取得します。
カレンダーに登録データを取得できました。
コピーした値は不要なので、クリアされます。
コピーした値をクリア
これで、データベースからカレンダーに値を取得できます。
データベースからカレンダーに値を取得できた
データベースからカレンダーに値を取得できました。
年と月を変更で実行するイベントに追加
データベースから値を取得するVBAコードを、年と月を変更で実行するできるようにします。
先ほど作成したChangeイベントに「Call GetData」を追加します。
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Range("A2:A3"), Target) Is Nothing Then Exit Sub
Call MakeCal 'カレンダーを作成
Call SetFormat '書式を設定
Call GetHoliday '祝日を反映
Call GetData 'データを取得
End Sub
Sub WriteData()
Dim A
For Each A In Sheets("月").Range("B4").Resize(, 31)
'日付をフィルタ
Sheets("DB").Range("A1").AutoFilter 1, Format(A, "yyyy/m/d")
'登録データあり
If Application.Subtotal(103, Sheets("DB").Range("A:A")) > 1 Then
'値を書き込み
Sheets("DB").Cells(Rows.Count, "A").End(xlUp).Offset(0, 1) = A.Offset(2, 0)
'登録データなし
Else
If A.Offset(2, 0) <> "" Then '値がある場合'フィルタ解除
Sheets("DB").Range("A1").AutoFilter
With Sheets("DB").Cells(Rows.Count, "A").End(xlUp)
.Offset(1, 0) = A '日付を書き込み
.Offset(1, 1) = A.Offset(2, 0) '値を書き込み
End With
End If
End If
Next
'フィルタを解除
Sheets("DB").Range("A1").AutoFilter
End Sub
カレンダーの値を変更しておきます。
カレンダーの値を変更しておく
では、VBAコードを実行してみます。
カレンダーの日付をループしていきます。
カレンダーをループして、データを書き込みしていく
データ登録ありの場合は、データベースに値を書き込みします。
データ登録ありの場合は、値を書き込み
カレンダーの日付で、データベースをフィルタします。
日付のデータが登録されている場合は、データを書き込みます。
データベースに書き込みができました。
データ未登録で入力なしは、なにもしないで、次の日付へ移動します。
データ未登録で入力なしは、次の日付へ移動
次の日付でデータベースをフィルタします。
データベースが未登録で、カレンダーが入力なしの場合は、次の日付に移動します。
データベースは変更しないで、そのまま次のセルへ移動します。
データ未登録で入力ありの場合は、新規で書き込みをします。
データ未登録で入力ありの場合は、新規で書き込み
カレンダーの日付でフィルタします。
データベースに未登録で、カレンダーに入力がある場合は、データベースに書き込みしていきます。
データベースのフィルタを解除します。
データベースに日付を登録します。
データベースにカレンダーの値を登録します。
データベースにカレンダーの値を、新規で登録できました。
すべて書き込んだら、データベースのフィルタを解除します。
データベースのフィルタを解除
これで、データベースに値を書き込みできます。
カレンダーからデータベースに書き込みできた
データベースに値を書き込みできました。
書き込みのボタンを追加
データベースに値を書き込む際は、ボタンを使うと便利です。
書き込みのボタンを作成します。
書き込みのボタンを追加
ボタンに登録するVBAコードは、先ほどご紹介した書き込みのVBAコードになります。
ボタンに登録するVBAコード
Sub WriteData()
Dim A
For Each A In Sheets("月").Range("B4").Resize(, 31)
'日付をフィルタ
Sheets("DB").Range("A1").AutoFilter 1, Format(A, "yyyy/m/d")
'登録データあり
If Application.Subtotal(103, Sheets("DB").Range("A:A")) > 1 Then
'値を書き込み
Sheets("DB").Cells(Rows.Count, "A").End(xlUp).Offset(0, 1) = A.Offset(2, 0)
'登録データなし
Else
If A.Offset(2, 0) <> "" Then '値がある場合'フィルタ解除
Sheets("DB").Range("A1").AutoFilter
With Sheets("DB").Cells(Rows.Count, "A").End(xlUp)
.Offset(1, 0) = A '日付を書き込み
.Offset(1, 1) = A.Offset(2, 0) '値を書き込み
End With
End If
End If
Next
'フィルタを解除
Sheets("DB").Range("A1").AutoFilter
End Sub