이번 글에서는 MS Access Tree View Right Click Event 구현 방법에 대해서 기술해 보도록 하겠습니다.
기본적으로 제공되는 트리 뷰에서는 전체 노트를 접거나 펼치는 등의 기능은 제공되지 않습니다. 또한 노드를 표시하기만 할 뿐 추가하거나 삭제등의 기능은 제공되지 않습니다. 바로 위의 기능들을 커스터마이징하는 방법에 대해서 기술하고자 합니다.
MS Access Tree View Right Click Event 구현
Expand All, Contract All 구현하기

먼저 Alt+F11을 클릭하여 ‘도구’ – ‘참조’ 메뉴를 클릭합니다.

목록에서 ‘Microsoft Office 16.0 Object Library’를 선택한 뒤 ‘확인’ 버튼을 클릭합니다.

폼 디자인보기에서 ImageListControl을 더블클릭하여 속성 화면을 엽니다.

Images탭에서 각각의 메뉴에 사용할 이미지들을 불러옵니다. 그리고 각 이미지마다 Key값을 설정합니다. 다음의 키 값으로 저장하였습니다.
- ExpandAll
- ContractAll
- InsertAbove
- InsertBelow
- InsertInside
Insert Below / Above / Inside 구현하기

새로운 노드를 추가하기 위해서는 상위 노드의 ID값과 정렬 순서를 알 필요가 있습니다. 따라서 서브 폼의 텍스트 박스를 다음과 같이 이름을 변경하여 사용하도록 하겠습니다.

이미지를 등록하고 난 뒤 트리 뷰가 포함된 메인 폼에 treeReqs – MouseUp 이벤트를 등록해 줍니다.
코드를 등록하기에 앞서 매개변수로 전달되는 Button값은 마우스 왼쪽, 오른쪽 클릭을 구분해 주는 역할을 합니다. 1은 왼쪽, 2는 오른쪽, 3은 가운데 클릭을 나타냅니다. 향후에 헷갈리지 않도록 Enumerate 형식으로 지정해 주도록 하겠습니다.

Module1을 열어 위와 같은 코드를 입력해 주도록 하겠습니다.
Public Enum eMouse
LeftClick = 1
RightClick = 2
CenterClick = 3
End Enum
Public Function getImageList() As MSComctlLib.ImageList
Set getImageList = Forms("frm_treeView").imgListIcons.Object
End Function
‘modeCommandBars’라는 이름의 모듈을 추가해 주도록 하겠습니다.
Option Compare Database
Option Explicit
Public Sub RightClickEmptySpace()
Dim cmdBAR As CommandBar
Set cmdBAR = CommandBars.Add(, msoBarPopup, False, True)
Dim cmdExpandAll As CommandBarButton
Set cmdExpandAll = cmdBAR.Controls.Add(msoControlButton)
cmdExpandAll.Caption = "Expand All"
cmdExpandAll.OnAction = "ExpandAll"
cmdExpandAll.Picture = getImageList.ListImages("ExpandAll").Picture
Dim cmdContractAll As CommandBarButton
Set cmdContractAll = cmdBAR.Controls.Add(msoControlButton)
cmdContractAll.Caption = "Contract All"
cmdContractAll.OnAction = "ContractAll"
cmdContractAll.Picture = getImageList.ListImages("ContractAll").Picture
cmdBAR.ShowPopup
'Cleanup
Set cmdBAR = Nothing
Set cmdExpandAll = Nothing
Set cmdContractAll = Nothing
End Sub
Public Sub ExpandAll()
Dim tv As TreeView
Dim nodX As Node
Set tv = getTV
For Each nodX In tv.Nodes
If nodX.Expanded = False Then
nodX.Expanded = True
End If
Next
'cleanup
Set nodX = Nothing
Set tv = Nothing
End Sub
Public Sub ContractAll()
Dim tv As TreeView
Dim nodX As Node
Set tv = getTV
For Each nodX In tv.Nodes
If nodX.Expanded = True Then
nodX.Expanded = False
End If
Next
'cleanup
Set nodX = Nothing
Set tv = Nothing
End Sub
Public Sub RightClickNode(nodX As MSComctlLib.Node)
Dim cmdBar As CommandBar
Set cmdBar = CommandBars.Add(, msoBarPopup, False, True)
Dim cmdButtonInsertAbove As CommandBarButton
Set cmdButtonInsertAbove = cmdBar.Controls.Add(msoControlButton)
cmdButtonInsertAbove.Caption = "Insert Above"
cmdButtonInsertAbove.Style = msoButtonIconAndCaption
cmdButtonInsertAbove.OnAction = "=InsertNew('Above'," & getID(nodX) & ")"
cmdButtonInsertAbove.Picture = getImageList.ListImages("InsertAbove").Picture
Dim cmdButtonInsertBelow As CommandBarButton
Set cmdButtonInsertBelow = cmdBar.Controls.Add(msoControlButton)
cmdButtonInsertBelow.Caption = "Insert Below"
cmdButtonInsertBelow.Style = msoButtonIconAndCaption
cmdButtonInsertBelow.OnAction = "=InsertNew('Below'," & getID(nodX) & ")"
cmdButtonInsertBelow.Picture = getImageList.ListImages("InsertBelow").Picture
Dim cmdButtonInsertInside As CommandBarButton
Set cmdButtonInsertInside = cmdBar.Controls.Add(msoControlButton)
cmdButtonInsertInside.Caption = "Insert Inside"
cmdButtonInsertInside.Style = msoButtonIconAndCaption
cmdButtonInsertInside.OnAction = "=InsertNew('Inside'," & getID(nodX) & ")"
cmdButtonInsertInside.Picture = getImageList.ListImages("InsertInside").Picture
cmdBar.ShowPopup
'cleanup
Set cmdBar = Nothing
Set cmdButtonInsertAbove = Nothing
Set cmdButtonInsertBelow = Nothing
Set cmdButtonInsertInside = Nothing
End Sub
Public Function InsertNew(strLocation As String, lngID As Long)
Dim rs As DAO.Recordset
Dim lngParentID As Long
Dim dblCurrentSort As Double
Dim dblNewSort As Double
lngParentID = DLookup("ID_Parent", "tbl_Reqs", "PK_Req=" & lngID)
Select Case strLocation
Case "above"
Set rs = CurrentDb.OpenRecordset("SELECT PK_req, ID_Parent,dbl_Sort FROM tbl_REqs WHERE ID_Parent=" & lngParentID & " ORDER by dbl_Sort", dbOpenDynaset)
rs.FindFirst "PK_Req=" & lngID
dblCurrentSort = rs!dbl_Sort
rs.MovePrevious
If rs.BOF Then
'Node has no siblings above
dblNewSort = dblCurrentSort - 1
Else
'node has a sibling node above
dblNewSort = (dblCurrentSort + rs!dbl_Sort) / 2
End If
Case "Below"
Set rs = CurrentDb.OpenRecordset("SELECT PK_req, ID_Parent,dbl_Sort FROM tbl_REqs WHERE ID_Parent=" & lngParentID & " ORDER by dbl_Sort", dbOpenDynaset)
rs.FindFirst "PK_Req=" & lngID
dblCurrentSort = rs!dbl_Sort
rs.MoveNext
If rs.EOF Then
'Node has no siblings below
dblNewSort = dblCurrentSort + 1
Else
'node has a sibling node below
dblNewSort = (dblCurrentSort + rs!dbl_Sort) / 2
End If
Case "Inside"
Set rs = CurrentDb.OpenRecordset("SELECT PK_req, ID_Parent,dbl_Sort FROM tbl_REqs WHERE ID_Parent=" & lngID & " ORDER by dbl_Sort", dbOpenDynaset)
lngParentID = lngID
If rs.EOF Then
'No children nodes
dblNewSort = 1
Else
rs.MoveFirst
dblNewSort = rs!dbl_Sort - 1
End If
End Select
Dim frmReq As Form_frm_Reqs
Set frmReq = Forms("frm_treeView").ctrlSubForm.Form
frmReq.tb_ParentID.DefaultValue = lngParentID
frmReq.tb_SortValue.DefaultValue = Replace(dblNewSort, ",", ".")
frmReq.Recordset.AddNew
'Cleanup
Set frmReq = Nothing
Set rs = Nothing
End Function

다시 treeReqs_MouseUp 이벤트 코드 작성 영역으로 돌아와서 아래의 코드를 입력합니다.
Private Sub treeReqs_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Long, ByVal y As Long)
If Button = eMouse.RightClick Then
Dim nodX As Node
Set nodX = getTV.HitTest(x, y)
If nodX Is Nothing Then
'User clicked Empty space
Call RightClickEmptySpace
Else
'User clicked a node
Call RightClickNode(nodX)
End If
End If
End Sub