Newsgroup: it.comp.appl.access
Titolo: Access TreeView

Mi interessava la costruzione in VBA.
Ce n'è molte in Google ma poi ognuno dà i nomi più diversi
a Parent e Child e nessun (meglio: io non ho trovato nessuno)
che dia un'indicazione precisa sul layout delle tabelle e
sulla rappresentazione dell'albero genealogico finale.
Qualcuno ha una cosetta piccola-piccola su cui rifarsi
l'occhio senza eccessivo impegno mentale?
 
Bruno

Non ho capito nulla.
Cosa ti serve... di preciso...?
Spiega semplice sai che io fatico se inizi ad andare troppo sul tecnico...
 
@Alex

 Spiega semplice sai che io fatico se inizi ad andare troppo sul tecnico...
 
Un esempio piccolo-piccolo di applicazione TreeView in VBA
che mostri come partendo da una tabellina corta-corta si
giunga all'alberello finale.
 
Mi sembrava di esser stato chiaro... debbo convincermi ad
inviare post la mattina presto, prima che inizi a bere.
 
Bruno

Intanto la tabella devono essere 2... semplifica sulla struttura più flessibile, potrebbe esserne usata anche solo 1 con il campo Padre, ma in quel caso un ITEM può essere figlio solo nei 1 padre... risulta molto limitata, ma fattibile.
 
Io uso sempre la.soluzione con 2 tabelle.
 
tblAnagrafica
IdAnagrafica(Pk)
IdTipo
Desxrizione
 
tblRelazione
IdAnagrafica(Pk)
IdAnagraficaParent(Pk)
Quantita 
 
Va da sé che nella tabella tblRelazione serve una SELFREFERENCE TABLE alla tabella tblAnagrafica_1
 
La tabella tblRelazione rappresenta la ricetta ottenuta per gerarchia.
 
Questa struttura consente di poter creare ITEM con Figli che possono essere a loro volta ITEM di Items.
 
Questa è la.struttura più flessibile in assoluto.
 
Pensa a ricette di cucina in cui hai(idTipo):
RICETTE FINITE
RICETTE SEMILAVORATE
ELEMENTI BASE
 
Questi 3(n) tipi di Anagrafica finiscono sempre nella tblAnagrafica mentre la ricetta sarà indicata dalla tblRelazione.
È evidente che ogni oggetto della tabella anagrafica può essere relazionato come sottooggetto di un'altro oggetto.
 
La proprietà IdTipo però è quella che si usa per estrarre le RICETTE FINITE.
Da lì si cerca nella tabella tblRelazione quali items ci sono con IdAnagraficaParent=RICETTA  FINITA.... e qui inizia la logica ricorsiva in qua to ogni IDANAGRAFICA figlio di IDANAGRAFICAPARENT potrebbe a sua volta avere figli... che saranno sempre contenuti nella tblRelazione...
 
Il Treeview di fatto è una classe ricorsiva sull'oggetto Nodo a sua volta elemento della collection Nodes...
 
Quindi se si costruisce la funzione VBA che esplora in modo gerarchico la tblRelazione in automatico si va a popolare l'oggetto gerarchico del Treeview... nel senso che se un item ha figli si  inseriscono i nodi figlio...
 
Oggi non ho pc comodo... ma se riesco domani ti mostro le 10 righe di codice ricorsiva per popolare il treeview...
 
Intanto questi 2 link danno qualche spunto utilr:
https://access-programmers.co.uk/forums/showthread.php?t=277829
 
 
https://www.experts-exchange.com/questions/20988029/Recursive-treeview-function.html
 
 
Saluti
@Alex

Ti mostro un esempio veloce e semplice della struttura semplificata, ovvero con una sola Tabella che consente la gerarchia a N livelli.
 
Quindi la struttura delle Tabelle prevede 1 Tabella Principale de una Tabella GErarchica:
 
Tabella Princilape che identifica un PROGETTO:
[tProgetti]
CAMPI:
IdProgetto (PK Counter)
Titolo (Testo Breve)
... altri campi non utili
 
Tabella Gerarchica che identifica FASI di LAVORO del PROGETTO, ongni Fase può avere SOTTOFASI(n) non finite.
 
[tPhases]
CAMPI:
IdProgetto (FK Intero Lungo)
IdPhaseParent (FK Intero Lungo)
IdPhase (PK Counter)
NomeFase (Testo)
 
La tabella [tProgetti] è in relazione 1-M con la tabella [tPhases].
La tabella [tPhases] ha una SELFREFERENCE_TABLE [tPhases_1] sul campo 
 
[tPhases_1](IdPhase)[1]<----->[M](IdPhaseParent)[tPhases]
 
Il Legame(JOIN) è di tipo [3]
 
La Maschera principale è basata sulla Tabella [tProgetti], sicchè ho i Controlli  associati ai campi [IdProgetto] e [Titolo]
Sono 2 TextBox con il NomeControllo=NomeCampo
Il Controllo TreeView si chiama [cTW]
 
Nella Form ho questo codice sotto...
La funzione LoadTree() carica il NOME del PROGETTO come ROOT, poi inizia a caricare i Records della Tabella [tPhases] che NON HANNO Padre, ovvero tutti i Records a LIVELLO=0.
La funzione come vedi nel LOOP, chiama la Funzione(Ricorsiva), passando il NODO che contiene la PK nella proprietà TAG del Nodo.
 
AddChildren sKey, ndP
 
Questa seconda Funzione carica i Records con IdPhaseParent=Nodo.tag, ovvero tutt i Records che hanno come Padre il nodo di LIVELLO(N-1)
Qusta funzione a sua volta nel LOOP esplora se il Record ha dei SottoRecords richiamando se setssa..., questa è la RICORSIONE.
 
Questo il codice(ho tolto dei pezzi non necessari, spero di non aver tolto troppo):
---------------------------------------------------------------------------------
Option Compare Database
Option Explicit
 
Private Const mcProcParent      As String = "Form_Progetto"
Private Const mMnuName          As String = "mPopupRuntime"
 
Private mT                      As MSComctlLib.TreeView
Private mND                     As MSComctlLib.node
Private mItem                   As String
 
Private Sub Form_Load()
 
    Set mT = Me.cTW.Object
 
mT.Font.Name
 = "Calibri"
 
    Call LoadTree
    Me.cTW.Visible = True
 
End Sub
 
 
Public Sub LoadTree()
    Const mcProcName = "LoadTree"
    On Error GoTo Err_Handler
 
    Dim rs          As DAO.Recordset
    Dim rsI         As DAO.Recordset
    Dim sKey        As String
    Dim ssKEY       As String
    Dim sSQL        As String
    Dim ndP         As MSComctlLib.node
    Dim ndC         As MSComctlLib.node
    Dim ndRoot      As MSComctlLib.node
 
    Set mT = Me.cTW.Object
    mT.Nodes.Clear
 
    Set ndRoot = mT.Nodes.Add(, , "P-" & Me.IdProgetto, Me.Titolo, 1)
 
    sSQL = "SELECT * FROM tPhases WHERE IdProgetto=" & Me.IdProgetto & " AND IdPhaseParent Is Null ORDER BY IdPhase;"
 
    Set rs = DBEngine(0)(0).OpenRecordset(sSQL, dbOpenDynaset, dbReadOnly)
    If rs.EOF = False Then
        rs.MoveFirst
        Do Until rs.EOF
            sKey = UniqueKey
 
            Set ndP = mT.Nodes.Add("P-" & Me.IdProgetto, tvwChild)
 
            ndP.Key = sKey
            ndP.Text = rs.Fields("NomeFase").Value
            ndP.Image = 2
            ndP.Tag = rs.Fields("IdPhase").Value
            'add sub levels
            AddChildren sKey, ndP
 
            rs.MoveNext
        Loop
 
    End If
 
Exit_Here:
 
    On Error Resume Next
    ndRoot.Expanded = True
    If Not rs Is Nothing Then rs.Close:    Set rs = Nothing
    Set ndP = Nothing
    Set ndRoot = Nothing
 
    Err.Clear
    Exit Sub
 
Err_Handler:
    Select Case Err.Number
        Case Else
            MsgBox Err.Number & " in " & mcProcParent & vbNewLine & Err.Description, vbCritical, mcProcName
    End Select
    Resume Exit_Here
 
End Sub
 
Sub AddChildren(ByVal Parent_Key As String, Optional mNode As MSComctlLib.node)
    Const mcProcName = "AddChildren"
    On Error GoTo Err_Handler
 
    Dim rsC             As DAO.Recordset
    Dim sSQL            As String
    Dim sKey            As String
    Dim nd              As MSComctlLib.node
 
    sSQL = "SELECT * FROM tPhases WHERE IdProgetto=" & Me.IdProgetto & " AND  IdPhaseParent = " & mNode.Tag & " ORDER BY IdPhase"
    Set rsC = DBEngine(0)(0).OpenRecordset(sSQL, dbOpenDynaset, dbReadOnly)
    If rsC.RecordCount > 0 Then
        With rsC
            .MoveFirst
            Do While .EOF = False
                sKey = UniqueKey
 
                Set nd = cTW.Nodes.Add(Parent_Key, tvwChild)
                nd.Key = sKey
                nd.Text = .Fields("NomeFase").Value
                nd.Image = 4
                nd.Tag = .Fields("IdPhase").Value
 
                AddChildren sKey, nd
 
                Set nd = Nothing
 
                .MoveNext
            Loop
        End With
    End If
 
Exit_Here:
 
    On Error Resume Next
    If Not rsC Is Nothing Then rsC.Close:    Set rsC = Nothing
 
    Err.Clear
    Exit Sub
 
Err_Handler:
    Select Case Err.Number
        Case Else
            MsgBox Err.Number & " in " & mcProcParent & vbNewLine & Err.Description, vbCritical, mcProcName
    End Select
    Resume Exit_Here
 
End Sub
 
Public Function UniqueKey() As String
'***************************************************************************
'Purpose: Generate a unique key for a Treeview. Actually there is a one in
'         10 million chance of the key *not* being unique, but the error
'         handling code in the calling Sub takes care of that.
'Inputs : None
'Outputs: The key for the Treeview
'***************************************************************************
 
    UniqueKey = "K" & 1 + Int(Rnd() * 10000000)
 
End Function
 
Secondo me questo è un Esempio abbastanza banale e semplice.
Se vuoi applicare il concetto alla evoluzione con le 2 Tabelle, la logica è esattamente la stessa...
 
Ciao
@Alex

 [...]
Per me hai tolto troppo poco.
Per il momento grazie, ci guarderò con calma e riferirò.
 
Ti mando il completamento di quanto già inviato ad Alfio
(Ricostruzione Albero Categorie del 11-05-19).
https://1drv.ms/u/s!AvTaMfd5-b2oxB0LAwhKiz-oOonD
 
 
Puoi cambiare StartParent in sub CFG().
Non mi piace per niente il ricorso a CatTree() e NumCat
definite in Root del Modulo, per la compilazione della
tabella destinazione (Categorie_Tree)... ma non ho trovato
nulla di meglio.
Hai qualche idea migliore?
 
Bruno

 Bruno
 
@Alex
 
 

 controlli nella sezione si sposta a DX in base al livello stesso:
 
Meno chiacchiere, fammi vedere un fior del tuo giardino, fammi
vedere un report.
Ho bisogno di vedere un risultato, te l'ho già chiesto alla prima
domanda che m'hai fatto.
Diversamente non riesco a comprendere l'utilià delle tue
considerazioni.
 
Mandamelo stampato, non dirmi come si deve fare per crearlo.
 
Bruno

 Bruno
 
@Alex

"..Mandamelo stampato, .."
 
 
Anvedi, sei un ardito
Che hai fatto servizio nelli Alpini ?


Io si...! Battaglione Tridentina.
 
@Alex

 Che hai fatto servizio nelli Alpini ?
 
No, figlio maggiore che ha perso anche l'ultimo genitore.
Se rinasco un'altra volta vado volontario in fanteria.
 
Bruno


Non so se ti può essere utile, io mi sono trovata molto bene seguendo la guida pubblicata da karl su 
http://www.donkarl.com/it/CISA/Download.htm
 

 guida pubblicata da karl su 
http://www.donkarl.com/it/CISA/Download.htm
 
 
Ti ringrazio.
Vi ho dato una scorsa veloce e mi sembra ben fatto.
È un bel giochino non c'è dubbio anche se mancano
(dovrei dire non ho visto?) alcune cosette tipo la
costruzione di un un report decente e, dato un child,
la possibilità di evidenziare la sua ascendenza/discendenza.
Correggimi se sbaglio.
 
Tu lo usi per qualche utilità pratica?
 
Bruno


Di solito lo utilizzo per facilitare i filtri durante le interrogazioni; cerco di essere più chiara con un esempio... Interrogazioni anagrafe articoli prendiamo ad esempio categoria e sottocategoria 
Nel Treeview a livello 1 carico le categorie, a livello 2 le sottocategorie 
Quando l'utente clicca su un nodo applico il filtro.
Normalmente aggiungo anche un pulsante che permette di ricaricare l'albero con le caratteristiche scelte dall'utente da un elenco preimpostato.
Come metodo è molto semplice e anche di facile utilizzo
 
Gabriella


www.accessgroup.it
 esempio di treeview ricorsivo
MA