Attribute VB_Name = "ModTree"
'''
''' ツリー構造の折りたたみや展開を実現する
'''
''' [example]
''' Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
''' Cancel = Tree.Wrap(Target)
''' End Sub
'''
' 折りたたみ走査行数
Private Const MAXSEEK_BOTTOM = 30
' 折りたたみ走査列数
Private Const MAXSEEK_RIGHT = 100
' マーク:展開
Private Const MARK_OPEN = "◆"
' マーク:折りたたみ
Private Const MARK_CLOSE = "▼"
'''
''' 指定されたセルを基準にしてツリー構造の折りたたみや展開を実現する
'''
''' 該当セル
'''
''' true 折りたたみや展開処理が完了
''' false 指定されたセルは不正である
'''
Public Function Wrap(Target As Range) As Boolean
Dim r As Long
Application.ScreenUpdating = False
'折りたたみ/展開処理
i = 0
For r = Target.Row + 1 To Rows.Count
If MAXSEEK_BOTTOM < r - Target.Row Then
Exit For
End If
If Not canNext(r, Target.Column) Then
Exit For
End If
Select Case Target.Value
Case MARK_OPEN
Cells(r, Target.Column).EntireRow.Hidden = True
Case MARK_CLOSE
If canOpen(r, Target.Column, Target.Row) Then
Cells(r, Target.Column).EntireRow.Hidden = False
End If
End Select
Next
Application.ScreenUpdating = True
'事後処理
Select Case Target.Text
Case MARK_OPEN
Target.Value = MARK_CLOSE
Wrap = True
Case MARK_CLOSE
Target.Value = MARK_OPEN
Wrap = True
Case Else
Wrap = False
End Select
End Function
'''
''' 指定されたセルに対して処理を継続するかどうかを取得する
'''
''' 該当セルの行
''' 該当セルの列
''' true:継続,false:終了
Private Function canNext(r As Long, c As Long) As Boolean
Dim col As Long
'その行の最初の列について調べる
If Not Cells(r, c + 1).Value = "" And _
Not Cells(r, c + 1).Value = MARK_CLOSE And _
Not Cells(r, c + 1).Value = MARK_OPEN Then
canNext = False
Exit Function
End If
'この行の左列について調べる
For col = 1 To c
If Not Cells(r, col).Value = "" Then
canNext = False
Exit Function
End If
Next
canNext = True
End Function
'''
''' 展開時に指定されたセルの行を展開するかどうかを取得する
'''
''' 該当セルの行
''' 該当セルの列
'''
''' true 展開する
''' false 展開しない
'''
Private Function canOpen(r As Long, c As Long, begin_row As Long) As Boolean
Dim rr As Long
'その行の最初の列についてだけ調べる
If c = Columns.Count Then
canOpen = True
Exit Function
ElseIf Not Cells(r, c + 1).Value = "" Then
canOpen = True
Exit Function
End If
'ループで前行に戻りつつ、再帰で右列を調べる
For rr = r - 1 To begin_row + 1 Step -1
If Cells(rr, c + 1).Value = MARK_CLOSE Then
canOpen = False
Exit Function
ElseIf Not Cells(rr, c + 1).Value = "" Then
'この階層ではわからないのでひとつ右の列を調べる
canOpen = canOpen(r, c + 1, begin_row)
Exit Function
End If
Next
'この階層ではわからないのでひとつ右の列を調べる
If c <= MAXSEEK_RIGHT Then
canOpen = canOpen(r, c + 1, begin_row)
Else
canOpen = True
End If
End Function