设置检查节点检查事件

Posted

技术标签:

【中文标题】设置检查节点检查事件【英文标题】:Setting Checked On NodeCheck Event 【发布时间】:2014-04-29 13:23:52 【问题描述】:

NodeCheck 事件期间设置选中的属性会导致它恢复到之前的状态。

例如:节点被检查,下面的事件被触发。它发现节点被检查并将其设置为假。如果我用中断遍历代码,节点将在用户界面中反映这一点。虽然,只要代码到达 end sub,复选框就会跳回设置为 true。

Private Sub treeviewExample_NodeCheck(ByVal Node As Object)
     If Node.Checked = True Then
            Node.Checked = False
     ElseIf Node.Checked = False Then
            Node.Checked = True
     End If
end sub

如何在NodeCheck 事件期间设置checked 属性?

我已经尝试了解决方案here,它将节点设置为本地或全局变量,然后设置它,它做同样的事情。

【问题讨论】:

NodeCheck 事件被触发,因为节点的 Checked 值已更改。 Windows 为您检查/清除检查。您不必更改代码中的值,除非您想更改选中的值以响应用户执行其他操作。 我使用节点的方式是验证权限与否。如果用户没有安全性来编辑权限,那么我希望节点重置为其原始正确值,而不是向用户显示他/她有安全性来更改它。 请阅读:Should questions include “tags” in their titles? 【参考方案1】:

您可以将 Checkboxes 属性设置为 False,并使用 Windows API 来设置 checkboxes 属性。然后使用 NodeClick 事件来选择是否选中或取消选中节点。

Option Explicit

Private Const TVS_CHECKBOXES As Long = &H100
Private Const GWL_STYLE As Long = (-16)
Private Const TVS_HASLINES As Long = 2
Private Const TV_FIRST As Long = &H1100
Private Const TVM_SETBKCOLOR As Long = (TV_FIRST + 29)

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Sub Form_Load()

    SetTVCheckboxStyle TreeView1

End Sub

Private Sub SetTVCheckboxStyle(pobjTV As TreeView)

    Dim lngCurStyle As Long
    Dim lngResult   As Long

    ' === Set the Checkbox style of the TreeView ===
    ' As advised by Microsoft, due to a bug in the TreeView control,
    ' set the Checkbox style of the TreeView by using the following
    ' API calls, rather than simply setting the "Checkboxes" property
    ' to True ...
    lngCurStyle = GetWindowLong(pobjTV.hwnd, GWL_STYLE)
    lngResult = SetWindowLong(pobjTV.hwnd, GWL_STYLE, _
                              lngCurStyle Or TVS_CHECKBOXES)

End Sub

当您添加节点时,请设置您希望禁用的节点的一些属性,以便稍后检查该属性。我选择使用 ForeColor 属性,因此禁用的节点将具有禁用的外观。然后使用 NodeClick 事件来检查、清除或忽略用户点击。

Private Sub TreeView1_NodeClick(ByVal Node As MSComctlLib.Node)

    If Node.ForeColor <> vbGrayText Then
        Node.Checked = Not Node.Checked
    End If

End Sub

【讨论】:

如果此解决方案对我有用,我仍在努力,但您可能需要查看 GetWindowLongptrSetWindowLongptr 函数,而不是 GetWindowLongSetWindowLong。它们似乎已被弃用,较新的功能同时支持 32 位和 64 位 Windows。 msdn.microsoft.com/en-us/library/windows/desktop/… 我还有一个问题是该事件也会在标签上触发。我怎么能覆盖标签点击VS。复选框点击? 我不确定您如何或是否可以从复选框点击中辨别标签。不幸的是,因为您不能禁用选定的节点,所以这只是一个杂项。另一种解决方案是根本不使用复选框,而是使用在各种状态下看起来像复选框的图像。 IMO 理想的解决方案是重新考虑 UI 设计。 令人失望的是,我无法在 Treeview 上采取行动,尽管我确实喜欢您的 imagelist 建议。谢谢【参考方案2】:

我遇到了这个问题,并找到了解决方法。

您不能在其自己的 NodeCheck 事件中设置树视图复选框的“已选中”。

但是,假设您正在捕获用户单击复选框,Treeview_Click 事件随后会立即触发(因为他们必须单击才能更改它),并且您可以在该事件中设置复选框。

因此,您需要做的就是存储对需要更改的复选框的引用,并在 Click 事件中设置它,然后再清除引用。

Private WithEvents tv As TreeView

Private checkBoxToSet_Node As Node
Private checkBoxToSet_value As Boolean


Private Sub tv_NodeCheck(ByVal Node As MSComctlLib.Node)

    Dim prompt As VbMsgBoxResult

    prompt = MsgBox("Do you REALLY want to set this checkbox?", vbQuestion + vbYesNoCancel)

    ' can't set the checked-ness here, so we store it

    If (prompt <> vbYes) Then
        Set checkBoxToSet_Node = Node
        checkBoxToSet_value = Not Node.checked
    End If

End Sub


Private Sub tv_Click()

    ' check if we had previously set a node to have its checkbox changed

    If (Not checkBoxToSet_Node Is Nothing) Then
        tv.Nodes(checkBoxToSet_Node.key).checked = checkBoxToSet_value

        Set checkBoxToSet_Node = Nothing
    End If

End Sub

【讨论】:

以上是关于设置检查节点检查事件的主要内容,如果未能解决你的问题,请参考以下文章

检查日期范围的最快方法

TVirtualStringTree。如何通过一次确认检查节点及其子节点?

TVirtualStringTree。如何识别用户检查的确切节点?

如何在不引发事件的情况下设置 checkbox.isChecked

检查节点是不是存在,如果不存在则创建

NodeJS高效数据库日期超时事件。