Oggi impariamo come usare un controllo treeview in Access.
Non è così semplice, perché il treeview è un controllo particolare. Non ha una origine controllo facilmente impostabile, come la casella di testo, o la casella combinata. Per popolare di valori il controllo treeview devo usare dei recordset.
Il recordset è un oggetto che mi consente di “mettere” in memoria i record presenti in una tabella o in una query (quindi un sottoinsieme di righe e forse anche un sottoinsieme di colonne della tabella originale, o anche campi provenienti da più tabelle).
I dati visibili su un controllo treeview sono chiaramente dati che hanno una relazione gerarchica tra loro, un po’ come la struttura ad albero delle cartelle nel nostro computer. Nel nostro esempio lavoreremo con i dati dei clienti e dei relativi ordini, che infatti sono in relazione uno-a-molti.
Partiamo con una maschera vuota in cui inseriamo un controllo treeview. Lo troviamo andando su controlli ActiveX
Nel lungo elenco selezioniamo Microsoft Treeview Control e poi Ok. Diamo nome al controllo “tv”.
Aggiungiamo un pulsante di comando “cmdCaricaTreeView”
Ora dobbiamo scrivere il codice che popolerà il controllo. Per farlo andiamo sull’evento Su clic del pulsante di comando, tasto destro, Genera, generatore di codice e arriviamo nella finestra dove scrivere il nostro VBA.
Iniziamo dichiarando una variabile di tipo MSComctlLib.Node. Sarà il nostro nodo, l’oggetto che di volta in volta conterrà i valori da visualizzare nel treeview.
Dim tempNode As MSComctlLib.Node
Ora le due variabili per i recordset dei clienti e degli ordini
Dim rsC As DAO.Recordset ' contiene i record dei clienti Dim rsO As DAO.Recordset ' contiene i record degli ordini
A questo punto una istruzione che svuota il controllo TreeView:
tv.Nodes.Clear ' svuota il controllo treeview
E ora creiamo il livello iniziale del nostro treeview, un po’ come se fosse il nostro C:\ in una struttura ad albero vecchia maniera
Set tempNode = tv.Nodes.Add(, , "C", "Clienti")
Uso il metodo Add per la collezione Nodes del controllo Treeview.
Questo metodo ha 4 argomenti:
- relative: serve per fare riferimento a un nodo già esistente
- relationship: specifica il tipo di relazione con il nodo già esistente
- key: chiave univoca che identifica il nodo
- text: il testo che l’utente visualizza nel treeview (obbligatorio)
Sarà più chiaro il loro utilizzo mano mano che scriveremo il codice.
Carico il recordset con l’elenco dei clienti
Set rsC = CurrentDb.OpenRecordset("SELECT IDCliente,NomeSocietà FROM tblClienti ORDER BY NomeSocietà", , dbReadOnly)
Qui ho preso tutti i clienti. Avrei potuto filtrare i clienti scegliendo solo quelli che hanno fatto ordini quest’anno o altro. L’istruzione SELECT appartiene al linguaggio SQL, quello utilizzato dalle query.
dbReadOnly ottimizza l’esecuzione dell’istruzione, perché sto dicendo ad Access che non farò modifiche in quei record e così il recordset sarà imn sola lettura.
Ora eseguo un loop e passerò in rassegna tutti i record che esistono nel recordset:
Do While Not rsC.EOF
Loop
Ossia: Fai finché non ti trovi alla fine (EOF) del recordset rsC e ripeti (loop)
Carico un nodo per ogni cliente trovato nel recordset:
Set tempNode = tv.Nodes.Add("C", tvwChild, "CL" & rsC.Fields("IDCliente"), rsC.Fields("NomeSocietà"))
- “C”:relative. Infatti questo record è relativo al nodo superiore, che prima abbiamo identificato con “C”
- tvwChild: relationship. questo nodo sarà figlio del precedente (il cliente appartiene ai Clienti)
- “CL” & rsC.Fields(“IDCliente”): key. chiave univoca del nodo (non può esistere un altro nodo con la stessa chiave)
- rsC.Fields(“NomeSocietà”): text. Ciò che vedrà l’utente
Ora per ciascuno cliente, se esistono, carico gli ordini.
Come prima cosa carico il recordset con l’elenco degli ordini
' carico gli ordini del cliente Set rsO = CurrentDb.OpenRecordset("SELECT IDOrdine as ChiaveOrdine,DataOrdine FROM tblOrdini WHERE IDCliente=""" & rsC.Fields("IDCliente") & """ ORDER BY DataOrdine DESC", , dbReadOnly)
Qui è necessario mettere una WHERe, ossia un filtro, e selezionare solo gli ordini del cliente su cui sono. Per questo motivo faccio riferimento a rsC.Fields(“IDCliente”).
E ora è tutto come prima: faccio un ciclo e creo un nodo con l’ordine:
Do While Not rsO.EOF Set tempNode = tv.Nodes.Add("CL" & rsC.Fields("IDCliente"), tvwChild, "O" & rsO.Fields("ChiaveOrdine"), rsO.Fields("DataOrdine")) rsO.MoveNext Loop
- “CL”:relative. Infatti questo record è relativo al nodo superiore, che prima abbiamo identificato con “CL”
- tvwChild: relationship. questo nodo sarà figlio del precedente (l’ordine appartiene al cliente)
- “O” & rsC.Fields(“IDOrdine”): key. chiave univoca del nodo (non può esistere un altro nodo con la stessa chiave)
- rsO.Fields(“DataOrdine”): text. Ciò che vedrà l’utente,. Ho scelto la data, poteva naturalmente essere qualunque altra informazione.
Ora chiudo il recordset
rsO.Close
Dopo la chiusura del primo Do (quello tra i clienti), chiudo il recordset rsC:
rsC.Close
Ultima istruzione: imposto il treeview con il primo nodo sempre espanso:
tv.Nodes.Item(1).Expanded = True
Riepilogando, il codice è il seguente:
Dim tempNode As MSComctlLib.Node Dim rsC As DAO.Recordset ' contiene i record dei clienti
Dim rsO As DAO.Recordset ' contiene i record degli ordini tv.Nodes.Clear ' svuota il controllo treeview Set tempNode = tv.Nodes.Add(, , "C", "Clienti") Set rsC = CurrentDb.OpenRecordset("SELECT IDCliente,NomeSocietà FROM tblClienti ORDER BY NomeSocietà", , dbReadOnly) Do While Not rsC.EOF Set tempNode = tv.Nodes.Add("C", tvwChild, "CL" & rsC.Fields("IDCliente"), rsC.Fields("NomeSocietà")) ' carico gli ordini del cliente Set rsO = CurrentDb.OpenRecordset("SELECT IDOrdine as ChiaveOrdine,DataOrdine FROM tblOrdini WHERE IDCliente=""" & rsC.Fields("IDcliente") & """ ORDER BY DataOrdine DESC", , dbReadOnly) Do While Not rsO.EOF Set tempNode = tv.Nodes.Add("CL" & rsC.Fields("IDCliente"), tvwChild, "O" & rsO.Fields("ChiaveOrdine"), rsO.Fields("DataOrdine")) rsO.MoveNext Loop rsO.Close rsC.MoveNext Loop rsC.Close tv.Nodes.Item(1).Expanded = True