
少々の設定とコードのコピペで動作するようにまとめました。
「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エディターはこんな感じになります。
