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.
- Microsoft TreeView Control-zelfstudie
- Toegangsmenu maken met TreeView Control
- Afbeeldingen toewijzen aan TreeView-besturingselement
- Afbeeldingen toewijzen aan TreeView Control-2
- TreeView Control Vinkje Toevoegen Verwijder Nodes
- 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.
-
Open de ProjectMenu.accdb-database.
-
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.
-
Maak een nieuw formulier met de naam frmDragDrop .
-
Het frmDragDrop-formulierontwerp ziet eruit als de onderstaande afbeelding als u klaar bent.
-
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.
-
Wijzig de Naam Eigenschapswaarde van TreeView Control naar TreeView0 .
-
Plaats een opdrachtknop boven en linkerrand van het TreeView-besturingselement. Wijzig de Naam Eigenschapswaarde naar cmdExpand en Bijschrift waarde voor Alles uitvouwen .
- 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.
-
Voeg een labelbesturingselement in boven de opdrachtknoppen, breed genoeg om de kop te schrijven zoals hierboven weergegeven, en verander de lettergrootte 14.
-
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.
-
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.
-
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.
-
De bronknooppuntreferentie, knooppuntsleutel en ParentID-waarden, knooppuntkinderen, indien aanwezig.
-
Het doelknooppunt of de locatiereferentie, knooppuntsleutel.
-
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.
-
Het bronknooppunt wanneer het op een ander knooppunt wordt gedropt, wordt het doelknooppunt het nieuwe bovenliggende knooppunt van het bronknooppunt.
-
Als Source Node zijn eigen kinderen heeft, moeten deze ook met hun ouder worden verplaatst.
-
** 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.
-
** 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:
-
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.
-
Maak een tijdelijke Knooppunt met de originele sleutel:X5.
-
Verplaats alle onderliggende knooppunten van het bronknooppunt, indien aanwezig, als onderliggende knooppunten naar het tijdelijke knooppunt.
-
Verwijder de TreeView Source Node met de gewijzigde sleutel:X5Empty van het TreeView-besturingselement, maar het gerelateerde record op de voorbeeldtabel wordt niet aangeraakt.
-
Verplaats de tijdelijke Knooppunt met de originele sleutel X5 met zijn kinderen naar de positie op rootniveau van het TreeView-besturingselement.
-
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.
-
Open het formulier frmSample om te zien hoe de TreeView-weergave eruitziet, met de voorbeeldtabelrecords, geladen volgens de oude regel.
-
Als u klaar bent met het bekijken van de TreeView-knooppunten, sluit dan het formulier.
-
Open nu de frmDragDrop Formulier. We bereiden ons voor om een Node te slepen en neer te zetten.
-
Selecteer de Node met de Node-Text Tabel, Klik en houd de linkermuisknop ingedrukt, sleep het naar de Node, met de Node-Text Form.
-
De Tabel Knooppunt met zijn onmiddellijke onderliggende knooppunt Velden en zijn onderliggende knooppunten worden verplaatst als onderliggende knooppunten onder het formulier Knooppunt.
-
Sluit het formulier frmDragDrop en open het weer. De Nodes zullen correct verschijnen waar je ze hebt neergezet, zoals in de onderstaande afbeelding.
-
Sluit nu het formulier frmDragDrop.
-
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.
-
Selecteer de opdrachtknop Debug om naar de gemarkeerde coderegel te gaan, waar de fout is opgetreden.
-
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.
-
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.
-
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
- MS-Access Class-module en VBA
- MS-Access VBA Class Object Arrays
- MS-Access-basisklasse en afgeleide objecten
- VBA Base Class and Derived Object-2
- Basisklasse en afgeleide objectvarianten
- MS-Access-recordset en klassenmodule
- Toegang tot klassenmodule en wrapperklassen
- Transformatie van functionaliteit van wrapperklasse