【簡単Excelマクロ・VBA】カレンダーを作成する|アプリ事例 #005
いつもありがとうございます。
ノンプログラマー向けの「Excelマクロ・VBAアプリ事例解説シリーズ」へようこそ。
本稿では、「カレンダーを作成するアプリ」をお届けいたします。
皆さんは、カレンダーを作成したいときはないでしょうか。
例えば、勤務シフト表や当番表を作成するときなどです。
カレンダの作成を手作業で行うのは、非常に時間がかかりますし、ミスも起こりがちです。
しかし、このような作業は、VBAを使えば簡単に自動化することができます。
VBAで自分に合ったアプリを作成し、仕事量は半分に、成果は2倍にしていきましょう。
初心者でも理解しやすいように、分かりやすく解説していきます。ぜひご覧ください。
ことばの意味
- ノンプログラマー
プログラミングを主な仕事にしていない人たちのことです。 - マクロ
VBAを使って作成される「機能」のことです。 - VBA
Visusal Basic for Application の略で、プログラミング言語のことです。
関連記事
VBAでカレンダを作成する方法
アプリの仕様
Excelシート上で、対象年月を指定してカレンダーを自動作成します。カレンダーは、新しいブックを作成し、そのシートに表示します。作成したブックは保存はせず、新規ブックとして開いたままにします。必要に応じて「名前を付けて保存」などの操作を手動で行うことを想定しています。
Excelシートの設計
まず、年月を指定するためのExcelシートを準備します。下図のようなシートを作成しましょう。メニューからマクロを実行するのは手間がかかるため、下図にあるような「カレンダー作成」ボタンも作成しておきます。このボタンにマクロを登録し、クリックするとマクロが動作するように設定します。マクロの登録手順については、後述します。
コードの実装
カレンダを作成するコードと、その実行結果を以下に示します。
Sub CreateCalendar()
' 変数宣言
Dim this_wb As Workbook ' 現在のブック
Dim this_wb_ws1 As Worksheet ' 現在のブックの1つ目のシート
Dim new_wb As Workbook ' 新しく作成するブック
Dim new_wb_ws1 As Worksheet ' 新しく作成するブックの1つ目のシート
Dim new_window As Window ' 新しいブックのウィンドウ
Dim user_input_year As Long ' ユーザーが入力した年
Dim user_input_month As Long ' ユーザーが入力した月
Dim last_day_of_month As Long ' 指定した月の最終日
Dim column_index As Long ' 曜日に基づく列インデックス
Dim row_index As Long ' 行インデックス
Dim day_counter As Long ' 日数カウンター
Dim weekday_name As String ' 曜日名
Dim row_position As Long ' 枠線調整のための行位置
' 定数の定義:カレンダーの開始列と行を設定
Const START_COLUMN As Long = 2 ' カレンダーの開始列
Const START_ROW As Long = 3 ' カレンダーの開始行
' 現在のブックとシートを変数に代入
Set this_wb = ThisWorkbook
Set this_wb_ws1 = this_wb.Worksheets(1)
' 新しいカレンダー用のブックとシートを作成
Set new_wb = Workbooks.Add
Set new_wb_ws1 = new_wb.Worksheets(1)
' 年と月をシートから取得
user_input_year = this_wb_ws1.Cells(5, 3).Value
user_input_month = this_wb_ws1.Cells(5, 4).Value
' カレンダーのタイトル(年と月)を新しいシートに書き込み
new_wb_ws1.Cells(2, START_COLUMN).Value = "'" & user_input_year & "年" & user_input_month & "月"
' 月の最終日を取得
last_day_of_month = Day(DateSerial(user_input_year, user_input_month + 1, 1) - 1)
' 行インデックスの初期化
row_index = START_ROW
' 各日付のループ処理
For day_counter = 1 To last_day_of_month
' 曜日名(例: 月、火、水...)を取得
weekday_name = WeekdayName(Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday), True)
' 曜日から列インデックスを計算(列の位置を設定)
column_index = Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday) + START_COLUMN - 1
' 日付と曜日をカレンダーに入力
With new_wb_ws1.Cells(row_index, column_index)
.Value = day_counter
If weekday_name = "土" Then .Font.ColorIndex = 5 ' 土曜日のフォントカラーを青に
If weekday_name = "日" Then .Font.ColorIndex = 3 ' 日曜日のフォントカラーを赤に
End With
With new_wb_ws1.Cells(row_index + 1, column_index)
.Value = weekday_name
If weekday_name = "土" Then .Font.ColorIndex = 5
If weekday_name = "日" Then .Font.ColorIndex = 3
End With
' 日付と曜日のセルを中央寄せに設定
Range(new_wb_ws1.Cells(row_index, column_index), new_wb_ws1.Cells(row_index + 3, column_index)).HorizontalAlignment = xlCenter
' もし土曜日なら次の行に移動
If Not day_counter = last_day_of_month Then
If column_index = START_COLUMN + 6 Then row_index = row_index + 3
End If
Next day_counter
' カレンダーの枠線を作成
With Range(new_wb_ws1.Cells(START_ROW, START_COLUMN), new_wb_ws1.Cells(row_index + 2, START_COLUMN + 6))
.Borders(xlEdgeTop).LineStyle = xlContinuous ' 上の枠線を連続線で設定
.Borders(xlEdgeBottom).LineStyle = xlContinuous ' 下の枠線を連続線で設定
.Borders(xlEdgeRight).LineStyle = xlContinuous ' 右の枠線を連続線で設定
.Borders(xlEdgeLeft).LineStyle = xlContinuous ' 左の枠線を連続線で設定
.Borders(xlInsideVertical).LineStyle = xlContinuous ' 垂直方向の内側の枠線を連続線で設定
.Borders(xlInsideHorizontal).LineStyle = xlContinuous ' 水平方向の内側の枠線を連続線で設定
End With
' 水平枠線の調整:行ごとの枠線を非表示にし、薄い枠線を追加
For row_position = START_ROW To row_index + 1 Step 3 ' カレンダーの各行を3行ごとに処理
' 対象行の枠内のセル範囲を選択し、水平の内側の枠線を非表示に設定
Range(new_wb_ws1.Cells(row_position, START_COLUMN), _
new_wb_ws1.Cells(row_position + 1, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).LineStyle = xlNone
' 次の行のセル範囲を選択し、薄い線で水平の枠線を描画
Range(new_wb_ws1.Cells(row_position + 1, START_COLUMN), _
new_wb_ws1.Cells(row_position + 2, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).Weight = xlHairline
Next row_position ' 次の3行に進む
' グリッド線を非表示にする
Set new_window = Application.Windows(new_wb.Name)
new_window.DisplayGridlines = False
End Sub
このコードを実行すると、下図のようなカレンダが表示されます。
解説していきます。
' 変数宣言
Dim this_wb As Workbook ' 現在のブック
Dim this_wb_ws1 As Worksheet ' 現在のブックの1つ目のシート
Dim new_wb As Workbook ' 新しく作成するブック
Dim new_wb_ws1 As Worksheet ' 新しく作成するブックの1つ目のシート
Dim new_window As Window ' 新しいブックのウィンドウ
Dim user_input_year As Long ' ユーザーが入力した年
Dim user_input_month As Long ' ユーザーが入力した月
Dim last_day_of_month As Long ' 指定した月の最終日
Dim column_index As Long ' 曜日に基づく列インデックス
Dim row_index As Long ' 行インデックス
Dim day_counter As Long ' 日数カウンター
Dim weekday_name As String ' 曜日名
Dim row_position As Long ' 枠線調整のための行位置
ここでは、コード内で使用する変数が宣言されています。変数は Dim 変数名 As データ型
の構文で宣言します。これにより、各変数は As
以降で指定したデータ型のデータを格納できるようになります。
' 定数の定義:カレンダーの開始列と行を設定
Const START_COLUMN As Long = 2 ' カレンダーの開始列
Const START_ROW As Long = 3 ' カレンダーの開始行
ここでは、カレンダーを作成する際に使用する「開始列」と「開始行」を定数として定義しています。
定数は、Const
キーワードを使って宣言します。定数とは、一度設定されたら変更することができない固定された値のことです。今回の場合は、カレンダーがExcelシートのどの位置から始まるかを指定するために、この定数を使用しています。
START_COLUMN
はカレンダが始まる列番号を、START_ROWは
カレンダが始まる行番号を指定しています。
' 現在のブックとワークシートを変数に代入
Set this_wb = ThisWorkbook
Set this_wb_ws1 = this_wb.Worksheets(1)
ここでは、オブジェクト変数 this_wb
と this_wb_ws1
に、それぞれワークブックオブジェクトとそのワークシートオブジェクトを代入しています。なお、ThisWorkbook
は現在のワークブック、つまりこのコードが記述されているワークブックを指します。
' 新しいカレンダー用のブックとシートを作成
Set new_wb = Workbooks.Add
Set new_wb_ws1 = new_wb.Worksheets(1)
ここでは、オブジェクト変数 new_wb
と new_wb_ws1
に、それぞれ新しく作成したワークブックオブジェクトとそのワークシートオブジェクトを代入しています。
Workbooks.Add
は、新しいワークブックを作成するためのメソッドです。このメソッドを使うことで、現在のブックとは別に新しいブックが開かれ、それを new_wb
に代入しています。
' 年と月をシートから取得
user_input_year = this_wb_ws1.Cells(5, 3).Value
user_input_month = this_wb_ws1.Cells(5, 4).Value
ここでは、シートに入力されている年と月の情報をそれぞれ user_input_year
と user_input_month
という変数に代入しています。
this_wb_ws1.Cells(5, 3)
は、シートの5行目3列目、つまりセル C5
を表します。
同様に、this_wb_ws1.Cells(5, 4)
は、セル D5
を表しています。
' カレンダーのタイトル(年と月)を新しいシートに書き込み
new_wb_ws1.Cells(2, START_COLUMN).Value = "'" & user_input_year & "年" & user_input_month & "月"
ここでは、カレンダーのタイトルとして「年」と「月」の情報を、新しく作成したシート(new_wb_ws1
)に書き込んでいます。先ほど定義した定数START_COLUMN
、START_ROW
を活用しています。
' 月の最終日を取得
last_day_of_month = Day(DateSerial(user_input_year, user_input_month + 1, 1) - 1)
ここでは、指定された月の最終日を取得して、変数 last_day_of_month
に代入しています。
DateSerial(user_input_year, user_input_month + 1, 1)
:DateSerial
関数は、指定された年・月・日を持つ日付を返します。ここでは、ユーザーが入力した年 (user_input_year
) と月 (user_input_month
) に対して、月を1つ増やして「次の月の1日」を作成します。-1
の意味:
「次の月の1日」から1日引くことで、現在の月の最終日を取得しています。例えば、10月の最終日を知りたい場合は、11月1日から1日引くことで10月31日を得ることができます。Day
関数:Day
関数は、指定された日付から日(1〜31)を抽出する関数です。DateSerial
で得られた日付(例えば10月31日)の「日」の部分だけを取得して、それをlast_day_of_month
に代入します。
' 各日付のループ処理
For day_counter = 1 To last_day_of_month
' 曜日名(例: 月、火、水...)を取得
weekday_name = WeekdayName(Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday), True)
' 曜日から列インデックスを計算(列の位置を設定)
column_index = Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday) + START_COLUMN - 1
' 日付と曜日をカレンダーに入力
With new_wb_ws1.Cells(row_index, column_index)
.Value = day_counter
If weekday_name = "土" Then .Font.ColorIndex = 5 ' 土曜日のフォントカラーを青に
If weekday_name = "日" Then .Font.ColorIndex = 3 ' 日曜日のフォントカラーを赤に
End With
With new_wb_ws1.Cells(row_index + 1, column_index)
.Value = weekday_name
If weekday_name = "土" Then .Font.ColorIndex = 5
If weekday_name = "日" Then .Font.ColorIndex = 3
End With
' 日付と曜日のセルを中央寄せに設定
Range(new_wb_ws1.Cells(row_index, column_index), new_wb_ws1.Cells(row_index + 3, column_index)).HorizontalAlignment = xlCenter
' もし土曜日なら次の行に移動
If Not day_counter = last_day_of_month Then
If column_index = START_COLUMN + 6 Then row_index = row_index + 3
End If
Next day_counter
ここでは、指定された月の日付を順番に処理して、各日付とその曜日をカレンダーに入力するループ処理を行っています。
' 各日付のループ処理
For day_counter = 1 To last_day_of_month
まず、For
ループを使って、1日からその月の最終日まで(last_day_of_month
)の各日付を順に処理しています。day_counter
は日付を表すカウンターで、ループの中で日付ごとの処理を行います。
' 曜日名(例: 月、火、水...)を取得
weekday_name = WeekdayName(Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday), True)
ここでは、指定された年と月の日付に対して、曜日を取得し、それをカレンダーに反映させる処理を行っています。
DateSerial(user_input_year, user_input_month, day_counter)
で、指定された年と月のday_counter
の日付を作成します。Weekday
関数は、この日付が何曜日かを数値(1=日曜日, 2=月曜日...)で返します。WeekdayName
関数は、Weekday
で得られた数値をもとに、曜日の名前(「月」、「火」など)を返します。vbSunday
を使って、週の始まりを日曜日として扱っています。- 最後の
True
は、曜日の名前を短縮形(例:「月」、「火」)で取得する指定です。
' 曜日から列インデックスを計算(列の位置を設定)
column_index = Weekday(DateSerial(user_input_year, user_input_month, day_counter), vbSunday) + START_COLUMN - 1
ここでは、取得した曜日をもとに、カレンダーのどの列に日付を入力するかを計算しています。
Weekday
関数で曜日の数値を取得し、START_COLUMN
に加算して列の位置を決定しています。TART_COLUMN - 1
をすることで、適切な列位置に調整しています。
' 日付と曜日をカレンダーに入力
With new_wb_ws1.Cells(row_index, column_index)
.Value = day_counter
If weekday_name = "土" Then .Font.ColorIndex = 5 ' 土曜日のフォントカラーを青に
If weekday_name = "日" Then .Font.ColorIndex = 3 ' 日曜日のフォントカラーを赤に
End With
ここでは、new_wb_ws1.Cells(row_index, column_index)
で、計算された行 (row_index
) と列 (column_index
) に日付を入力しています。
合わせて、土曜日はフォントカラーを青(ColorIndex = 5
)、日曜日は赤(ColorIndex = 3
)に設定することで、カレンダー上で見やすくしています。
With new_wb_ws1.Cells(row_index + 1, column_index)
.Value = weekday_name
If weekday_name = "土" Then .Font.ColorIndex = 5
If weekday_name = "日" Then .Font.ColorIndex = 3
End With
ここでは、日付の下の行に、その日の曜日を入力しています。こちらも、土曜日は青、日曜日は赤に設定しています。
' 日付と曜日のセルを中央寄せに設定
Range(new_wb_ws1.Cells(row_index, column_index), new_wb_ws1.Cells(row_index + 3, column_index)).HorizontalAlignment = xlCenter
ここでは、row_index
から3行分の範囲に対して、セルの内容を中央寄せに設定しています。これにより、カレンダーが整ったレイアウトになります。
' もし土曜日なら次の行に移動
If Not day_counter = last_day_of_month Then
If column_index = START_COLUMN + 6 Then row_index = row_index + 3
End If
ここでは、土曜日が来た場合や月の最終日ではない場合に、カレンダーの次の行に移動する処理を行っています。
If Not day_counter = last_day_of_month Then
:- この行は、「現在処理している日付が月の最終日でない場合」に次の処理を行うための条件です。
day_counter
がlast_day_of_month
と一致しない場合(つまり、まだ最終日ではない場合)、その後のIf
条件が実行されます。 - これにより、月の最終日において無駄な行移動を防ぐことができます。カレンダーの最終日をしっかり処理し、不要な操作をしないようにしています。
- この行は、「現在処理している日付が月の最終日でない場合」に次の処理を行うための条件です。
If column_index = START_COLUMN + 6 Then row_index = row_index + 3
:column_index = START_COLUMN + 6
の条件は、現在処理している日付が土曜日(カレンダーの1週間の最後の日)であることを確認するためのものです。土曜日は1週間の最終日なので、次の行に移動する必要があります。
' カレンダーの枠線を作成
With Range(new_wb_ws1.Cells(START_ROW, START_COLUMN), new_wb_ws1.Cells(row_index + 2, START_COLUMN + 6))
.Borders(xlEdgeTop).LineStyle = xlContinuous ' 上の枠線を連続線で設定
.Borders(xlEdgeBottom).LineStyle = xlContinuous ' 下の枠線を連続線で設定
.Borders(xlEdgeRight).LineStyle = xlContinuous ' 右の枠線を連続線で設定
.Borders(xlEdgeLeft).LineStyle = xlContinuous ' 左の枠線を連続線で設定
.Borders(xlInsideVertical).LineStyle = xlContinuous ' 垂直方向の内側の枠線を連続線で設定
.Borders(xlInsideHorizontal).LineStyle = xlContinuous ' 水平方向の内側の枠線を連続線で設定
End With
ここでは、カレンダー全体に枠線を設定しています。特に、カレンダーを囲む外側の枠線と、内部の各セルを区切る内側の枠線を指定しています。
Range(new_wb_ws1.Cells(START_ROW, START_COLUMN), new_wb_ws1.Cells(row_index + 2, START_COLUMN + 6))
では、カレンダーの最初のセルから最後のセルまでの範囲を指定しています。つまり、START_ROW
と START_COLUMN
はカレンダーの開始位置、row_index + 2
と START_COLUMN + 6
はカレンダーの終端を指しています。
' 水平枠線の調整:行ごとの枠線を非表示にし、薄い枠線を追加
For row_position = START_ROW To row_index + 1 Step 3 ' カレンダーの各行を3行ごとに処理
' 対象行の枠内のセル範囲を選択し、水平の内側の枠線を非表示に設定
Range(new_wb_ws1.Cells(row_position, START_COLUMN), _
new_wb_ws1.Cells(row_position + 1, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).LineStyle = xlNone
' 次の行のセル範囲を選択し、薄い線で水平の枠線を描画
Range(new_wb_ws1.Cells(row_position + 1, START_COLUMN), _
new_wb_ws1.Cells(row_position + 2, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).Weight = xlHairline
Next row_position ' 次の3行に進む
ここでは、カレンダーの水平枠線を調整するために、3行ごとに枠線のスタイルを変更しています。具体的には、一部の枠線を非表示にし、その後で薄い枠線(xlHairline
)を追加することで、カレンダーのデザインを整えています。
' 水平枠線の調整:行ごとの枠線を非表示にし、薄い枠線を追加
For row_position = START_ROW To row_index + 1 Step 3 ' カレンダーの各行を3行ごとに処理
For
ループで、カレンダーの行ごとに処理を行っています。ここでは、START_ROW
から row_index + 1
までを、3行ずつ (Step 3
) 移動しながら処理を進めています。このカレンダー上では、1週間を3行で表しているため、3行ずつ (Step 3
)ずつ移動しています。
' 対象行の枠内のセル範囲を選択し、水平の内側の枠線を非表示に設定
Range(new_wb_ws1.Cells(row_position, START_COLUMN), _
new_wb_ws1.Cells(row_position + 1, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).LineStyle = xlNone
Range
で、現在の row_position
から次の行 (row_position + 1
) までの範囲を選択しています。この範囲内のセルに対して、水平の内側の枠線(xlInsideHorizontal
)を非表示に設定しています。LineStyle = xlNone
を指定することで、枠線が非表示になります。
' 次の行のセル範囲を選択し、薄い線で水平の枠線を描画
Range(new_wb_ws1.Cells(row_position + 1, START_COLUMN), _
new_wb_ws1.Cells(row_position + 2, START_COLUMN + 6)) _
.Borders(xlInsideHorizontal).Weight = xlHairline
次に、row_position + 1
から row_position + 2
までの範囲に対して、水平枠線を薄い線(xlHairline
)で描画しています。xlHairline
は最も薄い枠線のスタイルで、見た目を軽くし、視覚的にカレンダーがすっきり見えるようにしています。
' グリッド線を非表示にする
Set new_window = Application.Windows(new_wb.Name)
new_window.DisplayGridlines = False
ここでは、新しく作成したワークブックのワークシート(new_wb_ws1
)に表示されているグリッド線を非表示に設定しています。
Set new_window = Application.Windows(new_wb.Name)
:Application.Windows(new_wb.Name)
を使って、新しく作成したブック(new_wb
)のウィンドウオブジェクトを取得し、それを変数new_window
に代入しています。これにより、新しいブックのウィンドウに対して操作を行えるようになります。new_window.DisplayGridlines = False
:
取得したウィンドウオブジェクトのDisplayGridlines
プロパティをFalse
に設定することで、シートのグリッド線(セルの境界線としてデフォルトで表示されている点線)を非表示にしています。グリッド線が消えることで、カレンダーがより見やすくなります。
以上で、「コードの実装」の解説は終了です。ありがとうございました。
ボタンへのマクロの登録
次にボタンにマクロを登録する方法を解説します。
ボタンにマクロを登録し、これをクリックすることによりマクロが動くようにします。これをすることにより、いちいち表示メニューからマクロを実行する必要がなくなり、作業効率が上がります。
アプリをコミュニティに配布するのであれば、ユーザーの使い勝手を考えてこのようにしておくと親切です。
まず、ボタンの上で「右クリック」し、「マクロの登録」を選択します。
次のようなダイアログが表示されますので、該当のマクロ名(今回は、CreateCalendar)を選択し、「OK」を押下します。
以上でマクロの登録は完了です。
これで、ボタンをクリックするとマクロが動くようになりました。
以上で、「マクロの登録」の解説は終了です。ありがとうございました。
おわりに
ご覧いただきありがとうございました。
本稿では、「カレンダを作成するアプリ」の紹介をいたしました。
お問い合わせやご要望等ございましたら、「お問い合わせ/ご要望」またはコメントにて、ご連絡いただければ幸いでございます。
皆様の人生がより一層素晴らしいものになるよう、少しでもお役に立てれば幸いでございます。
なお、当サイトでは様々な情報を発信しております。もしよろしければ、トップページもご確認いただけると幸いでございます。
筆者の記事関連経験
- VBA使用経験約20年
実務に使用するマクロを多数作成してきました。 - Python 3 エンジニア認定基礎試験
経済産業省が定めたガイドライン「ITスキル標準(ITSS)」に掲載されている民間資格です。
VBAプログラミングスキルアップのための参考情報
ここでは参考図書を紹介いたしますが、これらに限らず自分に合うものを選ぶことが重要だと考えております。皆様の、より一層のご成功を心よりお祈りしております。
VBAプログラミングのスキルアップ
学習用としてもハンドブックとしても役立つ便利な書籍がこちらです。価格はやや高めですが、その内容は非常に充実しています。相応のスキルを身に付けるためには、こうしたしっかりとした書籍を一冊持っておくと良いでしょう。
入門書に関しては、どの書籍も大きな違いはありません。あまり迷うことに時間をかけるよりは、手頃なものを一冊選んでみると良いでしょう。VBAの入門書は数多く出版されていますので、興味がある方はぜひチェックしてみてください。
甲乙つけがたい場合、私はインプレス社の「いちばんやさしい」シリーズを選ぶことが多いです。
\チェックしてみよう/
\チェックしてみよう/
\チェックしてみよう/
VBAのプログラミング能力を客観的に証明したい場合には「VBAエキスパート試験」があります。この試験はVBAの知識を公式に認定するものです。VBAの総合的な能力獲得を目指す方に適しています。以下の公式テキストが販売されております。
プログラミングの一般教養
「独学プログラマー」というプログラミングの魅力を解説した書籍があります。これはVBAではなくPythonを題材としていますが、プログラミングの基本的な知識や思考法、仕事の進め方まで幅広く学べます。
こちらの記事でも紹介しております。もしよろしければご覧ください。