Access
 sql >> Base de Dados >  >> RDS >> Access

Reorganizar nós TreeView por arrastar e soltar

Introdução.


Espero que você tenha achado o tutorial da semana passada sobre o ImageCombo Control útil para seus projetos do Microsoft Access. Com o controle TreeView ImageCombo, poderíamos criar um belo menu suspenso, com várias opções, e acomodá-lo em um pequeno espaço no formulário.

Da mesma forma, em uma sessão anterior, aprendemos como adicionar novos nós em um local específico na hierarquia de nós ou excluir um nó e adicionar um novo para realocar um nó no controle de exibição de árvore.

Este método solicita a criação de um novo registro na tabela de origem para o novo nó. Ou exclua um registro existente e crie um novo para mover um nó existente e torná-lo permanente. De certa forma, com o uso das Funções Add/Delete, poderíamos adicionar novos Nodes ou reorganizar os Nodes existentes no TreeView Control. No que diz respeito à reorganização dos nós, temos uma maneira melhor de fazer isso, em vez de excluir os nós e recriá-los. Arraste o nó de sua localização atual e solte-o onde queremos que esteja no controle TreeView. É isso que vamos aprender neste episódio

Essa abordagem simples precisa apenas atualizar a alteração do valor do campo ParentID dos registros relacionados, para tornar a alteração permanente.

Os tópicos abordados até agora nas sessões anteriores.

  1. Tutorial de controle do Microsoft TreeView
  2. Criando menu de acesso com controle TreeView
  3. Atribuindo imagens ao controle TreeView
  4. Atribuindo imagens ao TreeView Control-2
  5. Marque de seleção de controle do TreeView Adicionar nós de exclusão
  6. Menu de acesso suspenso do TreeView ImageCombo

Mas, podemos enfrentar alguns desafios ao usar este método e chegaremos a isso um pouco mais tarde nesta Sessão.

Tabela e formulário de dados de demonstração.


Precisamos de uma Tabela e um Formulário. Já temos uma tabela adequada com o nome Amostra criado em uma sessão de tutorial anterior. Se você já baixou o banco de dados de demonstração, a partir do segundo link da página acima, você também pode usar esse banco de dados para esta sessão. Usaremos os seguintes objetos desse banco de dados para nossos experimentos de arrastar e soltar:
  • Tabela:Amostra
  • Formulário:frmSample

A imagem de controle TreeView em frmSample com dados de demonstração é fornecida abaixo para referência:

Você pode baixar o banco de dados de demonstração (ProjectMenu.zip ) da página do segundo link fornecida acima e extraia o ProjectMenu.accdb base de dados.

Novo formulário para execuções de teste de arrastar e soltar.


  1. Abra o banco de dados ProjectMenu.accdb.

  2. Faça uma cópia da tabela Amostra e nomeie-o como Sample_bk, mantê-lo seguro, precisaremos de seus dados originais sem alterações posteriores. Quando experimentamos o método arrastar e soltar, é necessário atualizar o valor do campo ParentId na Tabela de demonstração de amostra. Mas, precisamos dos dados originais mais tarde, sem essas alterações.

  3. Crie um novo formulário com o nome frmDragDrop .

  4. O design do formulário frmDragDrop se parecerá com a imagem abaixo quando você terminar com ele.

  5. Insira o controle TreeView da lista de controles ActiveX e coloque-o no formulário, deixando espaço suficiente acima do controle, para que possamos criar dois botões de comando e um rótulo de título acima dele. Arraste a alça de dimensionamento no canto inferior direito para torná-la grande o suficiente para exibir todos os nós, sem rolar.

  6. Altere o Nome Valor da propriedade do controle TreeView para TreeView0 .

  7. Insira um botão de comando acima e na borda esquerda do controle TreeView. Altere seu Nome Valor da propriedade para cmdExpand e Legenda valor para Expandir tudo .
  8. Insira um segundo botão de comando acima e na borda direita do controle TreeView. Altere seu Nome Valor da propriedade para cmdCollapse e a Legenda Valor da propriedade para Recolher tudo.

  9. Insira um controle de rótulo acima dos botões de comando, largo o suficiente para escrever o título como mostrado acima, e altere o tamanho da fonte 14.

  10. Ignore o controle ImageList, por enquanto, eu comentei as linhas de código que modificam os números de índice do Node ImageList. Mais tarde, você pode importar o controle ImageList com imagens carregadas manualmente, de nosso banco de dados de demonstração do tutorial anterior (da 4ª página de link fornecida acima) e usá-lo para exibir imagens de nós em nós. Quando as posições do nó são alteradas durante as ações de arrastar e soltar, precisamos alterar as imagens do nó também dependendo da posição do nó (nó no nível raiz ou nó filho) no controle TreeView.

    Código do módulo de formulário de arrastar e soltar.




  11. Exiba o módulo de código VBA do formulário frmDragDrop, copie e cole o seguinte código VBA (esta é apenas a primeira metade do código do módulo de formulário) no módulo de classe do formulário frmDragDrop e salve o formulário:
    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

    Eu sei que você está familiarizado com o código acima, se você já passou pelos episódios anteriores, exceto o LoadTreeView() sub-rotina com algumas alterações. Aqui, o preenchimento dos nós TreeView foi dividido em um processo de duas etapas.

    Resumidamente, é isso que acontece nesta Sub-rotina.
    • Todos os registros no Amostra A tabela foi carregada como nós de nível raiz do controle TreeView, com um valor de campo de ID como chave, na primeira etapa.

    • Novamente, esses registros foram lidos uma segunda vez e verificamos um valor no ParentId campo, se estiver vazio, o Nó será retido como Nó de nível raiz.

    • Se o campo ParentID tiver um valor, identifique o nó com o valor ParentID como Node-Key e mova o Nó atual como seu Nó Filho, ou seu [Relativo] Parâmetro (de Adicionar () Método) valor é atualizado.


    • Embora pareça que o procedimento de preenchimento de nó em duas etapas seja um exercício desnecessário, há uma boa razão para seguirmos esse método. Voltaremos a isso um pouco mais tarde e você saberá sem muita explicação.

    • No design do formulário, dei um controle ImageList. Você pode inserir o Controle ActiveX ImageList e carregue algumas imagens nele manualmente a partir do disco, ou copie e cole este controle com imagens de downloads de banco de dados de demonstração anteriores. Em ambos os casos, certifique-se de que o nome do controle ImageList seja ImageList1 . Caso contrário, você precisa alterar o nome no Código.

    • Depois disso, habilite as linhas comentadas em Form_Open() Event Procedure. Habilite as seguintes linhas, removendo o símbolo de comentário do início da linha:
      'Set imgListObj = Me.ImageList1.Object
      'tv.ImageList = imgListObj
      



    • No TreeView0_ OLEDragDrop() A Sub-rotina (na 2ª parte do Código VBA) habilita os Parâmetros de Índice de Imagem dos Nós, removendo também os símbolos de Comentário dessas linhas. Com essas alterações, as imagens do nó aparecerão no controle TreeView. Se você tiver um controle ImageList próprio com imagens carregadas, altere os números de índice com base em qual imagem você gostaria de inserir nos nós.

      O TreeView0_NodeClick() Procedimento de evento Expande o nó atual, se os nós filhos estiverem em um estado recolhido, caso contrário, os nós filhos serão recolhidos. Normalmente esta ação é controlada (sem código) clicando no botão +/- Símbolo na linha de árvore do nó com nós filhos.

      As sub-rotinas cmdExpand_Click() e cmdCollapse_Click() Eventos Expande todos os nós e recolhe todos os nós respectivamente.

      Quando o código acima é executado, a exibição se parece com a imagem de exibição de formulário fornecida abaixo:



    • Você pode salvar o frmDragDrop Form e abra-o em Normal View. Se tudo correu bem, então você verá a tela acima. Experimente o Expandir tudo e Recolher tudo Botões de Comando e verifique se eles estão funcionando também. Caso contrário, verifique novamente se as seguintes configurações estão corretas ou não:

    • i) O nome do controle TreeView é:TreeView0

    • ii) Exibir a folha de propriedades de Examar tudo Botão de comando e selecione [Procedimento de evento] no Ao clicar Propriedade do evento.

    • iii) Certifique-se de que a mesma configuração esteja intacta para Recolher tudo Botão de comando também.

    • iv) Clique em um Node, com Nodes Filhos, para ver se eles são recolhidos ou expandidos em cliques repetidos.

    • v) Se o ImageList Control for colocado no formulário, seu nome deverá ser ImageList1 .

      Vamos prosseguir com a segunda parte do código VBA que implementa os eventos de arrastar e soltar.

    Segunda metade do código VBA.




  12. Copie a seguinte segunda parte do código VBA, no módulo de formulário frmDragDrop, que implementa a ação Drag-Drop, e cole-a abaixo do 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 a ação Drag-Drop, existem quatro sub-rotinas, elas são executadas automaticamente quando você arrasta o(s) nó(s), destaca o nó quando movido sobre outros nós e finalmente o solta em um nó diferente ou na área vazia no nível da raiz .

As principais sub-rotinas do código.

  • TreeView0_OLEStartDrag() - Inicializa o item selecionado e define o Node como Nothing
  • TreeView0_OLEDragOver() - Funciona como o Mouse Move Event, destaca o Node, quando arrasta um Node acima dele, a caminho do Target Node.
  • TreeView0_OLEDragDrop() – Executa verificações e controles, posiciona os nós no local descartado e atualiza o registro na tabela base.
  • TreeView0_OLECompleteDrag() - A propriedade DropHighlight está definida como Nothing.

Podemos fazer os trabalhos de arrastar e soltar com o TreeView0_OLEDragDrop() Sub-rotina sozinha. Nesse caso, não haverá nenhum destaque de nó, quando o nó de origem se mover sobre outros nós, de um local para outro, exceto que o ponteiro do mouse muda para arrastar uma segunda seta atrás dele, como na imagem de exemplo fornecida abaixo :

Então, vamos ficar atentos a esta sub-rotina e verificar o Código em detalhes desde o início. No início da sub-rotina, declaramos os Nós e Variáveis ​​String necessários, entre outros.

Em vez de repetir análises linha por linha aqui, comentei cada linha/seção de códigos adequadamente para que você entenda o que ela faz quando você passa pelo Código. Você pode passar por eles.

A Sequência de Eventos de Drops


Vamos entender a sequência de Eventos, o Usuário Seleciona um Node, Arrasta sobre outros Nodes no caminho para seu destino final e Drops no nó de destino. Ou Solte-o na área vazia no TreeView Control, para torná-lo um nó de nível raiz.

Quando você arrasta um Node sobre outro Node-Text, o Node-Text fica destacado, dizendo que sua posição atual está neste Node no caminho, para onde quer que você vá. Quando movido para fora do Node-text, o realce desaparece. Isso acontece até o nó de destino. O TreeView0_OLEDragOver() A subrotina cuida dessa ação de destaque.

Quando você solta um nó em algum lugar, o TreeView0_OLEDragDrop() A sub-rotina é sobrecarregada. Aqui, temos que analisar as intenções do Usuário e tomar as medidas adequadas. As informações a seguir devem ser salvas e analisadas para mover o Node para o local correto.

As informações importantes para acompanhar.


  1. A Referência do Nó de Origem, Chave do Nó e Valores ParentID, Nó Filhos, se houver.

  2. O Nó de Destino ou Referência de Local, Chave do Nó.

  3. Se o destino não for um nó, mas a área vazia do controle TreeView, o nó de origem será movido para a posição no nível da raiz.

  4. O Nó de Origem quando descartado em outro Nó, o Nó de Destino se torna o novo Pai do Nó de Origem.

  5. Se o Nó de Origem tiver seus próprios filhos, eles também deverão ser movidos com seu Pai.

  6. ** Quando o Nó é arrastado e solto em seu próprio Nó-Pai, Ignore esta ação.

    ** Por exemplo, verifique a imagem acima. Se arrastarmos o TextBox Node e solte-o em seu nó pai Controles, ou arrasta os Controles Node e solte-o em seu Formulário do Nó Pai então esses movimentos serão ignorados.



  7. ** Se no nível da raiz O nó é arrastado e solto na área vazia, então nenhuma ação será tomada porque já é um nó de nível raiz.

Para todos os movimentos válidos do Node, precisamos atualizar o ParentID valor do campo do registro relacionado na Amostra Tabela.

Node Drop na área vazia no nível da raiz.


No caso do item número 3 acima, temos que criar um Nó de nível Raiz, com o mesmo Número de ID do Nó de Origem, o que não é permitido. O valor de chave duplicado não é permitido na hierarquia TreeView. Esta é a única área do Código, onde você achará um pouco confuso sobre o procedimento seguido lá.

O procedimento é dado abaixo:

  1. Modifique a chave do nó TreeView existente com a adição de algum texto extra, (digamos Chave X5 alterar para X5Vazio ), para evitar conflitos de chave, ao criar um nó temporário com a chave original.

  2. Crie um temporário Nó com a chave original:X5.

  3. Mova todos os nós filhos do nó de origem, se houver, como nós filhos para o nó temporário.

  4. Exclua o nó de origem TreeView com a chave modificada:X5Empty do controle TreeView, mas o registro relacionado na tabela Sample não é tocado.

  5. Mova o temporário Nó com a chave original X5 com seus filhos para a posição de nível raiz do controle TreeView.

  6. Atualize o campo ParentID do registro relacionado com uma string de comprimento zero (“”) para marcá-lo como um nó de nível raiz.

Autoexperiências de arrastar e soltar.


Você pode experimentar alguns experimentos de arrastar e soltar e ver como funciona. Selecione um Node, clique e segure o botão esquerdo do mouse, arraste o Node e solte-o em outro Node, ou solte-o em uma área vazia do TreeView Control. Quando você arrasta o Node sobre outro Node-Text ele é realçado e quando você está fora do Node o realce se apaga. O nó arrastado aparecerá no novo local onde você o soltou. Você pode repetir este experimento de arrastar e soltar selecionando um único Nó ou Nó com Filhos.

Com base nesse movimento de nós, o ParentID do registro relacionado o valor do campo será atualizado com a Chave valor (ID) do registro relacionado ao Nó de Destino.

Por que o procedimento de preenchimento de nós em duas etapas?


Agora, vamos voltar para o LoadTreeView() Sub-rotina, para dar uma segunda olhada no processo de duas etapas que adotamos para preencher todos os nós para o controle TreeView.

  • Todos os registros na Amostra As tabelas são inicialmente adicionadas como nós de nível raiz, usando o valor do campo ID como chave de nó.

  • Na segunda passagem dos registros, se o valor do campo ParentID estiver vazio, esse Nó permanecerá como Nó de nível raiz, sem alteração.

  • Todos os outros registros relacionados a nós com valor ParentID são movidos corretamente em seu nó pai.

Naturalmente, surge a pergunta:por que temos que fazer dessa maneira?

Faremos um experimento simples para tornar a resposta clara sem explicá-la em muitas palavras. Você pode já ter feito algumas execuções de teste de arrastar e soltar execuções de teste e reorganizar os nós, no processo atualizou os valores de ParentID desses registros com a alteração. Portanto, precisamos redefinir os valores do registro para seu estado original na Amostra Table, antes de iniciarmos uma nova demonstração.

Já criamos uma cópia da nossa tabela amostra anteriormente, com o nome Sample_bk como backup. Exclua a amostra Tabela e faça uma cópia de Sample_bk com o nome original:Amostra .

Abra a Tabela e visualize os registros e seus valores do campo ParentID. A imagem de exemplo da tabela é fornecida abaixo:

Os valores do campo de ID são AutoNumeração e estão todos em ordem sequencial e todos os valores de ID são exclusivos. A regra simples a seguir rege a adição de um nó filho ao controle TreeView.

A regra do nó filho simples: O ParentID Valor do campo (Chave-pai ) em um registro espera que um nó pai já exista no controle TreeView, com o mesmo valor que Node-Key (o ID).

Verifique o terceiro registro a partir do topo, na Imagem da Tabela acima. O valor do campo ParentID é 2 e o ID do registro atual é 3. Nesse caso, o registro com ID 2 será adicionado ao TreeView Control antes de tentarmos adicionar o terceiro registro ao Node. Ambos os registros não estão necessariamente próximos um do outro. Verifique o registro com o número de ID 21, seu valor de campo ParentID é 12, menor que o valor de ID de registro atual 21.

Em ambos os casos, quando o programa encontra o valor ParentID em um registro, ele assume que o registro com o valor ID igual ao ParentID já foi adicionado como um nó no controle TreeView no ciclo anterior de preenchimento dos nós.

Justificando o procedimento de duas etapas.


Vamos tentar algumas execuções de teste de arrastar e soltar. Mas, antes disso, temos um Form com o nome frmSample, que que usamos na primeira Sessão de Tutorial, e nela carregamos todos os nós TreeView de uma só vez. Sim, seguimos o mesmo método até agora e precisamos de algumas mudanças a partir de agora. Mas antes vamos abrir o formulário antigo e ver como os Nodes aparecem no Form.

  1. Abra o formulário frmSample para ver como a exibição TreeView se parece, com os registros da tabela de amostra, carregados usando a regra antiga.

  2. Se você terminou de visualizar os nós TreeView, feche o Form.

  3. Agora, abra o frmDragDrop Forma. Estamos nos preparando para arrastar e soltar um aplicativo Node.

  4. Selecione o Nó com a Tabela de Texto Nó, Clique e segure o botão esquerdo do mouse, arraste e solte no Node, com o Node-Text Formulário.

  5. A Tabela Nó com seus Campos imediatos de Nó-filho e seus nós filhos são movidos como nós filhos no formulário Nó.

  6. Feche o formulário frmDragDrop e abri-lo novamente. Os Nodes aparecerão corretamente, onde você os soltou, como na imagem abaixo.

  7. Agora, feche o formulário frmDragDrop.

  8. Abra o formulário frmSample para ver como essa alteração aparece neste formulário. Você será recebido com uma mensagem de erro, Elemento não encontrado com Número do erro:35601.

  9. Selecione o botão de comando de depuração para ir para a linha de código realçada, onde ocorreu o erro.

  10. Aponte o mouse sobre a nodKey Param do método Add(), mostra X3, ponto o mouse na ParentKey parâmetro e mostra X7.

    Observando esses dois valores de parâmetros, podemos supor que estamos no registro com o valor de ID 3 e tentando designar este Node como um Node filho, para outro Node ainda não preenchido no TreeView Control, com o valor de ID 7.



  11. Pressione F5 Tecle para abrir a mesma caixa de diálogo novamente e clique no botão Encerrar Botão de comando para parar o programa e abrir o formulário na janela do banco de dados. Feche o formulário frmSample.

  12. Abra a Amostra Tabela para visualizar a disposição dos Números ParentID, após nossa ação de arrastar e soltar. Os registros serão parecidos com a imagem abaixo e destaquei o registro que acionou o erro com o valor ParentID 7 e mostrando a posição do registro pai.

Seguindo o procedimento normal de preenchimento de Node anterior, estamos na terceira posição de registro. Uma vez que, os registros ParentID valor 7, o Nod com valor ID 7 deve estar presente no controle TreeView. O nó com valor de ID 7 ainda não está preenchido no TreeView Control, mas estamos tentando fazer referência ao Node inexistente e isso aciona um Error.

Mesmo se você classificar os registros na ordem do campo ParentID, o novo arranjo dos registros será semelhante à imagem abaixo:

Agora, o nó pai de outro registro não está na posição esperada.

Portanto, nessas circunstâncias, nossa abordagem de carregamento de nós TreeView em duas etapas também funciona para ações normais e após arrastar e soltar.

Na primeira etapa, preencha todos os registros como nós de nível raiz no controle TreeView usando o valor do campo ID como Node-Key.

Agora, todos os Nodes de todos os registros estão disponíveis no TreeView Control. Será fácil movê-los para onde quisermos. Não diz que nenhum nó necessário não existe no TreeView.

Na segunda passagem no mesmo conjunto de registros, os registros com valores de campo ParentID vazios são intocados e podem permanecer como nós de nível raiz. Em outros casos, move o Node como Child-Node sob seu Pai Node, atualizando o [Relative] Parâmetro do Node com a seguinte instrução:
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 posição. 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 classe MS-Access e VBA
  2. Matrizes de objetos de classe VBA do MS-Access
  3. Classe base do MS-Access e objetos derivados
  4. VBA Base Class and Derived Object-2
  5. Classe base e variantes de objetos derivados
  6. Conjunto de registros e módulo de classe do MS-Access
  7. Módulo de classe de acesso e classes wrapper
  8. Transformação da funcionalidade da classe wrapper