sql >> Base de Datos >  >> RDS >> Access

Reorganizar los nodos de TreeView arrastrando y soltando

Introducción.

Espero que haya encontrado útil el tutorial de la semana pasada sobre ImageCombo Control para sus proyectos de Microsoft Access. Con el control TreeView ImageCombo, pudimos crear un hermoso menú desplegable, con varias opciones, y acomodarlo en un pequeño espacio en el formulario.

Del mismo modo, en una sesión anterior, aprendimos cómo agregar nuevos nodos en una ubicación específica en la jerarquía de nodos o eliminar un nodo y agregar uno nuevo para reubicar un nodo en el Control de vista de árbol.

Este método solicita la creación de un nuevo registro en la tabla de origen para el nuevo nodo. O elimine un registro existente y cree uno nuevo para mover un nodo existente y hacerlo permanente. En cierto modo, con el uso de las funciones Agregar/Eliminar, podríamos agregar nuevos nodos o reorganizar los nodos existentes en el control TreeView. En lo que respecta a la reorganización de los nodos, tenemos una mejor manera de hacerlo, en lugar de eliminar los nodos y volver a crearlos. Arrastre el nodo desde su ubicación actual y suéltelo donde queremos que esté en el control TreeView. Esto es lo que vamos a aprender en este episodio

Este enfoque simple solo necesita actualizar el cambio del valor del campo ParentID de los registros relacionados, para que el cambio sea permanente.

Los temas tratados hasta ahora en sesiones anteriores.

  1. Tutorial de control TreeView de Microsoft
  2. Creación del menú de acceso con TreeView Control
  3. Asignación de imágenes al control TreeView
  4. Asignación de imágenes a TreeView Control-2
  5. Control de TreeView Marca de verificación Agregar Eliminar nodos
  6. Menú de acceso desplegable TreeView ImageCombo

Sin embargo, es posible que enfrentemos algunos desafíos al usar este método y llegaremos a eso un poco más adelante en esta sesión.

Formulario y tabla de datos de demostración.

Necesitamos una tabla y un formulario. Ya tenemos una tabla adecuada con el nombre Sample creado en una sesión de tutorial anterior. Si ya ha descargado la base de datos de demostración, desde la segunda página de enlace proporcionada anteriormente, también puede usar esa base de datos para esta sesión. Usaremos los siguientes objetos de esa base de datos para nuestros experimentos de arrastrar y soltar:

  • Tabla:Ejemplo
  • Formulario:frmMuestra

La imagen de control de TreeView en frmSample con datos de demostración se proporciona a continuación como referencia:

Puede descargar la base de datos de demostración (ProjectMenu.zip ) de la página del segundo enlace anterior y extraiga el ProjectMenu.accdb base de datos.

Nuevo formulario para ejecuciones de prueba de arrastrar y soltar.

  1. Abra la base de datos ProjectMenu.accdb.

  2. Haz una copia de la tabla Ejemplo y asígnele el nombre Sample_bk, manténgalo seguro, necesitaremos sus datos originales sin cambios más adelante. Cuando experimentamos con el método de arrastrar y soltar, es necesario actualizar el valor del campo ParentId en la tabla de demostración de muestra. Pero necesitamos los datos originales más tarde, sin estos cambios.

  3. Cree un nuevo formulario con el nombre frmDragDrop .

  4. El diseño de formulario frmDragDrop se verá como la imagen que se muestra a continuación cuando termine con él.

  5. Inserte el control TreeView de la lista de controles ActiveX y colóquelo en el formulario, dejando suficiente espacio sobre el control, para que podamos crear dos botones de comando y una etiqueta de encabezado sobre él. Arrastre el controlador de tamaño en la esquina inferior derecha para que sea lo suficientemente grande para mostrar todos los nodos, sin desplazarse.

  6. Cambiar el Nombre Valor de propiedad de TreeView Control para TreeView0 .

  7. Inserte un botón de comando arriba y en el borde izquierdo del control TreeView. Cambiar su Nombre Valor de propiedad para cmdExpand y Título valor para Expandir todo .

  8. Inserte un segundo botón de comando arriba y en el borde derecho del control TreeView. Cambiar su Nombre Valor de propiedad para cmdCollapse y el Título Valor de propiedad para Contraer todo.
  9. Inserte un control de etiqueta encima de los botones de comando, lo suficientemente ancho para escribir el encabezado como se muestra arriba, y cambie su tamaño de fuente 14.

  10. Ignore el control ImageList, por el momento, he comentado las líneas de código que modifican los números de índice de Node ImageList. Más adelante, puede importar el control ImageList con imágenes cargadas manualmente, desde nuestra base de datos de demostración de tutoriales anterior (de la cuarta página de enlace anterior) y usarlo para mostrar imágenes de nodos en nodos. Cuando se cambian las posiciones de los nodos durante las acciones de arrastrar y soltar, también debemos cambiar las imágenes de los nodos según la posición del nodo (nodo de nivel raíz o nodo secundario) en el control TreeView.

    Código del módulo de formulario de arrastrar y soltar.

  11. Muestre el módulo de código VBA del formulario frmDragDrop, copie y pegue el siguiente código VBA (esta es solo la primera mitad del código del módulo de formulario) en el módulo de clase del formulario frmDragDrop y guarde el formulario:

    Option Compare Database
    Option Explicit
    
    Dim tv As MSComctlLib.TreeView
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim imgListObj As MSComctlLib.ImageList
    Const KeyPrfx As String = "X"
    
    Private Sub Form_Open(Cancel As Integer)
    Set tv = Me.TreeView0.Object
    
    'Set imgListObj = Me.ImageList1.Object
    'tv.ImageList = imgListObj
    
    LoadTreeView
    
    End Sub
    
    Sub LoadTreeView()
    Dim strKey As String
    Dim strPKey As String
    Dim strText As String
    Dim strsQL As String
    
    strsQL = "SELECT * FROM Sample ORDER BY ID"
    
    Set db = CurrentDb
    Set rst = db.OpenRecordset(strsQL, dbOpenDynaset)
        
    tv.Nodes.Clear
    
    'Add all Items are added as Root Nodes
    Do While Not rst.BOF And Not rst.EOF
        strKey = KeyPrfx & CStr(rst!ID)
        strText = rst!desc
        tv.Nodes.Add , , strKey, strText
        
        'With tv.Nodes.Item(strKey)
        '    .Image = 1
        '    .SelectedImage = 4
        'End With
    
        rst.MoveNext
    Loop
    
    'Prepare to update the Parent-Key of Nodes
    'wherever applicable to move and position the Child Nodes
    strPKey = ""
    rst.MoveFirst
    Do While Not rst.EOF
        strPKey = Nz(rst!parentid, "")
        
        If Len(strPKey) > 0 Then
            strPKey = KeyPrfx & strPKey
            strKey = KeyPrfx & CStr(rst!ID)
            strText = rst!desc
            
            'Move the Child Node under it's Parent-Node
            Set tv.Nodes.Item(strKey).Parent = tv.Nodes.Item(strPKey)
            
    'Update Image and SelectedImage Properties
    'with ImageList Index numbers
            'With tv.Nodes.Item(strKey)
            '    .Image = 2
            '    .SelectedImage = 3
            'End With
    
        End If
        rst.MoveNext
    Loop
    
    rst.Close
    Set rst = Nothing
    Set db = Nothing
    
    End Sub
    
    
    Private Sub TreeView0_NodeClick(ByVal Node As Object)
    Dim SelectionNode As MSComctlLib.Node
        
    'Ensure that the clicked node equals the selected node in the tree
    If Not Node Is Nothing Then
        Set SelectionNode = Node
           If SelectionNode.Expanded = True Then
                SelectionNode.Expanded = False
            Else
                SelectionNode.Expanded = True
            End If
    End If
    End Sub
    
    Private Sub cmdCollapse_Click()
    Dim tmpnod As MSComctlLib.Node
    For Each tmpnod In tv.Nodes
        If tmpnod.Expanded = True Then
            tmpnod.Expanded = False
        End If
    Next
    
    End Sub
    
    Private Sub cmdExpand_Click()
    Dim tmpnod As MSComctlLib.Node
    For Each tmpnod In tv.Nodes
        If tmpnod.Expanded = False Then
            tmpnod.Expanded = True
        End If
    Next
    
    End Sub

    Sé que está familiarizado con el Código anterior, si ya ha pasado por los Episodios anteriores, excepto el LoadTreeView() subrutina con algunos cambios. Aquí, llenar los nodos TreeView se ha dividido en un proceso de dos pasos.

    Brevemente, esto es lo que sucede en esta Subrutina.

    • Todos los registros en Muestra La tabla se cargó como nodos de nivel raíz de TreeView Control, con un valor de campo de ID como clave, en el primer paso.

    • Nuevamente, estos registros se leyeron por segunda vez y se buscó un valor en el Id de padre campo, si está vacío, el nodo se mantendrá como nodo de nivel raíz.

    • Si el campo ParentID tiene un valor, identifique el nodo con el valor de ParentID como Node-Key y mover el nodo actual como su nodo secundario, o su [Relativo] Parámetro (de Agregar () Método) el valor se actualiza.

    • Aunque parece que el procedimiento de relleno de nodos de dos pasos es un ejercicio innecesario, hay una buena razón por la que tenemos que seguir este método. Volveremos sobre esto un poco más adelante y lo sabrás sin muchas explicaciones.

    • Sobre el Diseño del Formulario, le he dado un Control ImageList. Puede insertar el ImageList ActiveX Control y cargue algunas imágenes manualmente desde el disco, o copie y pegue este control con imágenes de descargas de bases de datos de demostración anteriores. En cualquier caso, asegúrese de que el nombre del control ImageList sea ImageList1 . De lo contrario, debe cambiar el nombre en el Código.

    • Después de eso, habilite las líneas comentadas en el procedimiento de evento Form_Open(). Habilite las siguientes líneas eliminando el símbolo de comentario del principio de la línea:

      'Set imgListObj = Me.ImageList1.Object
      'tv.ImageList = imgListObj
      

    • En el TreeView0_ OLEDragDrop() La subrutina (en la segunda parte del código VBA) habilita los parámetros de índice de imagen de los nodos, al eliminar también los símbolos de comentario de esas líneas. Con estos cambios, las imágenes de nodo aparecerán en el control TreeView. Si tiene un control ImageList propio con imágenes cargadas, cambie los números de índice en función de la imagen que le gustaría insertar en los nodos.

      El TreeView0_NodeClick() Procedimiento de evento Expande el nodo actual, si los nodos secundarios están colapsados; de lo contrario, los nodos secundarios se colapsarán. Normalmente esta acción se controla (sin código) haciendo clic en +/- Símbolo en la línea de árbol del nodo con nodos secundarios.

      Las Subrutinas cmdExpand_Click() y cmdCollapse_Click() Eventos Expande todos los nodos y contrae todos los nodos respectivamente.

      Cuando se ejecuta el código anterior, la pantalla se parece a la imagen de vista de formulario que se muestra a continuación:

    • Puede guardar el frmDragDrop Formulario y ábralo en Vista normal. Si todo salió bien, verá la pantalla anterior. Pruebe Expandir todo y Ocultar todo Botones de comando y verifique si también funcionan. De lo contrario, vuelva a verificar que las siguientes configuraciones sean correctas o no:

    • i) El nombre del control TreeView es:TreeView0

    • ii) Mostrar la hoja de propiedades de Expandir todo Botón de comando y seleccione [Procedimiento de evento] en Al hacer clic Propiedad del evento.

    • iii) Asegúrese de que la misma configuración esté intacta para Contraer todo Botón de comando también.

    • iv) Haga clic en un nodo que tenga nodos secundarios para ver si colapsan o se expanden con clics repetidos.

    • v) Si se coloca ImageList Control en el formulario, su nombre debe ser ImageList1 .

      Procedamos con la segunda parte del código VBA que implementa los eventos de arrastrar y soltar.

    Segunda mitad del código VBA.

  12. Copie la siguiente segunda parte del código VBA, en el módulo de formulario frmDragDrop, que implementa la acción de arrastrar y soltar, y péguelo debajo del código existente:

    Private Sub TreeView0_OLEStartDrag(Data As Object, AllowedEffects As Long)
        Set Me.TreeView0.SelectedItem = Nothing
    End Sub
    
    
    Private Sub TreeView0_OLEDragOver(Data As Object, _
                                    Effect As Long, _
                                    Button As Integer, _
                                    Shift As Integer, _
                                    x As Single, _
                                    y As Single, _
                                    State As Integer)
        
        Dim SelectedNode As MSComctlLib.Node
        Dim nodOver As MSComctlLib.Node
        
        If tv.SelectedItem Is Nothing Then
            'Select a node if one is not selected
            Set SelectedNode = tv.HitTest(x, y)
            If Not SelectedNode Is Nothing Then
                SelectedNode.Selected = True
            End If
        Else
            If tv.HitTest(x, y) Is Nothing Then
            'do nothing
            Else
                'Highlight the node the mouse is over
                Set nodOver = tv.HitTest(x, y)
                Set tv.DropHighlight = nodOver
            End If
        End If
    
    End Sub
    
    
    Private Sub TreeView0_OLEDragDrop(Data As Object, _
                                        Effect As Long, _
                                        Button As Integer, _
                                        Shift As Integer, _
                                        x As Single, _
                                        y As Single)
    
        Dim sourceNode As MSComctlLib.Node
        Dim SourceParentNode As MSComctlLib.Node
        Dim targetNode As MSComctlLib.Node
        
        Dim tmpRootNode As MSComctlLib.Node
        Dim strtmpNodKey As String
        Dim ChildNode As MSComctlLib.Node
        
        Dim strSPKey As String
        Dim strTargetKey As String
        
        Dim strsQL As String
        Dim intKey As Integer
        Dim intPKey As Integer
        
        On Error Resume Next
        
        Select Case Screen.ActiveControl.Name
                
               Case TreeView0.Name
                    Set sourceNode = tv.SelectedItem
                
        End Select
        
        'Get Source Parent Node & Target Node Reference
        Set SourceParentNode = sourceNode.Parent
        Set targetNode = tv.HitTest(x, y)
                
        'If any errors then exit
        If Err <> 0 Then
            MsgBox Err & " : " & Err.Description, vbInformation + vbCritical, "OLEDragDrop()"
            Err.Clear
            Exit Sub
        Else
            On Error GoTo 0
        End If
        
    
        'Get/define Source parent Node Key to compare it with Target Node Key
        If SourceParentNode Is Nothing Then
            strSPKey = "Empty"
        Else
            strSPKey = SourceParentNode.Key
        End If
        
        'Check the Target Node/Location and define the Key
         Select Case True
            Case targetNode Is Nothing
                strTargetKey = "Empty"
            
            Case targetNode.Key = ""
                strTargetKey = "Empty"
                Set targetNode = Nothing
            Case Else
                strTargetKey = targetNode.Key
         End Select
        
        'Make sure the Target Node is not the source Node's own parent
        If strTargetKey = strSPKey Then Exit Sub
        
        'Track User's Node move action, check for error.
        On Error Resume Next
        
        If targetNode Is Nothing Then
            
            'If target Node is Nothing (the Node dropped in the empty area),
            'then the Node must be moved to the Root-level
            'save the original sourceNode.Key
            strtmpNodKey = sourceNode.Key
            
            'Modify the source Node Key, with addition of some text, say 'Empty', like 'X5Empty'
            'So that a temporary Node can be created with the original source Node key.
            'Note: Two Nodes with the same Key cannot remain in memory at the same time.
            'The Source Node with key 'X5Empty' deleted later,
            'temporary Node takes it's droped location.
            sourceNode.Key = sourceNode.Key & strTargetKey
    
            'Create the temporary Root Node, with original sourceNode Key
            Set tmpRootNode = tv.Nodes.Add(, , strtmpNodKey, sourceNode.Text)
            
            'define the Root Node image indexes
            'With tmpRootNode
            '    .Image = 1
            '    .SelectedImage = 4
            'End With
            
            'Move all child Nodes from SourceNode,if any,
            'as tmpRootNode's Children
            Do Until sourceNode.Children = 0
                Set sourceNode.Child.Parent = tmpRootNode
                
                'modify Node image indexes
                'With sourceNode
                '    .Image = 2
                '    .SelectedImage = 3
                'End With
            Loop
    
            'Delete the Source Node with modified Key from TreeView
            tv.Nodes.Remove sourceNode.Index
            
            'Move the tmpRootNode with original Key
            'to the dropped location on TreeView
            Set sourceNode = tmpRootNode
        Else
            'Move the sourceNode under targetNode as child
            Set sourceNode.Parent = targetNode
            
            'modify Node image indexes
            'With sourceNode
            '    .Image = 2
            '    .SelectedImage = 3
            'End With
        End If
        
        'Notify, if there was an Error then Exit, else Update PrentID of related Record.
        If Err <> 0 Then
            MsgBox Err & " : " & "Unable to move:" & vbCrLf & Err.Description, vbInformation + vbCritical, "DragDrop2()"
            Exit Sub
        Else
            'Build and execute the SQL statement to update the record
            If targetNode Is Nothing Then
                intKey = Val(Mid(sourceNode.Key, 2))
                strsQL = "UPDATE Sample SET ParentID = Null" & _
                         " WHERE ID = " & intKey
            Else
                intKey = Val(Mid(sourceNode.Key, 2))
                intPKey = Val(Mid(targetNode.Key, 2))
                
                strsQL = "UPDATE sample SET ParentID = " & intPKey & _
                         " WHERE ID = " & intKey
            End If
            
            'Modify the table records
            CurrentDb.Execute strsQL, dbFailOnError
            
            'If an error raised then refresh TreeView and exit
            If Err <> 0 Then
                MsgBox Err & " : " & Err.Description
                LoadTreeView 'Refresh/display TreeView without changes
            Else
                'Sort Nodes
                If sourceNode.Parent Is Nothing Then
                    sourceNode.Root.Sorted = True
                Else
                    sourceNode.Parent.Sorted = True
                End If
                
                tv.Nodes(sourceNode.Key).Selected = True
            End If
        End If
        On Error GoTo 0
    
    End Sub
    
    Private Sub TreeView0_OLECompleteDrag(Effect As Long)
    
        'Turn off the drophighlight
        Set tv.DropHighlight = Nothing
    
    End Sub
    
    Private Sub Form_Close()
    
    Set tv = Nothing
    End Sub

Para la acción de arrastrar y soltar, hay cuatro subrutinas, se ejecutaron automáticamente cuando arrastra los nodos, resalta el nodo cuando se mueve sobre otros nodos y finalmente lo suelta en un nodo diferente o en el área vacía del nivel raíz. .

Las Principales Subrutinas del Código.

  • TreeView0_OLEStartDrag() - Inicializa el elemento seleccionado y establece el Nodo en Nada
  • TreeView0_OLEDragOver() - Funciona como el evento de movimiento del mouse, resalta el nodo, cuando arrastra un nodo sobre él, en el camino hacia el nodo de destino.
  • TreeView0_OLEDragDrop() – Realiza comprobaciones y controles, coloca los nodos en la ubicación soltada y actualiza el registro en la tabla base.
  • TreeView0_OLECompleteDrag() - La propiedad DropHighlight se establece en Nada.

Podemos hacer los trabajos de arrastrar y soltar con TreeView0_OLEDragDrop() Subrutina sola. En ese caso, no habrá ningún nodo resaltado, cuando el nodo de origen se mueva sobre otros nodos, de una ubicación a otra, excepto que el puntero del mouse cambia para arrastrar una segunda flecha detrás de él, como en la imagen de muestra que se muestra a continuación. :

Por lo tanto, prestaremos atención a esta subrutina y revisaremos el Código en detalle desde el principio. Al principio de la subrutina, hemos declarado los Nodos y Variables de Cadena necesarios, y otros.

En lugar de repetir análisis línea por línea aquí, he comentado cada línea/sección de códigos adecuadamente para que comprenda lo que hace cuando revisa el Código. Puede revisarlos.

La secuencia de eventos Drap Drop

Entendamos la secuencia de Eventos, el Usuario Selecciona un nodo, arrastra sobre otros nodos en el camino hacia su destino final y solta en el nodo de destino. O colóquelo en el área vacía del control TreeView para convertirlo en un nodo de nivel raíz.

Cuando arrastra un Nodo sobre otro Nodo-Texto, el Nodo-Texto se resalta, diciendo que su posición actual está en este Nodo en el camino, dondequiera que vaya desde aquí. Cuando se mueve fuera del texto del nodo, el resaltado desaparece. Esto sucede hasta el nodo de destino. El TreeView0_OLEDragOver() La subrutina se encarga de esta acción de resaltado.

Cuando suelta un nodo en algún lugar, el TreeView0_OLEDragDrop() La subrutina se sobrecarga. Aquí, tenemos que analizar las intenciones del Usuario y tomar las medidas apropiadas. La siguiente información debe guardarse y analizarse para mover el Nodo a la ubicación correcta.

Información importante a tener en cuenta.

  1. La referencia de nodo de origen, la clave de nodo y los valores de ID de padre, hijos de nodo, si los hay.

  2. El nodo de destino o referencia de ubicación, clave de nodo.

  3. Si el objetivo no es un nodo sino el área vacía del control TreeView, entonces el nodo de origen se moverá a la posición de nivel raíz.

  4. El nodo de origen cuando se coloca en otro nodo, el nodo de destino se convierte en el nuevo padre del nodo de origen.

  5. Si el nodo de origen tiene sus propios elementos secundarios, también se deben mover con su elemento principal.

  6. ** Cuando el nodo se arrastre y suelte en su propio nodo principal, ignore esta acción.

    ** Por ejemplo, compruebe la imagen de arriba. Si arrastramos el TextBox Nodo y suéltelo en su nodo principal Controles, o arrastra los Controles Nodo y suéltelo en su formulario de nodo principal entonces esos movimientos serán ignorados.

  7. ** Si nivel raíz El nodo se arrastra y suelta en el área vacía, luego no se realizará ninguna acción porque ya es un nodo de nivel raíz.

Para todos los movimientos válidos de Node, necesitamos actualizar el ParentID valor de campo del registro relacionado en la muestra Mesa.

Caída de nodo en el área vacía del nivel raíz.

En el caso del artículo número 3 arriba, tenemos que crear un Nodo de nivel Raíz, con el mismo Número de ID del Nodo Fuente, lo cual no está permitido. El valor de clave duplicado no está permitido en la jerarquía de TreeView. Esta es la única área del Código, donde encontrará un poco confuso el procedimiento seguido allí.

El procedimiento es el siguiente:

  1. Modifique la clave de nodo TreeView existente con la adición de texto adicional (diga Clave X5 cambiar a X5Vacío ), para evitar conflictos de clave, mientras se crea un nodo temporal con la clave original.

  2. Crear un temporal Nodo con la clave original:X5.

  3. Mueva todos los nodos secundarios del nodo de origen, si los hay, como nodos secundarios al nodo temporal.

  4. Elimine el nodo de origen TreeView con la clave modificada:X5Empty desde el control TreeView, pero el registro relacionado en la tabla de muestras no se toca.

  5. Mover el temporal Nodo con la clave original X5 con sus hijos a la posición de nivel raíz del control TreeView.

  6. Actualice el campo ParentID del registro relacionado con una cadena de longitud cero ("") para marcarlo como un nodo de nivel raíz.

Experimentos propios de arrastrar y soltar.

Puede probar algunos experimentos de arrastrar y soltar y ver cómo funciona. Seleccione un nodo, haga clic y mantenga presionado el botón izquierdo del mouse, arrastre el nodo y suéltelo en otro nodo, o suéltelo en un área vacía del control TreeView. Cuando arrastra el nodo sobre otro texto de nodo, se resalta y cuando está fuera del nodo, el resaltado desaparece. El nodo arrastrado aparecerá en la nueva ubicación donde lo soltó. Puede repetir este experimento de arrastrar y soltar seleccionando un solo nodo o nodo con hijos.

Basado en este movimiento de Nodos, el ParentID del registro relacionado el valor del campo se actualizará con la Clave valor (ID) del registro relacionado con el nodo de destino.

¿Por qué un procedimiento de llenado de nodos en dos pasos?

Ahora, volveremos a LoadTreeView() Subrutina, para echar un segundo vistazo al proceso de dos pasos que hemos adoptado para llenar todos los nodos del control TreeView.

  • Todos los registros de la muestra La tabla se agrega inicialmente como nodos de nivel raíz, utilizando el valor del campo de ID como clave de nodo.

  • En la segunda pasada de los registros, si el valor del campo ParentID está vacío, ese nodo permanecerá como nodo de nivel raíz, sin cambios.

  • Todos los demás registros relacionados con nodos con ParentID Value se mueven correctamente bajo su nodo principal.

Naturalmente, surge la pregunta, ¿por qué tenemos que hacerlo de esta manera?

Haremos un experimento simple para aclarar la respuesta sin explicarla con demasiadas palabras. Es posible que ya haya realizado algunas ejecuciones de prueba de arrastrar y soltar y haya reorganizado los nodos, en el proceso actualizó los valores de ParentID de esos registros con el cambio. Por lo tanto, debemos restablecer los valores de registro a su estado original en la muestra Table, antes de comenzar una nueva demostración.

Ya hemos creado una copia de nuestra Tabla Muestra anteriormente, con el nombre Sample_bk como copia de seguridad. Eliminar la muestra Tabla y hacer una copia de Sample_bk con el nombre original:Muestra .

Abra la tabla y vea los registros y sus valores de campo ParentID. La imagen de muestra de la tabla se muestra a continuación:

Los valores de campo de ID son autonuméricos y están todos en orden secuencial y todos los valores de ID son únicos. La siguiente regla simple rige la adición de un nodo secundario al control TreeView.

La regla del nodo secundario simple: El ID de padre Valor del campo (Clave principal ) en un registro espera que ya exista un nodo principal en el control TreeView, con el mismo valor que Node-Key (la identificación).

Verifique el tercer registro desde arriba, en la imagen de la tabla anterior. El valor del campo ParentID es 2 y el ID del registro actual es 3. En este caso, el registro con ID 2 se agregará al Control TreeView antes de que intentemos agregar el tercer registro al Nodo. Ambos registros no están necesariamente uno al lado del otro. Verifique el registro con el número de ID 21, su valor de campo ParentID es 12, menos que el valor de ID de registros actual 21.

En cualquier caso, cuando el programa encuentra el valor ParentID en un registro, asume que el registro con el valor de ID igual al ParentID ya se agregó como un nodo en el control TreeView en el ciclo anterior de llenado de los nodos.

Justificación del procedimiento de dos pasos.

Probemos algunas ejecuciones de prueba de arrastrar y soltar. Pero, antes de eso, tenemos un Formulario con el nombre frmSample, que que hemos usado en la primera sesión del tutorial, y en la que hemos cargado todos los nodos TreeView de una sola vez. Sí, hemos seguido el mismo método hasta ahora y necesitamos algún cambio a partir de ahora. Pero, antes de eso, abramos el formulario anterior y veamos cómo aparecen los Nodos en el Formulario.

  1. Abra el formulario frmSample para ver cómo se ve la visualización de TreeView, con los registros de la tabla de muestra, cargados con la regla anterior.

  2. Si ha terminado de ver los nodos TreeView, cierre el formulario.

  3. Ahora, abra el frmDragDrop Forma. Nos estamos preparando para arrastrar y soltar un nodo.

  4. Seleccione el nodo con la tabla de texto de nodo, Haga clic y mantenga presionado el botón izquierdo del mouse, arrástrelo y suéltelo en el Nodo, con el Formulario de Nodo-Texto.

  5. La Mesa Nodo con sus campos de nodo secundario inmediatos y sus nodos secundarios se mueven como nodos secundarios bajo el formulario Nodo.

  6. Cierra el formulario frmDragDrop y ábrelo de nuevo. Los nodos aparecerán correctamente, donde los haya soltado, como la imagen que se muestra a continuación.

  7. Ahora, cierre el Formulario frmDragDrop.

  8. Abra el formulario frmSample para ver cómo aparece este cambio en este Formulario. Recibirá un mensaje de error, Elemento no encontrado con Número de error:35601.

  9. Seleccione el botón de comando de depuración para ir a la línea de código resaltada, donde ocurrió el error.

  10. Apunte el mouse sobre la nodKey Param del método Add(), muestra X3, punto el ratón sobre la ParentKey parámetro y muestra X7.

    Mirando estos dos valores de parámetros, podemos suponer que estamos en el registro con el valor de ID 3 y tratando de designar este nodo como un nodo secundario, a otro nodo que aún no se ha rellenado en el Control TreeView, con valor de ID 7.

  11. Presiona F5 Presione la tecla para abrir el mismo cuadro de diálogo nuevamente y haga clic en Terminar Botón de comando para detener el programa y mostrar el formulario en la ventana de la base de datos. Cierre el formulario frmSample.

  12. Abra la muestra Tabla para ver la disposición de los números ParentID, después de nuestra acción de arrastrar y soltar. Los registros se verán como la imagen que se muestra a continuación y he resaltado el registro que provocó el error con el valor de ParentID 7 y mostrando su posición de registro principal.

Siguiendo el procedimiento normal de llenado de nodos anterior, estamos en la tercera posición de registro. Dado que los registros ParentID valor 7, el Nod con ID valor 7 debe estar presente en el control TreeView. El nodo con valor de ID 7 aún no está poblado en el control TreeView, pero estamos tratando de hacer referencia al nodo inexistente y esto desencadena un error.

Incluso si ordena los registros en el orden del campo ParentID, la nueva disposición de los registros se verá como la imagen que se muestra a continuación:

Ahora, el nodo principal de otro registro no está en la posición esperada.

Por lo tanto, en estas circunstancias, nuestro enfoque de carga de TreeView Nodes de dos pasos funciona tanto para las acciones normales como para después de arrastrar y soltar.

En el primer paso, rellene todos los registros como nodos de nivel raíz en el control TreeView utilizando el valor del campo ID como clave de nodo.

Ahora, todos los Nodos de todos los registros están disponibles en el Control TreeView. Será fácil moverlos por donde queramos. No dice que ninguno de los nodos requeridos existe en TreeView.

En la segunda pasada en el mismo conjunto de registros, los registros con valores de campo ParentID vacíos no se tocan y se les permite permanecer como nodos de nivel raíz. En otros casos, mueve el nodo como nodo secundario debajo de su nodo principal, actualizando el [Relativo] Parámetro del Nodo con la siguiente Declaración:

Set tv.Nodes.Item(strKey).Parent = tv.Nodes.Item(strPKey)

This is what we do through the second pass on the same set of records. You may do it by resetting the Record Pointer to the first record, by executing rst.MoveFirst before the Do . . . Loop, EOF conditions and rst.MoveNext to access each record as we normally do.

Second Step in Reverse Order.

Or you may do it in reverse order. After populating all records as Root-level Nodes the Record Pointer will be beyond the last record and on the EOF posición. You may reset the record pointer to the last record, by executing rst.MoveLast before the Do . . . Loop BOF check, and execute rst.MovePrevious to access each record and move the Nodes correctly under its p arent Node. But, the Nodes may load slightly differently in the placement order of Nodes.

You may try this out yourself with the above-suggested change of Code and see the result.

Download Demo Database


  1. Módulo de clase MS-Access y VBA
  2. Matrices de objetos de clase VBA de MS-Access
  3. Clase base de MS-Access y objetos derivados
  4. VBA Base Class and Derived Object-2
  5. Variantes de clase base y objeto derivado
  6. Módulo de clase y conjunto de registros de MS-Access
  7. Módulo de clase de acceso y clases contenedoras
  8. Transformación de la funcionalidad de la clase contenedora