能否在Microsoft TreeView Control 6.0 (MSComctlLib.TreeCtrl.2)中模拟三态复选框?

3

我在Microsoft Access中使用的是Microsoft TreeView Control 6.0控件。它似乎运行得很好,但是它似乎没有灰色状态,表明一些但不是所有子节点被选中。

我尝试使用自己的图像来模拟复选框,但是如果这样做,我必须删除真实的复选框,否则它看起来像每个项目都有两个复选框......但是然后我就没有任何复选框,也无法处理图像上的单击事件。

我可以找到许多人在其他语言/用途中对此控件提出类似的问题,但我找不到Microsoft Access的解决方案。

如果有其他可用的控件可以为我提供带有三态复选框的分层结构,则可以愉快地转向其他控件。

1个回答

3

经过一番研究和几个小时的编码,我终于自己写出了解决方案。

我需要添加一个ImageList,将其与TreeView关联,并添加三种状态下的复选框图像。在此过程中,Google图片搜索为我节省了一些时间 :)

'Enumeration for simulated tri-state checkboxes, matching up to the TreeView's associated Image List's Index
Private Enum CheckboxEnum
  Unchecked = 1
  Checked = 2
  Partial = 3
End Enum

'---------------------------------------------------------------------------------------
' Procedure : objTreeView_MouseDown
' Author    : Matty Brown
' Date      : 19/05/2014
' Purpose   : Because TreeView doesn't support tri-state checkboxes, these have to be simulated using images.
'---------------------------------------------------------------------------------------
'
Private Sub objTreeView_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)
  Const CHECKBOX_WIDTH As Integer = 195 '195=13px

  Dim objNode As Node
  Set objNode = objTreeView.HitTest(x, y)

  If objNode Is Nothing Then
    'Miss
  Else
    'Find left side of node by moving left one pixel at a time until you fall off the node, then move one pixel to the right
    Dim intX As stdole.OLE_XPOS_PIXELS
    For intX = x To 0 Step -15
      If Not objNode Is objTreeView.HitTest(intX, y) Then
        If x <= intX + CHECKBOX_WIDTH Then
          'User clicked on the checkbox
          Select Case objNode.Image
            Case CheckboxEnum.Unchecked:
              objNode.Image = CheckboxEnum.Checked
            Case Else:
              objNode.Image = CheckboxEnum.Unchecked
          End Select

          'Recursively check child nodes
          Call CheckTreeNodes(objTreeView, objNode, objNode.Image)

          'Update parent node(s)
          Call UpdateParentNodes(objTreeView, objNode)
        Else
          'User clicked outside of the checkbox
          '
        End If

        Exit For
      End If
    Next
  End If
End Sub

'---------------------------------------------------------------------------------------
' Procedure : CheckTreeNodes
' Author    : Matty Brown
' Date      : 16/05/2014
' Purpose   : Checks or unchecks all of the child nodes for the specified node
'---------------------------------------------------------------------------------------
'
Private Sub CheckTreeNodes(ByRef tv As TreeView, ByRef nodNode As Node, ByVal Value As CheckboxEnum)
  Dim lngIndex As Long

  'Cascade change to children
  If nodNode.Children > 0 Then
    lngIndex = nodNode.Child.Index
    Call CheckTreeNodes(tv, tv.Nodes(lngIndex), Value)

    Do While lngIndex <> nodNode.Child.LastSibling.Index
      lngIndex = tv.Nodes(lngIndex).Next.Index
      Call CheckTreeNodes(tv, tv.Nodes(lngIndex), Value)
    Loop
  End If

  nodNode.Image = Value
End Sub

'---------------------------------------------------------------------------------------
' Procedure : CountChildNodes
' Author    : Matty Brown
' Date      : 19/05/2014
' Purpose   : Counts how many child nodes are checked or unchecked, so that a parent node can be set correctly
'---------------------------------------------------------------------------------------
'
Private Sub CountChildNodes(ByRef tv As TreeView, ByRef nodNode As Node, ByRef lngChecked As Long, ByRef lngUnchecked As Long)
  Dim lngIndex As Long

  'Check this node's children
  If nodNode.Children > 0 Then
    lngIndex = nodNode.Child.Index
    Call CountChildNodes(tv, tv.Nodes(lngIndex), lngChecked, lngUnchecked)

    Do While lngIndex <> nodNode.Child.LastSibling.Index
      lngIndex = tv.Nodes(lngIndex).Next.Index
      Call CountChildNodes(tv, tv.Nodes(lngIndex), lngChecked, lngUnchecked)
    Loop
  Else
  'Update totals
    Select Case nodNode.Image
      Case CheckboxEnum.Checked:
        lngChecked = lngChecked + 1
      Case CheckboxEnum.Unchecked:
        lngUnchecked = lngUnchecked + 1
    End Select
  End If
End Sub


'---------------------------------------------------------------------------------------
' Procedure : UpdateParentNodes
' Author    : Matty Brown
' Date      : 19/05/2014
' Purpose   : Steps through parent nodes, updating them according to how many checked/unchecked child nodes they have
'---------------------------------------------------------------------------------------
'
Private Sub UpdateParentNodes(ByRef tv As TreeView, ByRef nodNode As Node)
  Dim lngIndex As Long
  Dim nodParent As Node
  Dim lngChecked As Long, lngUnchecked As Long

  'If this node has no parents, there's nothing to update
  If nodNode.Parent Is Nothing Then Exit Sub
  Set nodParent = nodNode

  Do While Not nodParent.Parent Is Nothing
    Set nodParent = nodParent.Parent

    'Reset counters
    lngUnchecked = 0
    lngChecked = 0

    'Count children
    Call CountChildNodes(tv, nodParent, lngChecked, lngUnchecked)

    'Update parent nodes
    If lngUnchecked = 0 And lngChecked > 0 Then
      nodParent.Image = CheckboxEnum.Checked
    ElseIf lngUnchecked > 0 And lngChecked > 0 Then
      nodParent.Image = CheckboxEnum.Partial
    Else
      nodParent.Image = CheckboxEnum.Unchecked
    End If
  Loop
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接