sql >> Database >  >> RDS >> Access

TreeView-knooppunten opnieuw rangschikken met slepen en neerzetten

Inleiding.

Ik hoop dat je de tutorial van vorige week over ImageCombo Control nuttig vond voor je Microsoft Access-projecten. Met de TreeView ImageCombo-besturing konden we een prachtig vervolgkeuzemenu maken, met verschillende opties, en dit in een kleine ruimte op het formulier plaatsen.

Evenzo hebben we in een eerdere sessie geleerd hoe u nieuwe knooppunten op een specifieke locatie in de knooppunthiërarchie kunt toevoegen of hoe u een knooppunt kunt verwijderen en een nieuwe kunt toevoegen om een ​​knooppunt in de boomstructuurweergave te verplaatsen.

Deze methode vraagt ​​om het aanmaken van een nieuw record in de brontabel voor het nieuwe knooppunt. Of verwijder een bestaande record en maak een nieuwe om een ​​bestaand knooppunt te verplaatsen om ze permanent te maken. In zekere zin zouden we met het gebruik van functies voor toevoegen/verwijderen nieuwe knooppunten kunnen toevoegen of de bestaande knooppunten opnieuw kunnen rangschikken in het TreeView-besturingselement. Wat het herschikken van knooppunten betreft, hebben we een betere manier om dit te doen, in plaats van knooppunten te verwijderen en ze opnieuw te maken. Sleep het knooppunt van de huidige locatie en zet het neer waar we het willen hebben in het TreeView-besturingselement. Dit gaan we leren in deze aflevering

Deze eenvoudige aanpak hoeft alleen de wijziging van de ParentID-veldwaarde van gerelateerde records bij te werken, om de wijziging permanent te maken.

De onderwerpen die tot nu toe in eerdere sessies zijn behandeld.

  1. Microsoft TreeView Control-zelfstudie
  2. Toegangsmenu maken met TreeView Control
  3. Afbeeldingen toewijzen aan TreeView-besturingselement
  4. Afbeeldingen toewijzen aan TreeView Control-2
  5. TreeView Control Vinkje Toevoegen Verwijder Nodes
  6. Vervolgkeuzemenu TreeView ImageCombo

Maar het kan zijn dat we tijdens het gebruik van deze methode met enkele uitdagingen worden geconfronteerd en daar komen we later in deze sessie op terug.

Demogegevenstabel en formulier.

We hebben een tabel en een formulier nodig. We hebben al een geschikte tafel met de naam Voorbeeld gemaakt in een eerdere zelfstudiesessie. Als u de demodatabase al heeft gedownload vanaf de tweede linkpagina hierboven, dan kunt u die database ook voor deze sessie gebruiken. We zullen de volgende objecten uit die database gebruiken voor onze Drag-Drop-experimenten:

  • Tabel:Voorbeeld
  • Formulier:frmSample

De TreeView-besturingsafbeelding op frmSample met demogegevens wordt hieronder ter referentie gegeven:

U kunt de demodatabase downloaden (ProjectMenu.zip ) van de tweede linkpagina hierboven en extraheer het ProjectMenu.accdb databank.

Nieuw formulier voor proefversies met drag-drop.

  1. Open de ProjectMenu.accdb-database.

  2. Maak een kopie van de tabel Voorbeeld en noem het als Sample_bk, bewaar het veilig, we hebben de originele gegevens later zonder wijziging nodig. Als we experimenteren met de methode slepen en neerzetten, is het nodig om de veldwaarde ParentId in de voorbeelddemotabel bij te werken. Maar we hebben de originele gegevens later nodig, zonder deze wijzigingen.

  3. Maak een nieuw formulier met de naam frmDragDrop .

  4. Het frmDragDrop-formulierontwerp ziet eruit als de onderstaande afbeelding als u klaar bent.

  5. Voeg het TreeView-besturingselement in uit de lijst met ActiveX-besturingselementen en plaats het op het formulier, met voldoende ruimte boven het besturingselement, zodat we twee opdrachtknoppen en een koplabel erboven kunnen maken. Sleep de formaatgreep in de rechterbenedenhoek om deze groot genoeg te maken om alle knooppunten weer te geven, zonder te scrollen.

  6. Wijzig de Naam Eigenschapswaarde van TreeView Control naar TreeView0 .

  7. Plaats een opdrachtknop boven en linkerrand van het TreeView-besturingselement. Wijzig de Naam Eigenschapswaarde naar cmdExpand en Bijschrift waarde voor Alles uitvouwen .

  8. Plaats een tweede opdrachtknop boven en aan de rechterrand van het TreeView-besturingselement. Wijzig de Naam Eigenschapswaarde naar cmdCollapse en het Bijschrift Eigenschapswaarde om Alles samen te vouwen.
  9. Voeg een labelbesturingselement in boven de opdrachtknoppen, breed genoeg om de kop te schrijven zoals hierboven weergegeven, en verander de lettergrootte 14.

  10. Negeer het ImageList-besturingselement, voorlopig heb ik commentaar gegeven op de coderegels die de indexnummers van Node ImageList wijzigen. Later kunt u het ImageList-besturingselement importeren met handmatig geüploade afbeeldingen uit onze eerdere zelfstudiedemodatabase (van de 4e linkpagina hierboven) en deze gebruiken om knooppuntafbeeldingen op knooppunten weer te geven. Wanneer knooppuntposities worden gewijzigd tijdens acties met slepen en neerzetten, moeten we knooppuntafbeeldingen ook wijzigen afhankelijk van de positie van het knooppunt (knooppunt op rootniveau of onderliggende knooppunt) op het TreeView-besturingselement.

    Drag-Drop Form Module Code.

  11. Geef de VBA-codemodule van het formulier frmDragDrop weer, kopieer en plak de volgende VBA-code (dit is alleen de eerste helft van de formuliermodulecode) in de klassenmodule van het frmDragDrop-formulier en sla het formulier op:

    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

    Ik weet dat je bekend bent met de bovenstaande code, als je de eerdere afleveringen al hebt doorgenomen, behalve de LoadTreeView() subroutine met enkele wijzigingen. Hier is het vullen van de TreeView-knooppunten verdeeld in een proces in twee stappen.

    Dit is in het kort wat er in deze subroutine gebeurt.

    • Alle records op de Voorbeeld Tabel is geladen als knooppunten op rootniveau van TreeView Control, met een ID-veldwaarde als Sleutel, in de eerste stap.

    • Nogmaals, deze records zijn een tweede keer gelezen en gecontroleerd op een waarde in de ParentId veld, als het leeg is, wordt het knooppunt behouden als knooppunt op rootniveau.

    • Als het ParentID-veld een Value heeft, identificeer dan de Node met de ParentID-waarde als Node-Key en verplaats het huidige knooppunt als zijn onderliggende knooppunt, of zijn [Relative] Parameter (van Toevoegen () Methode) waarde wordt bijgewerkt.

    • Ook al lijkt het erop dat de tweestaps procedure voor het vullen van knooppunten een onnodige oefening is, is er een goede reden waarom we deze methode moeten volgen. We komen hier later op terug en je zult het weten zonder veel uitleg.

    • Op het ontwerp van het formulier heb ik een ImageList-besturingselement gegeven. U kunt het ImageList ActiveX-besturingselement . invoegen en upload handmatig enkele afbeeldingen vanaf de schijf, of kopieer en plak dit besturingselement met afbeeldingen van eerdere demodatabasedownloads. Zorg er in beide gevallen voor dat de naam van het ImageList-besturingselement ImageList1 is . Anders moet u de naam in de code wijzigen.

    • Schakel daarna de uitgecommentarieerde regels in Form_Open() Event Procedure in. Schakel de volgende regels in door het commentaarsymbool aan het begin van de regel te verwijderen:

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

    • In de TreeView0_ OLEDragDrop() Subroutine (in het 2e deel van de VBA-code) schakelt de afbeeldingsindexparameters van knooppunten in door de commentaarsymbolen ook uit die regels te verwijderen. Met deze wijzigingen verschijnen de knooppuntafbeeldingen op het TreeView-besturingselement. Als je een eigen ImageList-besturingselement hebt met geüploade afbeeldingen, verander dan de indexnummers op basis van de afbeelding die je op de knooppunten wilt invoegen.

      De TreeView0_NodeClick() Gebeurtenisprocedure Breidt het huidige knooppunt uit, als de onderliggende knooppunten zich in een samengevouwen toestand bevinden, anders worden onderliggende knooppunten samengevouwen. Normaal gesproken wordt deze actie gecontroleerd (zonder code) door te klikken op de +/- Symbool op de boomlijn van het knooppunt met onderliggende knooppunten.

      De subroutines cmdExpand_Click() en cmdCollapse_Click() Evenementen Vouwt respectievelijk alle knooppunten uit en vouwt alle knooppunten samen.

      Wanneer de bovenstaande code wordt uitgevoerd, ziet het scherm eruit als de onderstaande afbeelding voor formulierweergave:

    • U kunt de frmDragDrop . opslaan Formulier en open het in de normale weergave. Als alles goed is gegaan ziet u het bovenstaande scherm. Probeer de Alles uitvouwen en Alles samenvouwen Command-knoppen en controleer of ze ook werken. Zo niet, controleer dan opnieuw of de volgende instellingen correct zijn of niet:

    • i) De naam van TreeView Control is:TreeView0

    • ii) Toon het eigenschappenblad van Exampand All Command-knop en selecteer [Event Procedure] in de On Click Evenement eigendom.

    • iii) Zorg ervoor dat dezelfde instelling intact is voor Alles samenvouwen Command-knop ook.

    • iv) Klik op een knooppunt met onderliggende knooppunten om te zien of ze bij herhaald klikken in- of uitklappen.

    • v) Als ImageList Control op het formulier is geplaatst, moet de naam ImageList1 zijn .

      Laten we verder gaan met het tweede deel van de VBA-code die de Drag-Drop-gebeurtenissen implementeert.

    Tweede helft van de VBA-code.

  12. Kopieer het volgende tweede deel van de VBA-code, op de frmDragDrop-formuliermodule, die de actie Drag-Drop implementeert, en plak het onder de bestaande code:

    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

Voor de actie Drag-Drop zijn er vier subroutines, deze worden automatisch uitgevoerd wanneer u de node(s) sleept, markeren de node wanneer deze over andere nodes wordt verplaatst en laten deze uiteindelijk vallen op een andere node of op het lege gebied op rootniveau .

De belangrijkste subroutines van de code.

  • TreeView0_OLEStartDrag() - Initialiseert het geselecteerde item en stelt de Node in op Niets
  • TreeView0_OLEDragOver() - Werkt als de Mouse Move-gebeurtenis, markeert het knooppunt, wanneer een knooppunt erboven wordt gesleept, op weg naar het doelknooppunt.
  • TreeView0_OLEDragDrop() – Voert controles en controles uit, plaatst de node(s) op de neergelaten locatie en werkt de record bij op de basistabel.
  • TreeView0_OLECompleteDrag() - De eigenschap DropHighlight is ingesteld op Niets.

We kunnen de werken met slepen en neerzetten doen met de TreeView0_OLEDragDrop() Subroutine alleen. In dat geval zal er geen Node-highlight zijn, wanneer de Source Node over andere Nodes beweegt, van de ene locatie naar de andere, behalve dat de muisaanwijzer verandert in het slepen van een tweede pijl erachter, zoals in de onderstaande voorbeeldafbeelding :

We zullen dus aandacht besteden aan deze subroutine en de code vanaf het begin in detail controleren. Aan het begin van de subroutine hebben we de benodigde Nodes en String Variables en andere gedeclareerd.

In plaats van hier regel voor regel analyses te herhalen, heb ik op elke regel/sectie van codes een passend commentaar gegeven, zodat u begrijpt wat het doet als u de Code doorneemt. Je kunt ze doornemen.

De opeenvolging van Drap Drop-gebeurtenissen

Laten we de volgorde van gebeurtenissen begrijpen die de gebruiker selecteert een node, sleept over andere nodes op weg naar zijn eindbestemming, en drops het op het doelknooppunt. Of laat het op het lege gebied op het TreeView-besturingselement vallen om er een knooppunt op rootniveau van te maken.

Wanneer je een Node over een andere Node-Text sleept, wordt de Node-Text gemarkeerd, met de mededeling dat je huidige positie op deze Node onderweg is, waar je ook heen gaat. Wanneer deze uit de Node-tekst wordt verplaatst, verdwijnt de markering. Dit gebeurt tot aan de Target Node. De TreeView0_OLEDragOver() Subroutine zorgt voor deze markeringsactie.

Wanneer u een knooppunt ergens neerzet, wordt de TreeView0_OLEDragDrop() Subroutine neemt overbelasting. Hier moeten we de bedoelingen van de gebruiker analyseren en passende maatregelen nemen. De volgende informatie moet worden opgeslagen en geanalyseerd om de Node naar de juiste locatie te verplaatsen.

De belangrijke informatie om bij te houden.

  1. De bronknooppuntreferentie, knooppuntsleutel en ParentID-waarden, knooppuntkinderen, indien aanwezig.

  2. Het doelknooppunt of de locatiereferentie, knooppuntsleutel.

  3. Als het doel geen knooppunt is maar het lege gebied van het TreeView-besturingselement, dan moet het bronknooppunt naar de positie op rootniveau worden verplaatst.

  4. Het bronknooppunt wanneer het op een ander knooppunt wordt gedropt, wordt het doelknooppunt het nieuwe bovenliggende knooppunt van het bronknooppunt.

  5. Als Source Node zijn eigen kinderen heeft, moeten deze ook met hun ouder worden verplaatst.

  6. ** Wanneer de Node op zijn eigen Parent-Node wordt gesleept en neergezet, negeer deze actie dan.

    ** Bekijk bijvoorbeeld de bovenstaande afbeelding. Als we het TextBox . slepen Knooppunt en zet het neer op het bovenliggende knooppunt Controls, of sleept de Controls Knooppunt en zet het neer op zijn bovenliggende knooppunt Formulier dan worden die zetten genegeerd.

  7. ** Als Rootniveau Het knooppunt wordt naar het lege gebied gesleept en neergezet, waarna er geen actie wordt ondernomen omdat het al een knooppunt op rootniveau is.

Voor alle geldige verplaatsingen van Node moeten we de ParentID . bijwerken veldwaarde van het gerelateerde record op het Voorbeeld Tafel.

Knooppuntdaling in het lege gebied op rootniveau.

In het geval van artikelnummer 3 hierboven moeten we een knooppunt op rootniveau maken, met hetzelfde ID-nummer van het bronknooppunt, wat niet is toegestaan. Dubbele sleutelwaarde is niet toegestaan ​​in de TreeView-hiërarchie. Dit is het enige deel van de Code waar u een beetje verwarrend zult zijn over de procedure die daar wordt gevolgd.

De procedure is als volgt:

  1. Wijzig de bestaande TreeView Node Key met de toevoeging van wat extra tekst, (zeg Key X5 verander naar X5Leeg ), om sleutelconflicten te voorkomen, terwijl u een tijdelijk knooppunt maakt met de originele sleutel.

  2. Maak een tijdelijke Knooppunt met de originele sleutel:X5.

  3. Verplaats alle onderliggende knooppunten van het bronknooppunt, indien aanwezig, als onderliggende knooppunten naar het tijdelijke knooppunt.

  4. Verwijder de TreeView Source Node met de gewijzigde sleutel:X5Empty van het TreeView-besturingselement, maar het gerelateerde record op de voorbeeldtabel wordt niet aangeraakt.

  5. Verplaats de tijdelijke Knooppunt met de originele sleutel X5 met zijn kinderen naar de positie op rootniveau van het TreeView-besturingselement.

  6. Werk het ParentID-veld van het gerelateerde record bij met een tekenreeks met lengte nul (“”) om het te markeren als een knooppunt op rootniveau.

Zelfexperimenten met Drag Drop.

U kunt zelf enkele Drag and Drop-experimenten uitproberen en kijken hoe het werkt. Selecteer een knooppunt, klik en houd de linkermuisknop ingedrukt, sleep het knooppunt en zet het neer op een ander knooppunt, of zet het neer in een leeg gebied van het TreeView-besturingselement. Wanneer u de Node over andere Node-Text sleept, wordt deze gemarkeerd en wanneer u zich buiten de Node bevindt, gaat de markering uit. Het versleepte knooppunt verschijnt op de nieuwe locatie waar u het hebt neergezet. U kunt dit experiment met slepen en neerzetten herhalen door een enkel knooppunt of knooppunt met kinderen te selecteren.

Op basis van deze verplaatsing van Nodes is de ParentID . van het gerelateerde record veldwaarde wordt bijgewerkt met de Sleutel waarde (ID) van het Target Node-gerelateerde record.

Waarom een ​​procedure voor het vullen van knooppunten in twee stappen?

Nu gaan we terug naar de LoadTreeView() Subroutine, om een ​​tweede blik te werpen op het proces in twee stappen dat we hebben aangenomen voor het vullen van alle knooppunten in het TreeView-besturingselement.

  • Alle records in het Voorbeeld Tabellen worden aanvankelijk toegevoegd als knooppunten op rootniveau, waarbij de ID-veldwaarde wordt gebruikt als knooppuntsleutel.

  • In de tweede doorgang van de records, als de waarde van het ParentID-veld leeg is, blijft dat knooppunt ongewijzigd als knooppunt op rootniveau.

  • Alle andere Nodes-gerelateerde records met ParentID-waarde worden correct verplaatst onder het bovenliggende knooppunt.

Natuurlijk komt de vraag op:waarom moeten we het op deze manier doen?

We zullen een eenvoudig experiment doen om het antwoord duidelijk te maken zonder het in te veel woorden uit te leggen. Mogelijk hebt u zelf al enkele proefruns met slepen en neerzetten gedaan en Nodes opnieuw gerangschikt, terwijl u de ParentID-waarden van die record met de wijziging hebt bijgewerkt. We moeten de recordwaarden dus terugzetten naar hun oorspronkelijke staat in het Voorbeeld Table, voordat we een nieuwe demo starten.

We hebben al een kopie gemaakt van onze Tabel Voorbeeld eerder, met de naam Sample_bk als back-up. Verwijder het Voorbeeld Tabel en maak een kopie van Sample_bk met de originele naam:Voorbeeld .

Open de tabel en bekijk de records en hun ParentID-veldwaarden. De voorbeeldafbeelding van de tabel wordt hieronder gegeven:

De ID-veldwaarden zijn AutoNummers en ze staan ​​allemaal in sequentiële volgorde en alle ID-waarden zijn uniek. De volgende eenvoudige regel regelt de toevoeging van een onderliggend knooppunt aan het TreeView-besturingselement.

De eenvoudige regel voor onderliggende knooppunten: De Ouder-ID veld Waarde (Oudersleutel ) in een record verwacht dat er al een bovenliggend knooppunt bestaat in het TreeView-besturingselement, met dezelfde waarde als Node-Key (de ID).

Controleer het derde record van boven, in de bovenstaande tabelafbeelding. De waarde van het ParentID-veld is 2 en de ID van het huidige record is 3. In dit geval wordt het record met ID 2 toegevoegd aan het TreeView-besturingselement voordat we proberen het derde record aan het knooppunt toe te voegen. Beide records staan ​​niet per se naast elkaar. Controleer het record met ID-nummer 21, de waarde van het ParentID-veld is 12, minder dan de huidige ID-waarde van het record 21.

In beide gevallen, wanneer het programma de ParentID-waarde in een record tegenkomt, neemt het aan dat het record met de ID-waarde die gelijk is aan de ParentID al als een knooppunt in het TreeView-besturingselement was toegevoegd in de eerdere cyclus van het vullen van de knooppunten.

De procedure in twee stappen rechtvaardigen.

Laten we een paar proefversies van Drag-Drop proberen. Maar daarvoor hebben we een formulier met de naam frmSample, welke we hebben gebruikt in de eerste Tutorial Sessie, en daarin hebben we alle TreeView Nodes in één keer geladen. Ja, we hebben tot nu toe dezelfde methode gevolgd en we hebben vanaf nu wat verandering nodig. Maar laten we eerst het oude formulier openen en kijken hoe de knooppunten op het formulier verschijnen.

  1. Open het formulier frmSample om te zien hoe de TreeView-weergave eruitziet, met de voorbeeldtabelrecords, geladen volgens de oude regel.

  2. Als u klaar bent met het bekijken van de TreeView-knooppunten, sluit dan het formulier.

  3. Open nu de frmDragDrop Formulier. We bereiden ons voor om een ​​Node te slepen en neer te zetten.

  4. Selecteer de Node met de Node-Text Tabel, Klik en houd de linkermuisknop ingedrukt, sleep het naar de Node, met de Node-Text Form.

  5. De Tabel Knooppunt met zijn onmiddellijke onderliggende knooppunt Velden en zijn onderliggende knooppunten worden verplaatst als onderliggende knooppunten onder het formulier Knooppunt.

  6. Sluit het formulier frmDragDrop en open het weer. De Nodes zullen correct verschijnen waar je ze hebt neergezet, zoals in de onderstaande afbeelding.

  7. Sluit nu het formulier frmDragDrop.

  8. Open het formulier frmSample om te zien hoe deze wijziging wordt weergegeven op dit formulier. U wordt begroet met een foutmelding, Element niet gevonden met Foutnummer:35601.

  9. Selecteer de opdrachtknop Debug om naar de gemarkeerde coderegel te gaan, waar de fout is opgetreden.

  10. Wijs met de muis op de nodKey Param van de methode Add() toont X3, punt de muis op de ParentKey parameter en het toont X7.

    Als we naar deze twee parameterwaarden kijken, kunnen we aannemen dat we geregistreerd zijn met de ID-waarde 3 en proberen dit knooppunt aan te wijzen als een onderliggend knooppunt, naar een ander knooppunt dat nog niet is ingevuld in het TreeView-besturingselement, met ID-waarde 7.

  11. Druk op F5 Toets om hetzelfde dialoogvenster opnieuw te openen en klik op de Einde Command-knop om het programma te stoppen en het formulier in het databasevenster te openen. Sluit het frmSample-formulier.

  12. Open het Voorbeeld Tabel om de rangschikking van de ParentID-nummers te bekijken, na onze slepen-en-neerzetten-actie. De records zien er uit als de onderstaande afbeelding en ik heb de record gemarkeerd die de fout veroorzaakte met de ParentID-waarde 7 en toont de positie van het bovenliggende record.

Na de eerdere Node die de normale procedure vult, bevinden we ons op de derde recordpositie. Sinds de records ParentID waarde 7, de Nod met ID waarde 7 moet aanwezig zijn in de TreeView Control. Het knooppunt met ID-waarde 7 is nog niet ingevuld in het TreeView-besturingselement, maar we proberen te verwijzen naar het niet-bestaande knooppunt en dit veroorzaakt een fout.

Zelfs als u de records sorteert in het veld Ouder-ID, ziet de nieuwe indeling van de records eruit als de onderstaande afbeelding:

Nu bevindt het bovenliggende knooppunt van een ander record zich niet in de verwachte positie.

In deze omstandigheden werkt onze tweestaps-aanpak voor het laden van TreeView Nodes dus ook voor zowel normale acties als acties na slepen en neerzetten.

Vul in de eerste stap alle records in als knooppunten op rootniveau in het TreeView-besturingselement met de ID-veldwaarde als knooppuntsleutel.

Nu zijn alle knooppunten van alle records beschikbaar in het TreeView-besturingselement. Het zal gemakkelijk zijn om ze te verplaatsen waar we maar willen. Er staat niet dat een van de vereiste nodes niet bestaat in de TreeView.

Bij de tweede doorgang van dezelfde set records blijven de records met lege ParentID-veldwaarden ongewijzigd en mogen ze als knooppunten op rootniveau blijven. In andere gevallen verplaatst het knooppunt als onderliggend knooppunt onder het bovenliggende knooppunt, door de [Relative] bij te werken Parameter van het knooppunt met de volgende verklaring:

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 position. 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. MS-Access Class-module en VBA
  2. MS-Access VBA Class Object Arrays
  3. MS-Access-basisklasse en afgeleide objecten
  4. VBA Base Class and Derived Object-2
  5. Basisklasse en afgeleide objectvarianten
  6. MS-Access-recordset en klassenmodule
  7. Toegang tot klassenmodule en wrapperklassen
  8. Transformatie van functionaliteit van wrapperklasse


  1. SQL Server 2016:een opgeslagen procedure maken

  2. MySQL ATAN2() Functie – Retourneer de boogtangens van 2 waarden

  3. Wat te doen als u een onjuiste bladwijzer-rangschikkingsfout krijgt bij het gebruik van SQL Server met ons Oracle ODBC-stuurprogramma?

  4. Hoe de PostgreSQL array_agg-functie naar SQLite vertalen?