少々の設定とコードのコピペで動作するようにまとめました。
「Excel シートにShapeカレンダー 1 」から「 4 」までのコードを2つのブロックにしました。
これに休日クラスを加えます。
シートのモジュール
Option Explicit '--------------------------------------- ' Private Sub Worksheet_SelectionChange(ByVal Target As Range) Dim DateFormats As Variant Dim DateFormat As Variant DateFormats = Array("yyyy/mm/dd", "yy/m/d", "yy/mm/dd", _ "d""日""", "dd""日""", "d/m/yyyy", _ "dd/mm/yyyy", "ggge", "ge") Call DeleteCal For Each DateFormat In DateFormats If InStr(Target.NumberFormatLocal, DateFormat) > 0 Then Call DispCalendarIcon Exit For End If Next End Sub '--------------------------------------- ' Private Sub DispCalendarIcon() Dim SHP As Object Set SHP = ActiveSheet.Pictures. _ Insert(Application.Path & "\FORMS\1041\APPTS.ICO") With SHP '--------アクティブセルの1つ右のセル .Left = ActiveCell.Offset(0, 1).Left + 5 .Top = ActiveCell.Offset(0, 1).Top + 2 '--------名前 .Name = "SHPIcon" '--------クリックしたときの動作 .OnAction = "ShapeCalendar.OpenCalendar" .PrintObject = msoFalse .Placement = xlMove .Locked = msoTrue End With End Sub
標準モジュール ShapeCalendar
セル横のアイコンの「 OnAction 」を「 ShapeCalendar.OpenCalendar 」としているため、標準モジュールのモジュール名を「 ShapeCalendar 」とします。
Option Explicit Private Enum YobiType Shuku = 10 Kokumin = 11 Hurikae = 12 Kanrei = 13 End Enum Private Enum IncFlg IncForward = 0 IncBackward = -1 End Enum Private shpHeight As Long Private shpWidth As Long Private TBT As Long Private YBT As Long Private DBT(1 To 6) As Long Private BL(1 To 7) As Long Private Const ColorSunday As Long = vbRed Private Const ColorSaturday As Long = vbBlue Private Const ColorWeekday As Long = vbBlack Private Const ColorPreHome As Long = 5288016 Private Const IntvDay As String = "d" Private Const IntvMonth As String = "m" Private Const IntvYear As String = "yyyy" Private Const IntvWeek As String = "ww" Private HoldDate As Date Private HoldYear As Long Private HoldMonth As Long Private HoldDay As Long Private CurDate As Date Private CurYear As Long Private CurMonth As Long Private CurDay As Long Private GetYobi As C_Kyuzitu Private Const FirstYobi As Long = vbSunday Private Yobi As Variant Private StartPosi As Long Private DaysAndWeeks() As Long Private SelectShape As String '--------------------------------------- ' Public Sub OpenCalendar() Dim I As Long Dim J As Long '--------新しくカレンダーを開く前に既存を抹消します。 Call DeleteCal Yobi = Array("", "日", "月", "火", "水", "木", "金", "土") '--------シェイプ1ブロックの大きさです。 shpHeight = 15 shpWidth = 35 '--------カレンダーの最も上の位置です。 TBT = ActiveCell.Offset(0, 1).Top '--------カレンダーの1列目の左の位置です BL(1) = ActiveCell.Offset(0, 1).Left '--------曜日のトップの位置です。 YBT = TBT + shpHeight '--------日付の1段目の位置です。 DBT(1) = YBT + shpHeight '--------2段目以降の位置です For I = 2 To 6 DBT(I) = DBT(I - 1) + shpHeight Next I '--------日付の2列以降の左端の位置です。 For J = 2 To 7 BL(J) = BL(J - 1) + shpWidth Next J Application.ScreenUpdating = False '--------シェイプを作成します。 Call UpShapes '--------カレンダーを描画します。 Call OpenDraw Application.ScreenUpdating = True End Sub '--------------------------------------- ' Private Sub UpShapes() Dim SHP As Shape Dim Row As Long Dim Col As Long Dim intLogicalDay As Long Dim Grid As Long '--------カレンダーの1行目を描画します。 Set SHP = ActiveSheet.Shapes.AddShape(1, BL(1), _ TBT, shpWidth, shpHeight) With SHP .Name = "SHP_PreviousYear" .OnAction = "ShapeCalendar.PreviousYearClick" .Fill.ForeColor.RGB = RGB(252, 213, 181) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "▼" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(2), _ TBT, shpWidth * 2, shpHeight) With SHP .Name = "SHP_TextYaer" .OnAction = "ShapeCalendar.Dummy" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(4), _ TBT, shpWidth, shpHeight) With SHP .Name = "SHP_NextYear" .OnAction = "ShapeCalendar.NextYearClick" .Fill.ForeColor.RGB = RGB(146, 246, 166) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "▲" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(5), _ TBT, shpWidth, shpHeight) With SHP .Name = "SHP_PreviousMonth" .OnAction = "ShapeCalendar.PreviousMonthClick" .Fill.ForeColor.RGB = RGB(252, 213, 181) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "▼" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(6), _ TBT, shpWidth, shpHeight) With SHP .Name = "SHP_TextMonth" .OnAction = "ShapeCalendar.Dummy" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(7), _ TBT, shpWidth, shpHeight) With SHP .Name = "SHP_NextMonth" .OnAction = "ShapeCalendar.NextMonthClick" .Fill.ForeColor.RGB = RGB(146, 246, 166) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = "▲" .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) '--------曜日の行を描画します。 For Col = 1 To 7 intLogicalDay = (((Col - 1) + (FirstYobi - 1)) Mod 7) + 1 Set SHP = ActiveSheet.Shapes.AddShape(1, BL(Col), _ YBT, shpWidth, shpHeight) With SHP .Name = "SHPY" & Format(Col, "00") .OnAction = "ShapeCalendar.Dummy" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 0 With .TextRange .Text = Yobi(intLogicalDay) .Font.Size = 10 If intLogicalDay = 1 Then .Font.Fill.ForeColor.RGB = RGB(255, 0, 0) ElseIf intLogicalDay = 7 Then .Font.Fill.ForeColor.RGB = RGB(0, 0, 255) Else .Font.Fill.ForeColor.RGB = ColorWeekday End If End With End With End With Call ShapeHyozi(SHP) Next Col '--------日にちを描画します。 For Row = 1 To 6 For Col = 1 To 7 Set SHP = ActiveSheet.Shapes.AddShape(1, BL(Col), _ DBT(Row), shpWidth, shpHeight) Grid = Col + (Row - 1) * 7 With SHP .OnAction = "ShapeCalendar.DateClick" .Name = "SHPD" & Format(Grid, "00") .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 2 'Text の描画等は DaysInMonth で行います。 End With End With Call ShapeHyozi(SHP) Next Col Next Row '--------最終行を描画します。 Set SHP = ActiveSheet.Shapes.AddShape(1, BL(1), _ DBT(6) + shpHeight, shpWidth * 2, shpHeight) With SHP .Name = "SHP_HOME" .OnAction = "ShapeCalendar.GoHome" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 1 With .TextRange .Text = "HOME" .Font.Fill.ForeColor.RGB = ColorSaturday .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(3), _ DBT(6) + shpHeight, shpWidth * 2, shpHeight) With SHP .Name = "SHP_PREHOME" .OnAction = "ShapeCalendar.GoPreHome" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 1 With .TextRange .Text = "preHOME" .Font.Fill.ForeColor.RGB = ColorPreHome .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) Set SHP = ActiveSheet.Shapes.AddShape(1, BL(5), _ DBT(6) + shpHeight, shpWidth * 3, shpHeight) With SHP .Name = "SHP_CANCEL" .OnAction = "ShapeCalendar.DeleteCal" .Fill.ForeColor.RGB = RGB(221, 221, 221) With .TextFrame2 .MarginTop = 1 With .TextRange .Text = "CANCEL" .Font.Fill.ForeColor.RGB = ColorSunday .Font.Size = 10 End With End With End With Call ShapeHyozi(SHP) End Sub '--------------------------------------- ' Private Sub ShapeHyozi(ByRef myShape As Shape) With myShape .Line.Visible = msoTrue .Line.ForeColor.RGB = RGB(166, 166, 166) .Line.Weight = 0.5 .Fill.Visible = msoTrue .Fill.Solid .Placement = xlFreeFloating .Locked = msoTrue With .TextFrame2 .HorizontalAnchor = msoAnchorCenter With .TextRange .ParagraphFormat.Alignment = msoAlignCenter End With End With End With End Sub '--------------------------------------- ' Private Sub NextYearClick() Call NextYear End Sub '--------------------------------------- ' Private Sub PreviousYearClick() Call PreviousYear End Sub '--------------------------------------- ' Private Sub NextMonthClick() Call NextMonth End Sub '--------------------------------------- ' Private Sub PreviousMonthClick() Call PreviousMonth End Sub '--------------------------------------- ' Public Sub NextYear() Call IncChageDraw(IntvYear, IncForward) End Sub '--------------------------------------- ' Public Sub PreviousYear() Call IncChageDraw(IntvYear, IncBackward) End Sub '--------------------------------------- ' Public Sub NextMonth() Call IncChageDraw(IntvMonth, IncForward) End Sub '--------------------------------------- ' Public Sub PreviousMonth() Call IncChageDraw(IntvMonth, IncBackward) End Sub '--------------------------------------- ' Private Sub IncChageDraw(ByVal intvMove As String, _ ByVal DT As IncFlg) Dim IncDate As Date Dim iInc As Long Dim Grid As Long '--------インクリメントの方向を決めます。 If DT = IncForward Then iInc = 1 Else iInc = -1 End If '--------インクリメントした日付を求めます。 IncDate = DateAdd(intvMove, iInc, CurDate) '--------表示年月日(CurDate/CurDay..)をセットします。 Call StartValues(IncDate) '--------年と月を表示します。 Call DrawYearMonth '--------日にちを描画します。 ' DaysAndWeeks の更新が必要 Call DaysDraw '--------黄色を戻します。 With ActiveSheet.Shapes(SelectShape) .Fill.ForeColor.RGB = RGB(221, 221, 221) End With '--------日にち(CurDay)を黄色に塗ります。 Call YellwPaint End Sub '--------------------------------------- ' Private Sub MoveToToday(ByVal UseCurYear As Boolean) '--------戻る日付を求めます。 If UseCurYear Then CurYear = HoldYear End If CurMonth = HoldMonth CurDay = HoldDay CurDate = DateSerial(CurYear, CurMonth, CurDay) '--------年と月を表示します。 Call DrawYearMonth '--------日にちを描画します。 ' DaysAndWeeks の更新が必要 Call DaysDraw '--------黄色を戻します。 With ActiveSheet.Shapes(SelectShape) .Fill.ForeColor.RGB = RGB(221, 221, 221) End With '--------日にち(CurDay)を黄色に塗ります。 Call YellwPaint End Sub '--------------------------------------- ' Private Sub DateClick() Dim myCaller As String '-----マクロを呼び出したオブジェクトの名前 myCaller = Application.Caller '-----シェイプにテキストデータがない If Len(ActiveSheet.Shapes(myCaller).TextFrame2.TextRange.Text) = 0 Then Exit Sub End If '--------2回連続でクリックされた場合、決定しアクティブセルに日付をセットします。 If (SelectShape = myCaller) Then ActiveCell.Value = CurDate Call DeleteCal Else '--------新しい選択のシェイプを描画します。 Call DateClickShape(myCaller) End If End Sub '--------------------------------------- ' Private Sub DateClickShape(ByVal NewSelect As String) Dim Grid As Long '--------シェイプの名前から Grid を求めます。 Grid = Replace(NewSelect, "SHPD", "") If CurMonth <> DatePart(IntvMonth, DaysAndWeeks(Grid)) Then '--------表示年月日(CurDate/CurDay..)をセットします。 Call StartValues(DaysAndWeeks(Grid)) '--------年と月を表示します。 Call DrawYearMonth '--------日にちを描画します。 ' DaysAndWeeks の更新が必要 Call DaysDraw Else '--------一部の更新します。 CurDate = DaysAndWeeks(Grid) CurDay = DatePart(IntvDay, CurDate) End If '--------黄色を戻します。 With ActiveSheet.Shapes(SelectShape) .Fill.ForeColor.RGB = RGB(221, 221, 221) End With '--------日にち(CurDay)を黄色に塗ります。 Call YellwPaint End Sub '--------------------------------------- ' Private Sub GoHome() Call MoveToToday(UseCurYear:=True) End Sub '--------------------------------------- ' Private Sub GoPreHome() Call MoveToToday(UseCurYear:=False) End Sub '--------------------------------------- ' Private Sub Dummy() End Sub '--------------------------------------- ' Private Sub OpenDraw() Dim BUF As String Dim Grid As Long '--------カレンダーを呼び出したセルの値を取得します。 BUF = Replace(StrConv(ActiveCell.Value, vbNarrow), ".", "/") If IsDate(BUF) Then HoldDate = CDate(BUF) Else HoldDate = Date End If '--------年月日の要素を取り出す HoldDay = DatePart(IntvDay, HoldDate) HoldMonth = DatePart(IntvMonth, HoldDate) HoldYear = DatePart(IntvYear, HoldDate) '--------表示年月日(CurDate/CurDay..)をセットします。 Call StartValues(HoldDate) '--------年と月を表示します。 Call DrawYearMonth '--------休日クラスを作成します。 Set GetYobi = New C_Kyuzitu '--------日にちシェイプの名前の Grid に対応するシリアル値を格納する配列を作成します。 ReDim DaysAndWeeks(1 To 42) '--------日にちを描画します。 Call DaysDraw 'オープン時の描画で黄色がありません。 '--------日にち(CurDay)を黄色に塗ります。 Call YellwPaint End Sub '--------------------------------------- 'カレンダーの上部に年と月を表示します。 Private Sub StartValues(ByVal OpenDate As Date) '表示の日付をセットします。 CurDate = OpenDate CurYear = DatePart(IntvYear, CurDate) CurMonth = DatePart(IntvMonth, CurDate) CurDay = DatePart(IntvDay, CurDate) End Sub '--------------------------------------- 'カレンダーの上部に年と月を表示します。 Private Sub DrawYearMonth() With ActiveSheet.Shapes("SHP_TextYaer").TextFrame2.TextRange .Text = Format(DateSerial(CurYear, CurMonth, 1), "ggge年") End With With ActiveSheet.Shapes("SHP_TextMonth").TextFrame2.TextRange .Text = Format(DateSerial(CurYear, CurMonth, 1), "m月") End With End Sub '--------------------------------------- ' Private Sub DaysDraw() Dim newSelected As String Dim OneDayYobi As Long Dim OneDaySerial As Long Dim I As Long '--------月の初めの1日のシリアル値を求めます。 OneDaySerial = DateSerial(CurYear, CurMonth, 1) '--------月の初めの1日の曜日の値(1日の位置)を求めます。 OneDayYobi = Weekday(OneDaySerial, FirstYobi) StartPosi = OneDayYobi '--------日にちシェイプに対応した配列にシリアル値を格納します。 For I = 1 To UBound(DaysAndWeeks) DaysAndWeeks(I) = OneDaySerial - OneDayYobi + I Next I '--------年をセットし、休日を求めます。 GetYobi.NowYear = CurYear '--------日付の描写 Call DaysInMonth End Sub '--------------------------------------- ' Private Sub DaysInMonth() Dim Row As Long Dim Col As Long Dim Grid As Long Dim SpName As String '--------DateCalendarの日付の描写 For Row = 1 To 6 For Col = 1 To 7 '--------Row/Colポジションにあるシェイプの名前を求めます。 Grid = Col + (Row - 1) * 7 SpName = "SHPD" & Format(Grid, "00") With ActiveSheet.Shapes(SpName).TextFrame2.TextRange '--------Grid に対応するシリアル値から日にち部分を求め表示します。 .Text = DatePart(IntvDay, DaysAndWeeks(Grid)) '--------対象月以外のフォントを小さくします。 If DatePart(IntvMonth, DaysAndWeeks(Grid)) <> CurMonth Then .Font.Size = 8 Else .Font.Size = 10 End If '--------休日の赤色表示処理 GetYobi.SetNumDate = DaysAndWeeks(Grid) Select Case GetYobi.WeekNum Case 1, Shuku, Kokumin, Kanrei, Hurikae .Font.Fill.ForeColor.RGB = ColorSunday Case 7 .Font.Fill.ForeColor.RGB = ColorSaturday Case Else .Font.Fill.ForeColor.RGB = ColorWeekday End Select End With Next Col Next Row End Sub '--------------------------------------- ' Private Sub YellwPaint() Dim Grid As Long Dim SpName As String '--------選択された日にち(シェイプ)の名前を取得します。 Grid = StartPosi + CurDay - 1 SpName = "SHPD" & Format(Grid, "00") SelectShape = SpName With ActiveSheet.Shapes(SpName) '--------黄色にします。 .Fill.ForeColor.RGB = RGB(255, 255, 0) End With End Sub '--------------------------------------- ' Public Sub DeleteCal() Dim SHP() As String Dim Sp As Shape Dim objRange As Object Dim iCount As Long Dim I As Long '-----シェイプがなければ終了 If ActiveSheet.Shapes.Count = 0 Then Exit Sub End If '-----名称がSHPから始まるシェイプの拾い上げ ReDim SHP(1 To ActiveSheet.Shapes.Count) iCount = 0 For Each Sp In ActiveSheet.Shapes If InStr(1, Sp.Name, "SHP") > 0 Then iCount = iCount + 1 SHP(iCount) = Sp.Name End If Next Sp '-----なければ終わり If iCount = 0 Then Exit Sub End If '-----シェイプの一括削除のため一括選択 ReDim Preserve SHP(1 To iCount) Set objRange = ActiveSheet.Shapes.Range(SHP) objRange.Select If Not GetYobi Is Nothing Then Set GetYobi = Nothing End If '----一括削除の実行 objRange.Delete End Sub
VBエディターの雰囲気
作成中のVBエディターはこんな感じになります。