Esempio N.1
Utilizzando il controllo Data è possibile eseguire le
operazioni più comuni scrivendo solo poche righe di codice (al limite nessuna).
Vediamo un esempio pratico: nella finestra di progettazione creiamo un nuovo progetto, chiamiamo
il Form Esempio1, scegliamo come font Arial 9 (per schermo 800x600), inseriamo un Frame a cui diamo come Caption "record corrente" (questo è solo per scopi estetici) e inseriamo nel Frame un controllo Data.
Gli diamo come Caption "Rubrica" (è più estetico di Data1), in Databasename
scegliamo il file Rubrica.mdb, modifichiamo Exclusive in True (per abituarci a pensare
che potremmo non essere l'unico utente che accede al Db), modifichiamo il tipo da Dynaset
a Table e scegliamo la tabella Rubrica.
Aggiungiamo, sempre nel Frame, un controllo Text e gli assegnamo come DataSource Data1,
poi scegliamo come DataField il primo, Cognome. Copiamo poi Text1, confermando che
vogliamo creare una matrice di controlli, tante volte quanto è necessario
modificando ogni volta il DataField, la lunghezza della casella e la proprietà
MaxLength per i vari campi.
Oltre che più comodo creare istanze multiple di un controllo è anche
una buona abitudine di programmazione, in quanto in questo modo si utilizzano meno
risorse del Sistema.
Aggiungiamo poi delle Label per dire che campi sono ed il nostro programma è
pronto; consente di scorrere la tabella Rubrica e modificare il contenuto dei records
presenti: infatti se modifichiamo il contenuto di uno o più dei campi Text
automaticamente modificheremo il Database.
Ma se modificheremo un record e poi terminiamo il programma senza spostarci
di record tramite il controllo Data vedremo la volta dopo che le ultime
modifiche si sono perse: infatti le modifiche vengono scritte sul Db quando
ci si sposta ad un altro record. Dovremo quindi rimediare aggiungendo del
codice: clicchiamo Form, scegliamo Unload ed aggiungiamo
Private Sub Form_Unload(Cancel As Integer) Data1.Recordset.MoveLast End Sub |
Così il primo problema è risolto.
Ma ne abbiamo un altro: in Databasename del controllo Data c'è un indirizzo assoluto
(nel mio caso "D:\Programmi\Vb98\Esempi\Database\Rubrica.mdb"), mentre
normalmente si vuole che Db e Programma stiano nella stessa Cartella;
inoltre Rubrica ha un indice per Cognome, Nome chiamato Rubrica e
vogliamo che i record compaiano in ordine. Aggiungiamo altro codice,
questa volta in Form_Laod
Private Sub Form_Load() Data1.DatabaseName = App.Path & "\Rubrica.mdb" Data1.RecordSource = "Rubrica" Data1.Refresh ' Impostiamo l'indice da usare (Cognome, Nome) Data1.Recordset.Index = "Rubrica" End Sub |
Visto che è necessario anche inserire nuovi record (la prima volta il Db è vuoto ed il programma non servirebbe a nulla) ed è utile potere anche cancellare inseriamo due Bottoni ed aggiungiamo una Label per avvertire se non ci sono record; il Form avrà questo aspetto:
Private Sub Command1_Click(Index As Integer) If Index = 0 Then ' Cancella record corrente Data1.Recordset.Delete Data1.Recordset.MoveNext If Data1.Recordset.RecordCount = 0 Then ' non ci sono più record Label2.Visible = True Command1(0).Enabled = False End If Exit Sub End If If Index = 1 Then ' Inserisci un record vuoto Data1.Recordset.AddNew Data1.Recordset("Cognome") = " " Data1.Recordset.Update ' fa divenire record corrente quello aggiunto Data1.Recordset.Bookmark = Data1.Recordset.LastModified ' abilita tasto DELETE perché c'è almeno 1 record Command1(0).Enabled = True Label2.Visible = False ' seleziona il blank del Cognome Text1(0).SelStart = 0 Text1(0).SelLength = Len(Text1(0).Text) Text1(0).SetFocus Exit Sub End If End Sub Private Sub Form_Load() Data1.DatabaseName = App.Path & "\Rubrica.mdb" Data1.RecordSource = "Rubrica" Data1.Refresh ' Impostiamo l'indice da usare (Cognome, Nome) Data1.Recordset.Index = "Rubrica" If Data1.Recordset.RecordCount > 0 Then ' altrimenti se Rubrica è vuoto da un errore Data1.Recordset.MoveFirst ' abilita tasto DELETE Command1(0).Enabled = True Else Label2.Visible = True End If End Sub Private Sub Form_Unload(Cancel As Integer) If Data1.Recordset.RecordCount > 0 Then ' se non si sposta il puntatore di record ' dopo avere variato i campi ' l'aggiornamento non viene effettuato Data1.Recordset.MoveLast End If End Sub |
Il nostro programmino comincia ad essere abbastanza a posto; lo proviamo, funziona tutto, etc. Ma l'appetito vien mangiando e lo vogliamo rendere più completo: farebbe comodo vedere in una lista tutti i records e poter scegliere quello voluto e posizionarlo come record corrente.
Per fare questo ci serve un nuovo controllo, il DbList, che non è tra quelli di default.
Per aggiungerlo clicchiamo Progetto, Componenti, cerchiamo nella lista Microsoft Data bound List Control, lo spuntiamo e clicchiamo OK.
Questo controllo si presenta come un List Box ma tra le sue proprietà ci sono quelle collegate ai dati; ci interessano RowSource e ListField: la prima è il controllo Data collegato, la seconda il campo che verrà listato.
Però abbiamo un problema: se usiamo il campo Cognome come facciamo se abbiano 2 record con lo stesso cognome e nomi diversi?
Facciamo attenzione a questo punto perché la soluzione potrà servirci anche in futuro!
Creiamo un altro controllo Data (Data2), lo assegnamo allo stesso Database di Data1,
ma come RecordsetType lasciamo 1 - Dynaset e come RecordSource usiamo una SQL:
SELECT Cognome, Nome, Cognome & ' ' & Nome AS Anagraf FROM Rubrica ORDER BY Cognome, Nome |
C'è una novità! Infatti nell'elenco campi della SQL non compare un campo o una funzione di aggregazione, ma una espressione campi (Cognome & ' ' & Nome) seguita da AS Anagraf (tecnicamente detto Alias): abbiamo creato un nuovo campo e gli abbiamo dato come "Header di Colonna" Anagraf; l'espressione campi può essere qualsiasi, ad esempio Importo * 1,2 AS ConIva, od anche più complicata e questo ci potrà essere utile in futuro.
Impostiamo a Data2 ReadOnly = True (non si sa mai) e Visible = False (non serve per scorrere i records) e mettiamo al nostro DbList RowSource = Data2 e ListField = Anagraf.
il Form avrà questo aspetto:
Private Sub DBList1_Click() ' posiziona Data2 su quello selezionato Data2.Recordset.Bookmark = DBList1.SelectedItem ' Ricerca per chiave su Data1 Data1.Recordset.Seek "=", Data2.Recordset("Cognome"), Data2.Recordset("Nome") End Sub |
Il controllo DbList non viene aggiornato automaticamente se variamo, aggiungiamo o cancelliamo records da Data1, per cui dobbiamo aggiungere
Private Sub Data1_Reposition() Data2.Refresh DBList1.ReFill End Sub |
Il nostro programma è terminato: i files di progetto Vb6 e Rubrica.mdb sono contenuti in Esempio1.zip (Download - 11kb) Esempio N.2 Se dobbiamo realizzare una applicazione per terzi lo schema seguito necessita di alcuni miglioramenti. Infatti non possiamo aggiornare in diretta il Database, ma dobbiamo farlo solo dopo avere controllato i dati immessi e dopo che l'utente abbia confermato l'operazione.
Pertanto dovremo operare nel modo seguente:
1 - Utilizzare nel Frame esistente label al posto di Text1 per la sola visualizzazione;
2 - Aggiungere un altro pulsante: EDIT;
3 - Creare un altro frame come quello attuale e nella stessa posizione ma con i campi Text non collegati a Data1 e con 2 pulsanti OK e Cancel e porre il frame con Visible = False;
4 - Al click di EDIT riempire i Text del 2° frame con le Caption delle label, renderlo visibile e mettere DbList1.Enabled = False;
5 - Al click di INSERT mettere a "" i Text del 2° frame, renderlo visibile e mettere DbList1.Enabled = False;
6 - Effettuare Data1.Recordset.Edit o Data1.Recordset.AddNew, mettere nei campi di Data1 il contenuto dei Text ed eseguire Data1.Recordset.Update quando viene cliccato OK e solo dopo avere controllato la congruità dei dati immessi (segnalando gli errori se ci sono), quindi rendere di nuovo invisibile il frame e riabilitare DbList1;
7 - Se viene cliccato Cancel rendere invisibile il frame e riabiltare DbList1.
Disabilitare DbList1 è necessario, perché se viene cliccato sposta il record corrente mentre stiamo aggiornando!
Non sarà più necessario spostare il puntatore dopo un aggiornamento in quanto il metodo Update provvede a rendere effettiva la modifica.
Il programma così modificato si chiama Esempio2 ed i files Vb6 relativi sono contenuti in Esempio2.zip (Download - 5kb). Oltre che utilizzarlo come vi pare potete stampare Esempio1 ed Esempio2 e confrontarli.
Inoltre potrebbe essere utile aggiungere la possibilità di ricercare i record per Chiave parziale: possiamo aggiungere una casella Textn ed all'evento Keypress eseguire Data1.Recordset.Seek ">=", Textn.Text; teniamo però presente che la chiave è "case sensitive" (Mal, mal e MAL non sono la stessa cosa), per cui nel caso del nostro esempio dovremo porre maiuscola (Ucase$) la 1a lettera del Text e minuscole (LCase$) le successive prima di eseguire la Seek.
In questo modo abbiamo anche visto il trattamento di un Database tramite oggetti DAO, anche se si tratta di oggetti impliciti ovvero creati automaticamente dal sistema: Data1.Recordset è un oggetto a tutti gli effetti e supporta tutti i Metodi e le Proprietà degli oggetti Recordset.
Nella Lezione 6 tratteremo oggetti espliciti, ovvero creati da noi tramite codice, e vedremo come trattarli.