Corso Visual Basic

Page 1


Maurizio Crespi - Corso di Visual Basic (Parte I)

Corso di Visual Basic (Parte I)

Corso di Visual Basic (Parte I)

La creazione di un form Gli eventi I metodi Le variabili Conclusioni Figure

Come muovere i primi passi con Microsoft Visual Basic, lo strumento da molti considerato ideale per la realizzazione di applicazioni di piccola e media entità in ambiente Windows.

Figura 1

di Maurizio Crespi

Figura 2 Figura 3

La nascita di Microsoft Visual Basic ha comportato una rivoluzione nel mondo degli strumenti di sviluppo per Windows, lanciando un nuovo modo di programmare, che vede per la prima volta prevalere l'uso del (c) 1997, Edizioni Infomedia srl mouse nei confronti di quello della tastiera. Figura 4

Tale approccio, detto visuale, si basa sull'uso di oggetti, ovvero di elementi attivi selezionabili su una barra degli strumenti (toolbox), caratterizzati dall'essere descritti da un insieme di valori, detti proprietà ed in grado di eseguire dei metodi, ovvero delle azioni che ne possono influenzare lo stato. Un'ulteriore particolarità degli oggetti consiste nella capacità di generare degli eventi, a cui il programmatore può associare come risposta degli insiemi di istruzioni, detti procedure (ad esempio quando viene premuto un bottone il programmatore può associare la chiusura di una finestra). Il linguaggio con cui esse sono scritte si basa sulle regole sintattiche previste dal BASIC, di cui mantiene la semplicità. La creazione di un form Un'applicazione Visual Basic è costituita da una o più finestre, dette form, sulle quali si trovano gli oggetti che formano l'interfaccia fra l'applicazione e l'utente. Su un form è possibile inserire pressoché qualsiasi elemento, sia che si tratti di un'immagine, di un box di testo, di una lista o di un pulsante. Il form principale dell'applicazione è generato automaticamente ogni volta che si agisce sul menu File per creare un nuovo progetto ed è visualizzato all'avvio dell'applicazione, di cui, in genere, rappresenta la schermata principale. La sua chiusura determina la fine dell'esecuzione del programma. Si supponga di voler realizzare un'applicazione che, alla pressione di un pulsante, faccia apparire in un punto preciso della finestra la scritta "Benvenuto in Visual Basic". Il primo passo consiste nel posizionare sul form gli elementi grafici necessari. Si deve dapprima inserire un contenitore per il testo da visualizzare. Visual Basic prevede due tipi di elementi adatti a questo scopo: si tratta delle label e delle textbox. file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

Le prime, come indica il nome, sono dedicate alla visualizzazione di "etichette", ovvero di porzioni di testo non modificabili dall'utente. Le seconde, invece, consentono la digitazione di un testo al proprio interno e si rivelano pertanto adatte all'acquisizione di dati. Nel caso dell'esempio, dovendo visualizzare un testo modificabile solo dal programma, è conveniente optare per una label, che può essere inserita sul form rendendo visibile la barra degli strumenti di disegno, operazione effettuabile agendo sulla voce Toolbox del menu View, selezionando su di essa l'elemento contraddistinto dalla lettera "A" e tracciando con il mouse un rettangolo sull'area destinata ad ospitare l'etichetta. Al rilascio del pulsante sinistro del mouse appare l'elemento desiderato, contenente la scritta "Label1". Con questa operazione si crea il primo oggetto. Per adeguarlo alle proprie esigenze, è necessario variarne le proprietà. Ciò è possibile facendo clic su di esso con il mouse e visualizzando la finestra delle proprietà agendo sulla voce Properties Window del menu View. Appare così una tabella, in cui la colonna di sinistra contiene i nomi di tutte le proprietà che descrivono l'elemento e la colonna di destra ne indica i rispettivi valori. Nel caso dell'etichetta testuale appena creata, si nota che due sue proprietà contengono il testo "Label1". Esse sono denominate, rispettivamente, Name e Caption. Come è facile immaginare, esse definiscono rispettivamente il nome dell'oggetto, ovvero l'identificatore da usare ogniqualvolta si desideri fare riferimento ad esso e il testo visualizzato nell'etichetta. Si noti che Visual Basic provvede ad assegnare a queste proprietà un valore predefinito. Spesso, però, è necessario fare in modo che la label visualizzi un dato diverso. Nell'esempio, l'etichetta deve visualizzare del testo solo dopo la pressione del pulsante. È pertanto necessario che all'avvio del programma il suo contenuto sia nullo. Affinché ciò avvenga, si deve fare clic con il mouse sulla colonna di destra in corrispondenza della proprietà Caption e si deve sostituirne il contenuto con uno spazio. Sebbene sia possibile mantenere per gli oggetti i nomi predefiniti, è consigliabile, al fine di rendere più facilmente leggibile il programma, assegnare ad essi degli identificatori che permettano ad un altro programmatore, o allo stesso autore dopo che sia trascorso un considerevole lasso di tempo, di poterne facilmente comprendere la funzione. Ciò rende più semplice ogni eventuale modifica successiva. Nel caso dell'esempio, è pertanto conveniente assegnare all'etichetta il nome lblMessaggio. Si noti l'uso del prefisso "lbl", abbreviazione di "label". Il ricorso a un prefisso è assolutamente facoltativo, ma si rivela estremamente utile nel caso di applicazioni complesse per fare sì che a colpo d'occhio sia possibile comprendere il tipo di componente a cui si sta facendo riferimento. La modifica del nome dell'oggetto avviene digitando il nuovo identificatore nella colonna di destra della finestra Properties, in corrispondenza della riga denominata Name. file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

In modo analogo a quanto visto per la label, è possibile inserire il pulsante all'interno del form selezionando sulla toolbox l'apposita icona e tracciando un rettangolo avente le dimensioni dell'oggetto da creare. Queste ultime possono essere modificate in qualsiasi momento trascinando i bordi dell'elemento con il mouse. Sempre con l'ausilio di questo strumento, è possibile spostare qualsiasi oggetto in una diversa posizione. Agendo sulla finestra delle proprietà, è possibile denominare l'oggetto btScrivi (ove "bt" rappresenta l'abbreviazione di bottone) e associare alla proprietà Caption, che contiene il testo che deve apparire sul pulsante, il valore "Scrivi". Gli eventi Il form appare come visualizzato in Figura 1. A questo punto è necessario rendere "attivo" il bottone, ovvero fare in modo che al verificarsi dell'evento costituito dalla sua pressione sia eseguito del codice che provveda a modificare il contenuto della label. A tal fine, occorre selezionare il pulsante e fare su di esso un doppio clic con il mouse. Si provoca così l'apertura di una finestra caratterizzata da una barra nella parte superiore, in cui è possibile osservare due liste a scomparsa. Quella posta a sinistra contiene il nome dell'oggetto, mentre in quella di destra sono elencati tutti i possibili eventi che esso può generare. Volendo fare in modo che la risposta avvenga in occasione della pressione del pulsante, occorre selezionare nella lista l'evento Click. Si provoca così la creazione della procedura btScrivi_Click, di cui è automaticamente visualizzata l'intestazione nella parte inferiore della finestra, seguita dalla frase End Sub, che indica la fine del blocco di codice. Le istruzioni che devono essere eseguite in risposta all'evento vanno inserite nello spazio compreso fra le righe generate automaticamente, avendo l'accortezza di indicare un solo comando per linea. Per fare in modo che il programma visualizzi per mezzo della label lblMessaggio il testo "Benvenuto in Visual Basic", è necessario variare la proprietà Caption di quest'ultima. La procedura da associare al pulsante è quindi la seguente: Sub btScrivi_Click () lblMessaggio.Caption = "Benvenuto in Visual Basic" End Sub Si noti che il nome della proprietà segue quello dell'oggetto, da cui è separato per mezzo di un punto. Per verificare il funzionamento dell'applicazione, è necessario selezionare la voce Start del menu Run, oppure premere il tasto F5. È così possibile osservare che, pur digitando una sola riga di codice, è stato creato un vero programma operante in ambiente Windows con un'interfaccia grafica.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

I metodi Come si è già accennato, ogni oggetto è in grado di ricevere dei comandi che possono provocare la variazione di alcune proprietà o la generazione di eventi. Si tratta dei metodi. L'invocazione di un metodo avviene secondo la sintassi: <oggetto>.<metodo> [<parametro>, ... ,<parametro>] Al nome dell'oggetto è necessario far seguire, separato da un punto, quello del metodo e gli eventuali parametri. Ad esempio, l'aggiunta della riga lblMessaggio.Move 0,0 nella procedura vista in precedenza, provoca l'esecuzione del metodo Move da parte dall'oggetto lblMessaggio. La coppia 0, 0 rappresenta l'insieme dei parametri. L'effetto che si ottiene consiste nello spostamento dell'etichetta testuale nell'angolo superiore sinistro del form, ovvero nel punto di cui i parametri rappresentano le coordinate. Le variabili Anche Visual Basic, come tutti i linguaggi di programmazione, prevede l'uso delle variabili, mediante le quali è possibile memorizzare dei valori testuali o numerici in strutture a cui il programma può accedere grazie a un nome assegnato loro in fase di creazione. Una variabile è detta locale quando è definita all'interno di una procedura; la sua creazione avviene quando si fa riferimento ad essa per la prima volta, oppure quando è eseguita l'istruzione Dim, che presenta la seguente sintassi: Dim <nome> [As <tipo>] in cui <nome> rappresenta il nome da assegnare alla variabile. Esso non si sottrae alla regola valida per tutti gli identificatori, ivi compresi i nomi degli oggetti, che impone loro di essere costituiti da delle sequenze di caratteri alfabetici o numerici prive di spazi ed aventi per iniziali delle lettere dell'alfabeto. È inoltre possibile, anche se non indispensabile (come sottolineato dalla presenza delle parentesi quadre), aggiungere all'istruzione Dim un'indicazione del tipo di dato da creare. Visual Basic prevede numerosi tipi standard. I più utilizzati sono integer, usato per rappresentare i dati numerici interi compresi fra -32,768 a 32,767, string, che può contenere delle sequenze (stringhe) alfanumeriche composte al massimo da circa 65500 caratteri, long, in grado di ospitare numeri interi compresi fra 2,147,483,648 e 2,147,483,647, single e double, con cui è possibile memorizzare numeri reali anche di notevole entità. Se invece è omessa la dichiarazione del tipo, la variabile è definita variant. Questo formato non è previsto dalla maggior parte dei linguaggi

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

di programmazione tradizionali. La sua caratteristica fondamentale è l'universalità. Una variabile variant, infatti, può contenere dei dati aventi qualsiasi formato. È buona norma, tuttavia, non fare largo uso di strutture di questo tipo, in quanto la loro gestione da parte dell'interprete è poco efficiente. Una variabile locale può anche non essere dichiarata. In questo caso, la sua creazione avviene la prima volta in cui si fa riferimento ad essa. In assenza di dichiarazione, è necessario aggiungere al nome un identificatore di tipo, costituito da un carattere. In caso di sua omissione, la variabile è creata di tipo Variant. I principali identificatori di tipo sono i seguenti: $ (String), % (Integer), & (Long), ! (Single), # (Double). Ad esempio, è possibile creare una variabile di tipo numerico intero ed assegnarle il valore 5 sia scrivendo Dim A as Integer A = 5 sia con la riga A% = 5 Dopo l'esecuzione dell'ultima istruzione presente nella procedura in cui sono state create, le variabili locali sono automaticamente distrutte. Per fare in modo che il loro valore sia conservato anche in occasione delle chiamate successive, è necessario dichiarare le variabili sostituendo Static alla parola chiave Dim. In alcuni casi, si rivela necessario fare in modo che una variabile non sia mai distrutta e sia accessibile anche dalle altre procedure presenti in un form. In questo caso, è necessario selezionare la sezione General nella lista a discesa posta nella parte superiore sinistra della finestra contenente il codice associato al form, la voce Declarations nella lista di destra e dichiarare la variabile per mezzo dell'istruzione Dim. Quando invece si presenta la necessità di fare in modo che una struttura sia accessibile da tutte le procedure presenti nell'applicazione, indipendentemente dal form in cui esse si trovano, è necessario utilizzare per la dichiarazione la parola chiave Global. Una variabile dichiarata in questo modo è detta globale. La sua dichiarazione è impossibile all'interno di un form. Essa deve essere effettuata in un modulo, ovvero in un file di testo caratterizzato dall'estensione .BAS, che è aggiunto al progetto selezionando la voce Add Module del menu Project. La riga di codice rappresenta un esempio di dichiarazione di una variabile globale: Global NomeCognome as String Un esempio di utilizzo di una variabile Si consideri l'applicazione precedentemente realizzata. Si desidera

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

modificarla per creare un semplice strumento in grado di visualizzare il tempo trascorso dall'ultima pressione del pulsante btScrivi. Per fare ciò, è necessario aggiungere al form un timer. Si tratta di un oggetto in grado di generare un evento ad intervalli regolari, la cui frequenza è decisa dal programmatore. Per inserire tale elemento, occorre selezionare sulla toolbox l'icona a forma di cronografo e disegnare un rettangolo sul form. Si provvede poi a selezionare il nuovo oggetto, a visualizzare la finestra Properties e ad assegnare il valore 1000 alla proprietà Interval. In tal modo si definisce il periodo (in millisecondi) che intercorre fra due eventi. L'impostazione effettuata provoca la generazione di un evento ogni secondo. Anche in questo caso, è possibile associare al verificarsi di questi eventi un insieme di istruzioni da eseguire. Ciò è possibile facendo doppio clic sull'oggetto. Si provoca così l'apertura della finestra del codice sorgente e la creazione della procedura Timer1_Timer, in cui è possibile scrivere: Sub Timer1_Timer () NumSecondi = NumSecondi + 1 lblMessaggio.Caption = Str$(NumSecondi) End Sub Essa ha lo scopo di incrementare di un'unità il valore della variabile NumSecondi, usata per conteggiare i secondi e di visualizzare tale valore all'interno della label. A tal fine, il risultato del conteggio è convertito in testo tramite la funzione Str$ ed è assegnato alla proprietà Caption dell'oggetto che provvede a visualizzarlo sullo schermo. Per consentire l'azzeramento del contasecondi in seguito alla pressione del pulsante btScrivi, è necessario modificare la procedura associata a tale evento. Ciò è possibile facendo doppio clic sul bottone e sostituendo le istruzioni precedentemente inserite con le seguenti: Sub btScrivi_Click () NumSecondi = 0 End Sub Affinché la variabile NumSecondi possa essere utilizzata da entrambe le procedure, è necessario che sia accessibile in tutto il form. Come visto in precedenza, perché ciò sia possibile, si deve digitare nella sezione Global/Declarations la riga Dim NumSecondi as Long Conclusioni Come dimostrato dagli esempi sopra descritti, si può realizzare

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


Maurizio Crespi - Corso di Visual Basic (Parte I)

un'applicazione funzionante in ambiente Windows in un batter d'occhio, semplicemente facendo uso del mouse e scrivendo un numero davvero ridotto di righe di codice. È proprio grazie alla notevole facilità d'uso, oltre che all'affidabilità dell'interprete di cui è dotato, che Visual Basic è da molti considerato lo strumento ideale per la realizzazione di programmi di piccola e media entità. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb01/index.htm[23/09/2010 4:38:12]


La dichiarazione di una variabile accessibile da tutte le procedure presenti nel form

Figura 4 La dichiarazione di una variabile accessibile da tutte le procedure presenti nel form

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb01/fig4.htm[23/09/2010 4:39:19]


L'ambiente di sviluppo di Visual Basic 5

Figura 1 L'ambiente di sviluppo di Visual Basic 5

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb01/fig1.htm[23/09/2010 4:42:19]


La toolbox e la finestra "Properties"

Figura 2 La toolbox e la finestra "Properties"

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb01/fig2.htm[23/09/2010 4:42:54]


L'applicazione di esempio in esecuzione

Figura 3 L'applicazione di esempio in esecuzione

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb01/fig3.htm[23/09/2010 4:43:04]


Maurizio Crespi - Corso di Visual Basic (Parte 2)

Corso di

Corso di Visual Basic (Parte 2)

Visual Basic

Le soluzioni degli esercizi proposti nella prima parte La struttura If La funzione Val

(Parte 2)

Le strutture If nidificate Conclusioni Figure

di Maurizio Crespi

Figura 1 Figura 2 Figura 3

La seconda parte del corso introduttivo alla programmazione in Visual Basic si pone come scopo di insegnare l'uso della struttura di controllo If e delle proprie varianti.

Figura 4

Dopo aver studiato come si creano delle semplici applicazioni ed aver preso confidenza con i tipi di dati fondamentali, è ora giunto il (c) 1997, Edizioni Infomedia srl momento di occuparsi delle strutture di controllo, mediante le quali si possono scrivere dei programmi in grado di comportarsi in modo diverso a seconda dei valori assunti dai dati da elaborare.

Le soluzioni degli esercizi proposti nella prima parte Prima di affrontare nuovi argomenti, è bene rivedere ciò che è stato oggetto di studio nella scorsa puntata. Lo spunto è offerto dalla correzione degli esercizi in essa proposti. Il primo esercizio Il primo esercizio prevede la creazione di un programma in grado di simulare il funzionamento di un interruttore mediante due pulsanti, riportanti rispettivamente le scritte "ON" e "OFF" e un'etichetta di testo, nella quale devono essere visualizzate in alternativa le indicazioni "Acceso" e "Spento". La prima fase consiste nel creare un nuovo progetto e nell'inserire all'interno del form principale i tre elementi grafici. Si provvede poi, per mezzo dell'apposita finestra, ad assegnare ad essi i valori della proprietà Caption, affinché sui pulsanti appaiano le scritte "ON" e "OFF". L'interfaccia appare come nella Figura 1. È buona norma assegnare anche dei nomi agli oggetti. Ciò comporta l'impostazione per ognuno di essi della proprietà Name. Si supponga di utilizzare i nomi btnON, btnOFF, per i pulsanti e lblValore per l'etichetta testuale. L'ultimo passo consiste nello scrivere il codice da associare alla pressione dei bottoni. Essi devono semplicemente variare il testo visualizzato dalla label, ovvero modificare la sua proprietà Caption. Dopo aver premuto due volte il tasto sinistro del mouse sul pulsante btnON ed aver quindi aperto la finestra che ospita il codice di risposta all'evento Click, è necessario scrivere quanto segue: Private Sub btnON_Click()

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2) lblValore.Caption = "Acceso" End Sub

Si noti che l'indicazione Private, il cui significato sarà analizzato in uno dei prossimi numeri, deve essere omessa sulle versioni di Visual Basic precedenti la 4.0. In modo perfettamente analogo si può completare l'applicazione associando al pulsante btnOFF la procedura: Private Sub btnOFF_Click() lblValore.Caption = "Spento" End Sub

Il secondo esercizio Nel secondo esercizio è richiesta la modifica del funzionamento di un programma che simula un cronografo. L'interfaccia si compone di un pulsante di azzeramento e di una label che visualizza il numero dei secondi trascorsi. Si desidera fare in modo che l'indicazione del tempo sia rappresentata nel formato HH:MM:SS. Il conteggio avviene per mezzo di un timer regolato, mediante l'impostazione della proprietà Interval al valore 1000, in modo da generare un evento ogni secondo. La procedura da modificare è pertanto quella che gestisce gli eventi Timer da esso prodotti. Devono essere eseguite delle divisioni successive per determinare il numero delle ore, dei minuti e dei secondi. Il codice diventa pertanto il seguente: Private Sub Timer1_Timer() Dim Ore, Minuti, Secondi, Resto As Integer Dim StringaOre, StringaMinuti, StringaSecondi, Tempo As String NumSecondi = NumSecondi + 1 Ore = Int(NumSecondi / 3600) Resto = NumSecondi - (Ore * 3600) Minuti = Int(Resto / 60) Secondi = Resto - (Minuti * 60) StringaOre = Str$(Ore) StringaMinuti = Str$(Minuti) StringaSecondi = Str$(Secondi) Tempo = StringaOre + ":" Tempo = Tempo + StringaMinuti + ":" Tempo = Tempo + StringaSecondi lblMessaggio.Caption = Tempo End Sub

Si noti che, per estrarre la parte intera del risultato di ogni divisione, si è fatto ripetutamente uso della funzione Int. Il numero delle ore è calcolato dividendo per 3600 il totale dei secondi, contenuto nella variabile globale NumSecondi. Il resto è poi diviso per 60 al fine di quantificare i minuti. Questa operazione genera un nuovo resto, che rappresenta il numero di secondi. I valori ottenuti sono successivamente trasformati in sequenze alfanumeriche e copiati nella variabile Tempo, anch'essa di tipo String, avendo cura di interporre fra di loro il carattere ":". Si noti che, per concatenare le stringhe, si fa uso dell'operatore di addizione "+". Il valore della file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2)

variabile Tempo è infine visualizzato per mezzo della label.

La struttura If Avviando l'applicazione sopra descritta, è possibile osservare che il contenuto dell'etichetta non è esattamente espresso nel formato HH:MM:SS. Infatti, l'indicazione appare come in Figura 2, ossia i valori indicanti il numero di ore, minuti e secondi non sono obbligatoriamente composti da due cifre. Si supponga di voler modificare il programma affinché provveda ad anteporre uno zero non significativo al contenuto delle variabili StringaOre, StringaMinuti e StringaSecondi ogniqualvolta esse risultino composte da una sola cifra. L'applicazione, in questo caso, deve essere in grado di riconoscere una condizione, nella fattispecie la presenza di un valore inferiore a dieci e di intervenire anteponendo uno zero solo quando essa è verificata. A differenza degli esempi fino ad ora esaminati, il flusso delle istruzioni all'interno della procedura non è più rigidamente definito, ma può variare in base al verificarsi di alcune condizioni. Il programma deve pertanto essere in grado di prendere delle decisioni. Come la quasi totalità dei linguaggi di programmazione, Visual Basic prevede a tal fine la struttura If, caratterizzata dalla seguente sintassi: If <condizione> Then <istruzioni da eseguire se la condizione è vera> [Else <istruzioni da eseguire se la condizione è falsa>] End If

La condizione può essere rappresentata da pressoché qualsiasi espressione booleana. Si ricorda che un'espressione è così detta se può assumere solo due valori distinti, cioè vero o falso. Se essa è verificata, l'interprete esegue il blocco di istruzioni indicato fra le parole chiave Then e Else. In caso contrario, è eseguito il secondo gruppo di comandi. Si noti che quest'ultimo può anche essere assente. In tal caso, la parola chiave Else non va utilizzata e non è eseguito alcun codice in caso di mancata verifica della condizione. La frase End If delimita la struttura. Tutte le istruzioni che la seguono sono eseguite in modo indipendente dal valore dell'espressione booleana. La procedura da associare all'evento Timer può essere pertanto modificata come indicato: Private Sub Timer1_Timer() Dim Ore, Minuti, Secondi, Resto As Integer Dim StringaOre, StringaMinuti, StringaSecondi, Tempo As String NumSecondi = NumSecondi + 1 Ore = Int(NumSecondi / 3600) Resto = NumSecondi - (Ore * 60) Minuti = Int(Resto / 60) Secondi = Resto - (Minuti * 60) If Ore < 10 Then StringaOre = "0" & Ore

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2) Else StringaOre = Str$(Ore) End If If Minuti < 10 Then StringaMinuti = "0" & Minuti Else StringaMinuti = Str$(Minuti) End If If Secondi < 10 Then StringaSecondi = "0" & Secondi Else StringaSecondi = Str$(Secondi) End If Tempo = StringaOre + ":" Tempo = Tempo + StringaMinuti + ":" Tempo = Tempo + StringaSecondi lblMessaggio.Caption = Tempo End Sub

Essa si differenzia dalla precedente per l'introduzione di tre strutture di controllo pressoché analoghe. Si osservi ad esempio la prima; la condizione è vera se la variabile Ore contiene un numero inferiore a dieci. In questo caso, alla variabile StringaOre è associato un testo composto dal carattere "0" e dal valore contenuto nella variabile Ore. Si noti che in questo caso non si è fatto uso della funzione Str$. Quando un dato numerico è assegnato ad una variabile di tipo stringa, infatti, la conversione di formato è eseguita automaticamente, a condizione che il codice utilizzato non possa generare delle ambiguità. È per questo motivo che la concatenazione delle stringhe è stata effettuata mediante il simbolo "&", anziché con l'operatore di addizione che, essendo applicabile anche ai valori numerici, avrebbe reso l'interprete incapace di dedurre le reali intenzioni del programmatore. Il carattere "&" può essere utilizzato esclusivamente per unire due stringhe alfanumeriche e quindi pone al riparo da ogni dubbio.

La funzione Val Nel seguito di questa trattazione si farà uso delle caselle di testo (textbox). Esse risultano estremamente simili alle label, ma si differenziano da esse in quanto rendono possibile la modifica del proprio contenuto all'utente finale. Sono pertanto utilizzate ogniqualvolta si presenti la necessità di richiedere un dato alfanumerico all'utilizzatore del programma. Per verificare o modificare il loro contenuto è necessario accedere alla proprietà Text, che è sempre di tipo String. La sua conversione in una valore numerico, quando possibile, può essere effettuata per mezzo della funzione Val, la cui sintassi è: <var1> = Val(<var2>)

dove var1 è di tipo numerico e var2 rappresenta una stringa. Occorre notare che la funzione esegue una scansione del testo fornitole come parametro a partire dal carattere posto all'estrema sinistra. Il controllo

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2)

termina quando è incontrato un elemento non numerico. Pertanto, la condizione Val("1234") = Val("1234abc")

è verificata. Inoltre, è vera anche la condizione: Val("abcde") = 0

Facendo tesoro di ciò che è stato appena appreso, si provi a realizzare una semplice applicazione in grado di visualizzare in una label il valore assoluto di un numero posto in una casella di testo, senza far uso della funzione Abs. Il calcolo può essere eseguito in corrispondenza della pressione di un pulsante.

Le strutture If nidificate Si supponga di voler realizzare un programma in grado di calcolare il valore massimo fra due numeri forniti in ingresso mediante delle caselle di testo e di visualizzare il risultato in una label. L'interfaccia è rappresentata nella Figura 3. Si supponga di assegnare i nomi txtPrimoValore e txtSecondoValore alle textbox. La procedura da associare come risposta alla pressione del pulsante di calcolo è la seguente: Private Sub btCalcola_Click() Dim Valore1, Valore2 As Double Dim Risultato As String Valore1 = Val(txtPrimoValore.Text) Valore2 = Val(txtSecondoValore.Text) If Valore1 > Valore2 Then Risultato = "Valore massimo: " & Valore1 Else If Valore1 < Valore2 Then Risultato = "Valore massimo: " & Valore2 Else Risultato = "I valori sono uguali" End If End If lblMessaggio.Caption = Risultato End Sub

Dopo aver copiato i dati in ingresso in variabili numeriche, l'applicazione procede al confronto fra i valori. Dapprima il programma verifica se prevale il contenuto della variabile Valore1 rispetto a quello di Valore2. Se la condizione è verificata, il massimo è copiato nella variabile Risultato, che costituisce il testo da visualizzare per mezzo della label lblMessaggio. Altrimenti, è eseguito l'altro blocco della struttura If, ovvero è verificata la prevalenza del secondo valore rispetto al primo. In caso negativo, è segnalata l'uguaglianza dei dati in ingresso. È possibile osservare che è stata posta una struttura If all'interno di un'altra. L'annidamento di più blocchi di programma è una pratica molto comune quando si fa uso di linguaggi moderni come Visual Basic. Si noti che se fosse stato necessario eseguire il confronto fra un numero più elevato di valori, l'uso di strutture nidificate

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2)

avrebbe influenzato negativamente la leggibilità del programma. Per ridurre tali effetti negativi è possibile utilizzare la parola chiave ElseIf, che permette di mantenere un'organizzazione a due livelli anche in presenza di un numero elevato di confronti. Ecco come si presenta la procedura modificata: Private Sub btCalcola_Click() Dim Valore1, Valore2 As Double Dim Risultato As String Valore1 = Val(txtPrimoValore.Text) Valore2 = Val(txtSecondoValore.Text) If Valore1 > Valore2 Then Risultato = "Valore massimo: " & Valore1 ElseIf Valore1 < Valore2 Then Risultato = "Valore massimo: " & Valore2 Else Risultato = "I valori sono uguali" End If lblMessaggio.Caption = Risultato End Sub

L'uso delle parole riservate ElseIf permette di aumentare a piacimento il numero di condizioni da controllare all'interno della stessa struttura. Se nessuna di esse risulta verificata, allora è eseguito il codice specificato dopo la parola chiave Else. Per verificarne l'utilità, si provi a realizzare un'applicazione in grado di visualizzare un messaggio indicante se il dato inserito in una textbox rappresenta il nome di uno dei giorni della settimana.

Conclusioni Le strutture di controllo, oggetto di questa trattazione, danno alle applicazioni la flessibilità necessaria per svolgere operazioni non banali. Per questo motivo, la loro conoscenza è di importanza fondamentale. Al lettore è pertanto rivolto l'invito ad esercitarsi nell'uso di tali costrutti. Buon lavoro, dunque! (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


Maurizio Crespi - Corso di Visual Basic (Parte 2)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/index.htm[26/09/2010 12:37:56]


L'applicazione di esempio

Figura 3 L'applicazione di esempio

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/FIG3.HTM[26/09/2010 12:48:06]


La soluzione del secondo esercizio

Figura 2 La soluzione del secondo esercizio

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/FIG2.HTM[26/09/2010 12:47:40]


La soluzione del primo esercizio

Figura 1 La soluzione del primo esercizio

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/FIG1.HTM[26/09/2010 12:47:09]


La procedura che risponde alla pressione del pulsante btCalcola

Figura 4 La procedura che risponde alla pressione del pulsante btCalcola

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb02/FIG4.HTM[26/09/2010 12:48:48]


La soluzione del primo esercizio

Figura 1 La soluzione del primo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb02/fig1.htm[26/09/2010 12:52:10]


La soluzione del secondo esercizio

Figura 2 La soluzione del secondo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb02/fig2.htm[26/09/2010 12:52:55]


L'applicazione di esempio

Figura 3 L'applicazione di esempio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb02/fig3.htm[26/09/2010 12:53:16]


La procedura che risponde alla pressione del pulsante btCalcola

Figura 4 La procedura che risponde alla pressione del pulsante btCalcola

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb02/fig4.htm[26/09/2010 12:53:26]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

Corso di

Corso di Visual Basic (Parte 3)

Visual Basic

Le soluzioni agli esercizi della scorsa puntata La struttura Select Case Quando utilizzare la struttura Select Case

(Parte 3)

Confronti Multipli Gli operatori logici elementari L'operatore And

di Maurizio Crespi

L'operatore Or L'operatore Not Conclusioni Figure Figura 1 Figura 2 Figura 3 Figura 4

Il corso dedicato alla programmazione con Microsoft Visual Basic continua con l'analisi della struttura di controllo Select Case e degli operatori logici fondamentali

Spesso si rivela necessario sviluppare dei programmi caratterizzati dalla capacità di eseguire istruzioni diverse in base al valore assunto da una o più variabili. A tal fine, Visual Basic prevede la struttura di selezione multipla Select Case, al centro dell'attenzione in questa terza parte del corso dedicato alla programmazione con il noto strumento Microsoft. Continua pertanto lo studio delle strutture di controllo, delle quali difficilmente un'applicazione può fare a meno.

(c) 1997, Edizioni Infomedia srl

Le soluzioni agli esercizi della scorsa puntata Prima di affrontare lo studio di nuovi argomenti, è opportuno rivedere quanto esposto nello scorso numero. Come di consueto, lo spunto è offerto dalla correzione degli esercizi in esso proposti. Primo esercizio Il primo esercizio prevede la realizzazione di un programma in grado di leggere un numero mediante una textbox e di visualizzarne il valore assoluto. A tal fine, dopo aver creato un nuovo progetto, occorre aggiungere al form principale la casella di testo, a cui è possibile assegnare il nome txtNumero, nonché il pulsante btnCalcola, a cui è affidata la funzione di provocare l'aggiornamento del contenuto della label lblRisultato con il frutto dell'elaborazione. Ciò è ottenuto per mezzo della seguente procedura: Private Sub btnCalcola_Click() Dim StringaNumero As String Dim Numero As Integer StringaNumero = txtNumero.Text Numero = Val(StringaNumero) If Numero > 0 Then lblRisultato.Caption = "Valore assoluto: " & Numero Else lblRisultato.Caption = "Valore assoluto: " & Str(-1 * Numero) End If End Sub

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

Il contenuto della textbox è posto nella variabile StringaNumero, che è convertita in un dato numerico per mezzo della funzione Val. Per fare in modo che il valore sia mantenuto invariato qualora risulti positivo, o ne sia calcolato l'opposto altrimenti, si impone il ricorso ad una struttura If, associata alla condizione Numero > 0

Quando essa è verificata, il valore numerico fornito in ingresso è visualizzato senza subire modifiche. In caso contrario, la procedura provvede ad effettuare l'inversione di segno e ad assegnare il risultato, opportunamente trasformato in una stringa, alla label. Secondo esercizio Anche il secondo esercizio prevede la creazione di un programma in grado di ricevere un valore in ingresso per mezzo di una textbox e di visualizzare un risultato mediante una label. L'applicazione da sviluppare deve controllare che il dato inserito dall'utente rappresenti uno dei nomi dei giorni della settimana. Si desidera fare in modo che la verifica sia svolta automaticamente ogniqualvolta il contenuto della casella di testo subisca una variazione. Questa condizione è segnalata dall'oggetto, a cui si suppone di aver assegnato il nome txtTestoDigitato, con la generazione dell'evento Change. Per associare ad esso del codice, è sufficiente fare doppio clic con il mouse sulla textbox. In tal modo si crea la procedura txtTestoDigitato_Change, di seguito descritta. Private Sub txtTestoDigitato_Change() Dim Testo As String Dim GiornoSettimana As Integer Testo = UCase(txtTestoDigitato.Text) If Testo = "LUNEDI" Then GiornoSettimana = True ElseIf Testo = "MARTEDI" Then GiornoSettimana = True ElseIf Testo = "MERCOLEDI" Then GiornoSettimana = True ElseIf Testo = "GIOVEDI" Then GiornoSettimana = True ElseIf Testo = "VENERDI" Then GiornoSettimana = True ElseIf Testo = "SABATO" Then GiornoSettimana = True ElseIf Testo = "DOMENICA" Then GiornoSettimana = True Else GiornoSettimana = False End If If GiornoSettimana Then lblRisultato.Caption = "E' un giorno della settimana" Else lblRisultato.Caption = "Non è un giorno della settimana" End If End Sub

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

Si noti l'uso della funzione UCase, che provvede a restituire la stringa derivante dalla conversione in lettere maiuscole del dato in ingresso. Ciò permette di verificare la corrispondenza del testo digitato dall'utente al nome di un giorno della settimana in modo indipendente dall'uso che è stato effettuato durante la sua scrittura delle lettere maiuscole. Il numero dei confronti, in questo caso, risulta elevato. Si ricorre pertanto all'uso della parola chiave ElseIf, al fine di semplificare la struttura di controllo, che in tal modo risulta organizzata in un unico livello. Essa provvede alla modifica della variabile intera GiornoSettimana, che può assumere solamente due valori. Il primo, corrispondente al valore logico True, è assegnato nel caso in cui il confronto con uno dei nomi dei giorni della settimana abbia fornito un esito positivo. In caso contrario, la variabile prende il valore False. Tale dato è oggetto di valutazione nella seconda struttura If che visualizza, facendo uso di una label a cui è stato assegnato il nome lblRisultato, un messaggio indicante l'esito della verifica. Si noti che la condizione è rappresentata dalla sola variabile GiornoSettimana, a cui non è associato alcun operatore di confronto. Ciò a prima vista può lasciare sconcertati. In realtà, è perfettamente lecito, in quanto è noto che la condizione che regola una struttura If deve essere di tipo booleano, ovvero deve poter assumere esclusivamente i valori True o False. Proprio come la variabile GiornoSettimana.

La struttura Select Case L'esercizio precedente rappresenta un esempio di come una struttura If possa assumere dimensioni notevoli. In questi casi, la leggibilità del programma rischia di essere gravemente intaccata. Per evitare che questo accada, è possibile ricorrere ad una diversa struttura di controllo denominata Select Case, la cui sintassi è la seguente: Select Case <variabile> Case <valore 1>: <blocco istruzioni 1> [Case <valore 2>: <blocco istruzioni 2>] . . . [Case <valore n>: <blocco istruzioni n>] [Case Else: <istruzioni da eseguire se tutti i confronti falliscono>] End Select

La struttura Select Case è adatta ad essere utilizzata ogniqualvolta si desideri variare il flusso del programma in base al risultato del confronto fra il valore di una variabile e uno o più dati costanti. Ognuno di essi deve essere preceduto dalla parola chiave Case e seguito dai due punti, nonché dal gruppo di istruzioni da eseguire quando il confronto ha esisto positivo. Inoltre, è possibile utilizzare la clausola Case Else, che va obbligatoriamente posta alla fine della struttura, per definire un gruppo di istruzioni che deve essere eseguito file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

solo se tutti i confronti hanno ottenuto un esito negativo. La procedura che costituisce la soluzione del secondo esercizio può quindi essere riscritta nel modo seguente: Private Sub txtTestoDigitato_Change() Dim Testo as string Dim GiornoSettimana as integer Testo = Ucase(txtTestoDigitato.text) Select Case Testo Case "LUNEDI": GiornoSettimana = True Case "MARTEDI": GiornoSettimana = True Case "MERCOLEDI": GiornoSettimana = True Case "GIOVEDI": GiornoSettimana = True Case "VENERDI": GiornoSettimana = True Case "SABATO": GiornoSettimana = True Case "DOMENICA": GiornoSettimana = True Case Else GiornoSettimana = False End Select If GiornoSettimana Then lblRisultato.caption = "E' un giorno della settimana" Else lblRisultato.caption = "Non è un giorno della settimana" End If End Sub

Il codice risulta in questo caso più leggibile. Tuttavia, c'è spazio per un ulteriore miglioramento, grazie alla possibilità di utilizzare la virgola per separare i valori a cui devono essere fatte corrispondere sequenze analoghe di istruzioni. La struttura Select Case può quindi essere nuovamente riscritta in modo estremamente più sintetico: Select Case Testo Case "LUNEDI", "MARTEDI", "MERCOLEDI", "GIOVEDI", "VENERDI", "SABATO", "DOMENICA": GiornoSettimana = True Case Else GiornoSettimana = False End Select

È possibile pertanto notare come talvolta l'impiego della struttura Case possa agevolare notevolmente il compito del programmatore. Al fine di verificare ciò, si provi a realizzare un'applicazione che, ricevuto in ingresso un numero composto da una sola cifra, restituisca una stringa contenente l'indicazione dello stesso valore indicato in lettere.

Quando utilizzare la struttura Select Case

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

La struttura Select Case, potendo agire su una sola variabile per volta, presenta alcune limitazioni rispetto alla struttura If, in quanto non rende possibile l'esecuzione di valutazioni complesse. Si osservi il seguente esempio: If (valore1 = 2) Then Risultato = 5 ElseIf (valore2 = 3) Then Risulato = 7 End if

Non è possibile eseguire le stesse operazioni mediante una sola struttura Case. Ne sono necessarie due nidificate, come illustrato di seguito: Select Case Valore1 Case 2: Risultato = 5 Case Else: Select Case Valore2 Case 3: Risultato = 7 End Select End Select

La leggibilità del codice è in questo caso peggiorata. Inoltre, il numero delle righe digitate è aumentato. Da ciò appare evidente che l'uso della struttura Case non è sempre consigliabile. La sua opportunità deve essere valutata attentamente in fase di progettazione. Confronti Multipli Fino ad ora si è fatto uso della struttura di selezione multipla per confrontare il valore della variabile di controllo con alcuni dati costanti. In realtà, ci sono altre potenzialità nell'uso del costrutto Case che andiamo ora ad esplorare. L'uso della struttura Case per valutare l'appartenenza a degli intervalli di valori. Per mezzo della struttura Case diventa estremamente semplice valutare l'appartenenza del contenuto di una variabile a un intervallo di valori. Si supponga ad esempio di disporre di un form, caratterizzato anche questa volta dalla presenza di una label, denominata lblRisultato, di una casella di testo, a cui è assegnato il nome txtValore e di un pulsante avente la funzione di avviare l'elaborazione. Si ipotizzi di voler avvisare mediante la label quando il valore indicato nella textbox, presunto numerico, risulta compreso fra 1 e 10, oppure se appartiene all'intervallo avente per estremi 11 e 100. Supponendo che il pulsante sia denominato btnVerifica, è possibile digitare la procedura: Private Sub btnVerifica_Click() Dim Testo As String Dim Valore As Integer If IsNumeric(txtValore.Text) Then Valore = Val(txtValore.Text)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3) Select Case Valore Case 1 To 10: Testo = "E' compreso fra 1 e 10" Case 11 To 100: Testo = "E' compreso fra 11 e 100" Case Else: Testo = "Non appartiene agli intervalli" End Select Else Testo = "Non è un valore numerico" End If lblRisultato.Caption = Testo End Sub

Si noti l'uso della funzione IsNumeric atta a controllare che la stringa contenuta nella textbox, contenga effettivamente un numero (convertibile successivamente in un valore numerico per mezzo della funzione Val). Infatti, solo in questo caso sono effettuati i confronti. Altrimenti, si provvede a visualizzare nella label un opportuno messaggio di avviso. Questa volta, la struttura Select Case non fa riferimento a dei valori costanti, bensì a degli intervalli, ognuno dei quali è specificato per mezzo dei propri estremi, inframmezzati dalla parola chiave To. L'uso della struttura Case per valutare se un valore è superiore ad una data soglia. Si supponga di voler modificare l'esempio precedente per valutare se il valore inserito è superiore a 100. La struttura case deve essere modificata come segue: Select Case Valore Case 1 To 10: Testo = "E' compreso fra 1 e 10" Case 11 To 100: Testo = "E' compreso fra 11 e 100" Case Is > 100: Testo = "E' maggiore di 100" Case Else: Testo = "Non appartiene agli intervalli" End Select

Si noti l'introduzione della parola chiave Is, seguita da un'espressione di confronto. Se quest'ultima ha esito positivo, è eseguita l'istruzione associata. Gli operatori logici elementari Si ipotizzi di voler scrivere una struttura If per verificare se il valore di una variabile numerica intera, denominata Numero, appartiene all'intervallo compreso fra 10 e 100. È necessario valutare contemporaneamente due condizioni: il numero deve essere maggiore di 10 il numero deve essere inferiore a 100

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

Per far sì che sia prodotta una stringa indicante l'esito del confronto, occorre digitare il seguente codice: If Numero > 10 then If Numero < 100 then Testo = "Il numero è compreso fra 10 e 100" Else Testo = "Il numero non appartiene all'intervallo" End if End if

Si noti che l'uso della struttura Case avrebbe consentito la creazione di un listato più semplice e leggibile. È però possibile operare una semplificazione combinando i due confronti, ovvero creando un'unica espressione booleana in grado di stabilire l'appartenenza all'intervallo specificato. A tal fine, è necessario ricorrere agli operatori logici.

L'operatore And Spesso si rivela necessario valutare la contemporanea validità di due o più condizioni. È il caso dell'esempio precedente, in cui si desidera verificare se la variabile Numero contiene un valore maggiore di 10 e nel contempo minore di 100. L'operatore And assolve questo compito, restituendo il valore logico True solo se le condizioni a cui è applicato sono contemporaneamente verificate. Il codice può pertanto essere riscritto come segue: If (Numero > 10) And (Numero < 100) Then Testo = "Il numero è compreso fra 10 e 100" Else Testo = "Il numero non appartiene all'intervallo" End if

Come è possibile notare, la struttura risulta più semplice, in quanto composta da un solo livello. L'operatore Or A differenza del precedente, l'operatore Or restituisce il valore logico True se almeno una delle condizioni specificate è vera. Ad esempio, la condizione (Numero = 5) Or (Numero > 11)

è verificata quando la variabile Numero assume un valore maggiore di 11 o uguale a 5.

L'operatore Not Un altro utile operatore logico è quello di negazione (Not). Come è facile dedurre, esso restituisce il valore True se la condizione a cui è

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

applicato non è verificata, mentre restituisce False in caso contrario. A titolo di esempio, si supponga di voler realizzare una struttura If in grado di generare una stringa indicate se il valore della variabile Numero risulta contemporaneamente diverso da 5 e da 10. Il codice da digitare è il seguente: If Not ((Numero = 5) Or (Numero = 10)) Then Testo = "Il numero è diverso da 5 e da 10" End if

Si osservi la condizione. Essa risulta dalla combinazione di due confronti. Si tratta di Numero = 5

e Numero = 10

L'uso dell'operatore OR permette di verificare se almeno uno di essi ha esito positivo. In tal caso, non deve essere fornita alcuna indicazione. La stringa deve essere creata, infatti, solo quando entrambi i confronti hanno esito negativo, ovvero quando l'espressione (Numero = 5) Or (Numero = 10)

restituisce il valore False, ovvero quando è verificata la condizione: Not ((Numero = 5) Or (Numero = 10))

Come esercizio, si provi a realizzare un programma che riceva in ingresso una stringa contenente il nome di un mese e restituisca il numero dei giorni di cui esso si compone. Si preveda la possibilità di specificare l'anno a cui fare riferimento, al fine di offrire una corretta indicazione della lunghezza del mese di febbraio anche negli anni bisestili.

Conclusioni Lo studio della struttura Select Case ha completato la panoramica sulle strutture di controllo iniziata nello scorso numero. Tali istruzioni ricoprono un ruolo fondamentale nella quasi totalità delle applicazioni. La loro conoscenza è inoltre indispensabile per la comprensione degli argomenti che verranno trattati nelle prossime puntate di questo corso. Al lettore va pertanto l'invito ad esercitarsi sui concetti illustrati e a non trascurare gli esercizi proposti. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


Maurizio Crespi - Corso di Visual Basic (Parte 3)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb03/index.htm[26/09/2010 12:58:05]


La soluzione del primo esercizio

Figura 1 La soluzione del primo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb03/fig1.htm[26/09/2010 12:59:13]


La soluzione del secondo esercizio

Figura 2 La soluzione del secondo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb03/fig2.htm[26/09/2010 12:59:35]


Il programma per determinare l'appartenenza di un numero a degli intervalli

Figura 3 Il programma per determinare l'appartenenza di un numero a degli intervalli

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb03/fig3.htm[26/09/2010 12:59:43]


L'ambiente di sviluppo di Visual Basic 5

Figura 4 L'ambiente di sviluppo di Visual Basic 5

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb03/fig4.htm[26/09/2010 12:59:52]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

Corso di

Corso di Visual Basic (Parte 4)

Visual Basic

Le soluzioni degli esercizi dello scorso numero Il ciclo For Cicli nidificati

(Parte 4)

Le funzioni Len e Mid$ Cicli con decremento Conclusioni

di Maurizio Crespi

Figure Figura 1 Figura 2 Figura 3 Figura 4

(c) 1997, Edizioni Infomedia srl

Oggetto di studio della quarta puntata del corso dedicato alla programmazione in Visual Basic sono i cicli e in particolare la struttura For, mediante la quale è possibile far eseguire al calcolatore delle operazioni ripetitive Uno dei punti di forza dei calcolatori è rappresentato dalla possibilità di eseguire in modo estremamente veloce delle operazioni ripetitive. A tal fine, i linguaggi di programmazione mettono a disposizione delle strutture che prendono il nome di cicli. Naturalmente, Visual Basic non si sottrae a questa regola. La prima struttura ad essere presa in esame è rappresentata dal ciclo For, a cui è dedicata questa lezione.

Le soluzioni degli esercizi dello scorso numero Come sempre, prima di procedere allo studio dei nuovi argomenti, saranno illustrate le soluzioni degli esercizi proposti nello scorso numero. Primo esercizio Il primo esercizio prevede la realizzazione di un programma in grado di leggere un numero composto da una sola cifra e di offrire come risultato la sua indicazione in lettere. Si tratta di una tipica applicazione della struttura Select Case, che opera una scelta fra dieci valori. Come interfaccia utente si fa uso di un form costituito da una textbox, denominata txtCifra, a cui è affidata la ricezione dei dati in ingresso. Il risultato è restituito per mezzo della label lblMessaggio, che deve essere aggiornata ogniqualvolta la cifra in ingresso subisca una variazione, ovvero in corrispondenza del verificarsi dell'evento change sulla textbox. La gestione di quest'ultimo è possibile per mezzo della seguente procedura: Private Sub txtCifra_Change() Dim Cifra As Integer Dim DatoIngresso As String DatoIngresso = txtCifra.Text If IsNumeric(DatoIngresso) Then Cifra = Val(DatoIngresso) Select Case Cifra Case 0

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4) lblMessaggio.Caption = "ZERO" Case 1 lblMessaggio.Caption = "UNO" Case 2 lblMessaggio.Caption = "DUE" Case 3 lblMessaggio.Caption = "TRE" Case 4 lblMessaggio.Caption = "QUATTRO" Case 5 lblMessaggio.Caption = "CINQUE" Case 6 lblMessaggio.Caption = "SEI" Case 7 lblMessaggio.Caption = "SETTE" Case 8 lblMessaggio.Caption = "OTTO" Case 9 lblMessaggio.Caption = "NOVE" Case Else lblMessaggio.Caption = "Il numero non è composto da una sola cifra" End Select Else lblMessaggio.Caption = "Dato non numerico" End If End Sub

La prima operazione effettuata consiste nella lettura del dato in ingresso attraverso la textbox. Se esso risulta convertibile in un numero, ovvero se la funzione IsNumeric restituisce il valore logico True, il dato è copiato nella variabile intera Cifra ed è utilizzato per controllare la struttura Select Case, che provvede ad effettuare i confronti necessari per verificare l'uguaglianza con i numeri compresi fra 0 e 9 ed a visualizzare la stringa corretta mediante la label. Secondo esercizio Il secondo esercizio prevede la creazione di un programma che, ricevendo in ingresso il nome di un mese, sia in grado di indicarne il numero dei giorni in un anno specificato. La soluzione comporta nuovamente l'uso della struttura Select Case. Per l'acquisizione dei dati si provvede, come di consueto, ad utilizzare delle caselle di testo, denominate txtMese e txtAnno. Il risultato è visualizzato in seguito alla pressione di un pulsante per mezzo della label lblMessaggio. Dopo aver creato un form ed aver posto su di essi gli oggetti grafici, è possibile implementare la procedura destinata al calcolo. Supponendo che al tasto sia assegnato il nome btnCalcola, si può scrivere: Private Sub btnCalcola_Click() Dim Anno As Integer Dim Giorni As Integer Dim Mese As String Anno = Val(txtAnno.Text) Mese = UCase(txtMese.Text) Select Case Mese

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4) Case "GENNAIO", "MARZO", "MAGGIO", "LUGLIO", "AGOSTO", "OTTOBRE", "DICEMBRE": Giorni = 31 Case "APRILE", "GIUGNO", "SETTEMBRE", "NOVEMBRE": Giorni = 30 Case "FEBBRAIO": If ((Anno Mod 4) = 0) And ((Anno Mod 100) <> 0) Then Giorni = 29 Else Giorni = 28 End If Case Else Giorni = 0 End Select If Giorni > 0 Then lblMessaggio.Caption = "Numero giorni :" & Giorni Else lblMessaggio.Caption = "Mese non corretto" End If End Sub

La struttura di selezione è controllata dalla variabile Mese, il cui contenuto è opportunamente convertito in maiuscolo per mezzo della funzione UCase e confrontato con i nomi dei mesi, anch'essi composti solo da lettere maiuscole. Ciò fa sì che il confronto non sia case sensitive. Si noti, che nel caso in cui il mese selezionato sia febbraio, è eseguito un ulteriore controllo per verificare se l'anno è bisestile. Tale verifica è effettuata testando la contemporanea validità di due condizioni, ovvero la divisibilità dell'anno per quattro e la non divisibilità per cento. La condizione risulta vera se entrambi i resti delle divisioni, calcolati per mezzo della funzione Mod, sono nulli. Si ricorre pertanto all'operatore logico And, in grado di restituire il valore True solo in caso di contemporanea verifica delle condizioni che ne costituiscono gli operandi.

Il ciclo For Si supponga di voler realizzare un programma in grado di calcolare il fattoriale di un numero, ovvero il prodotto di tutti i valori interi positivi minori o uguali ad esso. Gli strumenti illustrati nelle puntate precedenti di questo corso non si rivelano sufficienti a tal fine, in quanto è necessaria la capacità di ripetere per un numero variabile di volte l'operazione di moltiplicazione. Si impone pertanto il ricorso alle strutture di iterazione. Nel caso dell'esempio, occorre applicare la moltiplicazione a tutti i numeri naturali minori o uguali a quello di cui si desidera calcolare il fattoriale. Appare così evidente la necessità di disporre di una struttura in grado di permettere la ripetizione di una porzione di codice per un numero finito di volte; si tratta della classica struttura For, che nel caso di Visual Basic è caratterizzata dalla seguente sintassi: For <contatore> = <valore iniziale> To <valore finale> [Step <passo>] <istruzione 1>

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4) ... <istruzione n> Next [<contatore>]

Dopo la parola chiave For è necessario far seguire una variabile intera, che funge da contatore. Il suo valore è incrementato ad ogni ripetizione di un numero di unità pari a quello specificato dopo la parola chiave Step, fino al raggiungimento del valore finale; questa condizione determina la fine delle iterazioni e il passaggio all'istruzione seguente la parola riservata Next. Volendo quindi realizzare un'applicazione in grado di calcolare il fattoriale di un numero, occorre creare un form ed inserire su di esso una textbox, usata per leggere il dato in ingresso, una label, destinata ad accogliere il risultato e un pulsante, a cui è affidato il compito di avviare il calcolo. Alla pressione di quest'ultimo deve essere associata la seguente procedura: Private Sub btnCalcola_Click() Dim Contatore As Integer Dim Fattoriale As Integer Dim Numero As Integer If IsNumeric(txtNumero.Text) Then Numero = Val(txtNumero.Text) If Numero >= 0 Then Fattoriale = 1 For Contatore = 1 To Numero Fattoriale = Fattoriale * Contatore Next Contatore lblRisultato.Caption = Fattoriale Else lblRisultato.Caption = "Errore: valore negativo" End If Else lblRisultato.Caption = "Errore: dato non numerico" End If End Sub

Essa dapprima verifica che nella textbox txtNumero sia presente un dato numerico. In tal caso, quest'ultimo è assegnato alla variabile Numero dopo la necessaria conversione per mezzo della funzione Val. Tale valore è quindi oggetto di un secondo controllo volto a verificarne la positività. La funzione fattoriale, infatti, non è definita per i numeri negativi e vale 1 se il dato in ingresso è nullo. Successivamente, la procedura provvede ad effettuare le moltiplicazioni. A tal fine fa uso di un ciclo For, avente come valore iniziale 1 e come valore finale il numero di cui si desidera calcolare il fattoriale. Si noti che è stata omessa la parola chiave Step. In questo caso, il passo adottato è quello predefinito, cioè 1. All'interno della struttura è presente una sola riga di codice, che ha il fine di moltiplicare il contenuto della variabile Fattoriale per il valore assunto dal contatore. La sua ripetizione per tutti i valori compresi fra 1 e il numero fornito in ingresso fa sì che alla fine del ciclo la variabile Fattoriale contenga il risultato desiderato, che può essere visualizzato per mezzo della label. Si noti ciò che avviene se in ingresso è fornito il numero 0. La variabile Fattoriale è comunque inizializzata al valore 1. L'istruzione all'interno del ciclo, invece, non è mai eseguita. Infatti, come si è detto in precedenza, la ripetizione termina quando il contatore file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

raggiunge il valore finale. In questo caso, la condizione è immediatamente soddisfatta, per cui non si verificano iterazioni. Esercizio Per esercitarsi sull'uso della struttura For, si provi a realizzare un programma che, dato in ingresso un numero intero, visualizzi la somma di tutti i numeri naturali pari minori o uguali ad esso.

Cicli nidificati Si supponga ora di voler modificare l'applicazione dell'esempio precedente per fare in modo che fornisca all'utente la somma dei fattoriali dei primi n numeri interi positivi, dove n rappresenta il dato in ingresso acquisito mediante la casella di testo txtNumero. Per il calcolo del fattoriale è necessario ricorrere nuovamente a un ciclo, che è sostanzialmente identico a quello visto in precedenza. Tale operazione deve essere però ripetuta per tutti i numeri naturali minori o uguali al dato n fornito dall'utente, ovvero per tutti i valori interi compresi fra 1 e n. Si impone pertanto l'uso di un ulteriore ciclo, che deve risultare più esterno rispetto al precedente. Al pulsante btnCalcola si può quindi associare la seguente procedura: Private Sub btnCalcola_Click() Dim Contatore As Integer Dim Fattoriale As Integer Dim n As Integer Dim Risultato As Long If IsNumeric(txtNumero.Text) Then n = Val(txtNumero.Text) If n > 0 Then Risultato = 0 For Contatore1 = 1 To n Fattoriale = 1 For Contatore2 = 1 To Contatore1 Fattoriale = Fattoriale * Contatore2 Next Contatore2 Risultato = Risultato + Fattoriale Next Contatore1 lblRisultato.Caption = Risultato Else lblRisultato.Caption = "Errore: valore negativo o nullo" End If Else lblRisultato.Caption = "Errore: dato non numerico" End If End Sub

Anche questa volta è per prima cosa eseguito un controllo della validità del dato digitato dall'utente. Se si tratta di un numero intero

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

positivo, la procedura provvede ad avviare il calcolo, dopo aver posto a zero il valore della variabile Risultato. Si noti che tale operazione non è in realtà necessaria, in quanto Visual Basic provvede automaticamente ad azzerare le variabili intere in fase di creazione. La sua presenza, però, contribuisce a rendere leggibile il codice, soprattutto a coloro che sono abituati all'uso di altri linguaggi che non presentano questa caratteristica. Si osservino ora i due cicli nidificati. La variabile usata come contatore in quello più esterno funge da valore finale nel ciclo interno. Ad ogni iterazione è pertanto calcolato il fattoriale del numero contenuto nella variabile Contatore1. Tale valore va ad incrementare quello della variabile Risultato, che alla fine è visualizzato mediante la label. Allo scopo di mantenere una buona leggibilità del codice, è necessario fare in modo che alle istruzioni che si trovano all'interno di un ciclo sia associato un rientro sinistro maggiore. In tal modo risulta semplice riconoscere l'inizio e la fine della struttura. Tale necessità è ancora più evidente allorquando vi siano più cicli nidificati. Per lo stesso motivo, sebbene sia possibile farne a meno, è preferibile far seguire ogni parola chiave Next dal nome della variabile di conteggio che caratterizza il ciclo. In caso di omissione, l'interprete comunque assume che la struttura da delimitare sia quella posta nel blocco più interno.

Le funzioni Len e Mid$ Si supponga di voler scrivere un programma che sia in grado di invertire una stringa fornita in ingresso. Per la sua realizzazione occorre far uso di due funzioni specifiche per il trattamento dei dati alfanumerici. Si tratta della funzione Len, che restituisce la lunghezza della stringa passatale come parametro e della più complessa funzione Mid$. Quest'ultima permette di estrarre da una stringa una sequenza composta da un dato numero di caratteri consecutivi. La sua sintassi è la seguente: <risultato> = Mid$(<stringa>, <posizione>, [<numero caratteri>])

I parametri rappresentano rispettivamente la stringa fornita in ingresso, la posizione del primo carattere da estrarre e il numero dei caratteri oggetto dell'operazione. Si noti che quest'ultimo è facoltativo. In sua assenza, è restituita tutta la porzione della stringa compresa fra la posizione indicata e il carattere posto all'estrema destra. Ad esempio, la riga A$ = Mid$("Developing Software Solutions", 12, 8)

Assegna alla variabile A$ la stringa "Software". Scrivendo invece A$ = Mid$("Developing Software Solutions", 12)

si provoca l'assegnamento della sequenza alfanumerica "Software Solutions". Cicli con decremento Ora si dispone dei mezzi necessari per la realizzazione dell'applicazione in grado di invertire una stringa. Supponendo di file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

utilizzare un form analogo a quello degli esempi precedenti, caratterizzato da una textbox destinata all'acquisizione dei dati in ingresso, denominata txtStringa, dalla label lblRisultato, utilizzata per visualizzare la stringa risultante e dal pulsante btnInverti, che ha lo scopo di provocare l'inversione della sequenza, la procedura da associare ad esso è la seguente: Private Sub btnInverti_Click() Dim i As Integer Dim Lunghezza As Integer Dim Risultato As String Dim Carattere As String * 1 Lunghezza = Len(txtStringa.Text) Risultato = "" For i = Lunghezza To 1 Step -1 Carattere = Mid$(txtStringa.Text, i, 1) Risultato = Risultato + Carattere Next i lblRisultato.Caption = Risultato End Sub

Si fa uso della funzione Len per calcolare la lunghezza della stringa digitata dall'utente. Il valore restituito determina la posizione del primo carattere che deve essere aggiunto alla variabile Risultato. Esso rappresenta pertanto il valore di partenza in un ciclo For caratterizzato da un decremento, ovvero da un passo di segno negativo. Questa volta, quindi, il valore iniziale risulta maggiore di quello finale e le iterazioni terminano quando è raggiunto il valore minimo, nella fattispecie 1. La funzione Mid$ è utilizzata per estrarre il carattere posto nella posizione indicata dal contatore. Si noti che la variabile atta a contenerlo è di tipo stringa ed è stata dichiarata di dimensione pari a un elemento per mezzo della riga Dim Carattere As String*1

Visual Basic, infatti, a differenza di molti altri linguaggi di programmazione, non dispone di un tipo di dati idoneo alla memorizzazione dei singoli caratteri. Per ovviare a questo inconveniente, è necessario ricorrere ad una stringa di dimensione pari ad un'unità, come in questo esempio. Per mezzo dell'operatore di concatenazione (+), ogni carattere estratto è aggiunto in coda al contenuto della variabile Risultato, che al termine delle iterazioni contiene la stringa invertita. Quest'ultima può essere quindi assegnata alla proprietà Caption della label lblRisultato per essere visualizzata. Esercizio Per esercitarsi sui concetti esposti, si provi a realizzare un programma che, ricevuto in ingresso un numero intero positivo, sia in grado di restituire il maggior numero naturale per cui esso è divisibile.

Conclusioni Il ciclo For è estremamente usato in ogni applicazione. Esso non rappresenta però l'unica struttura di iterazione. Ne esistono delle file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

altre, che saranno oggetto di studio nella prossima lezione. Per comprendere il loro funzionamento è necessario aver assimilato quanto esposto in questa trattazione. Al lettore è pertanto rivolto il consueto invito ad esercitarsi nell'applicazione dei concetti illustrati. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Maurizio Crespi - Corso di Visual Basic (Parte 4)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb04/index.htm[26/09/2010 1:02:21]


Figura 1

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb04/fig1.htm[26/09/2010 1:03:01]


Figura 2

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb04/fig2.htm[26/09/2010 1:03:08]


Figura 3

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb04/fig3.htm[26/09/2010 1:03:17]


Figura 4

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb04/fig4.htm[26/09/2010 1:03:26]


Maurizio Crespi - Corso di Visual Basic (Parte V)

Corso di Visual Basic

Corso di Visual Basic (Parte V)

(Parte V)

Le soluzioni degli esercizi dello scorso numero Come ormai consuetudine, la prima parte della lezione è dedicata alla correzione degli esercizi proposti nello scorso numero.

di Maurizio Crespi

Primo esercizio Il comando Exit For Il ciclo While Le parole chiave Do e Loop Il ciclo Do Until Ripetizione di un blocco di istruzioni per almeno una volta Conclusioni Figure Figura 1 Figura 2 Figura 3

(c) 1997, Edizioni Infomedia srl

Oggetto di studio della quinta parte del corso dedicato alla programmazione in Visual Basic sono ancora i cicli. Questa volta l'obbiettivo è puntato sull'uso delle strutture regolate da una condizione booleana La necessità di poter eseguire ripetitivamente un gruppo di istruzioni è sentita durante la stesura di pressoché qualsiasi applicazione non banale. Per questo motivo, tutti gli strumenti di sviluppo prevedono il supporto per le strutture di iterazione. Dopo aver soffermato l'attenzione sulla struttura For, si procederà ora a studiare l'uso dei cicli basati sulla parola chiave Do, che permettono di legare il numero delle ripetizioni non più al valore assunto da un contatore, bensì al verificarsi di una condizione logica. Le soluzioni degli esercizi dello scorso numero Come ormai consuetudine, la prima parte della lezione è dedicata alla correzione degli esercizi proposti nello scorso numero. Primo esercizio Il primo esercizio prevede la realizzazione di un programma che, dato in ingresso un numero intero, visualizzi la somma di tutti i numeri naturali pari minori o uguali ad esso. Dopo aver disegnato un form dotato di una casella di testo, a cui può essere assegnato il nome txtNumero, di una label (lblRisultato) e di un pulsante (btnCalcola), è possibile scrivere la procedura da associare alla pressione di quest'ultimo: Private Sub btnCalcola_Click() Dim Numero As Integer Dim Contatore As Integer Dim Somma As Long Numero = Val(txtNumero.text) If Numero > 0 Then Somma = 0 For Contatore = 2 To Numero Step 2 Somma = Somma + Contatore Next Contatore

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

lblRisultato.Caption = Somma Else lblRisultato.Caption = "Numero negativo o nullo" End If End Sub Il suo scopo è di trasformare in un dato numerico la stringa posta nella casella di testo e, se tale valore risulta positivo, di creare un ciclo per calcolare tutti i numeri interi pari minori ad esso. A tal fine fa uso di una struttura For avente come valore iniziale 2, ovvero il più piccolo numero pari, e come passo ancora 2. In tal modo, sono esclusi dal conteggio i valori dispari, cioè non multipli di 2. Il limite massimo è rappresentato dal numero fornito dall'utente. Si noti che, nel caso in cui quest'ultimo sia dispari, la struttura fa sì che il contatore assuma in realtà un valore massimo inferiore di un'unità rispetto a quello indicato. Tutti i valori assunti dal contatore sono aggiunti alla variabile Somma, che al termine delle iterazioni contiene il risultato desiderato. Secondo esercizio Il secondo esercizio richiede la creazione di un programma che, dato in ingresso un numero intero positivo, restituisca il più grande numero naturale per cui esso è divisibile. Supponendo di riutilizzare il form descritto in precedenza, è possibile associare al pulsante la seguente procedura: Private Sub btnCalcola_click() Dim Contatore As Integer Dim Divisore As Integer Dim Numero As Double Numero = Val(txtNumero.Text) If Numero > 0 Then If Numero = Int(Numero) Then Divisore = 1 For Contatore = 2 To (Numero - 1) If (Numero Mod Contatore) = 0 Then Divisore = Contatore End If Next Contatore lblRisultato.Caption = Divisore Else lblRisultato.Caption = "Numero non intero" End If file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

Else lblRisultato.Caption = "Numero negativo o nullo" End If End Sub Si fa ancora uso di un ciclo For in cui il contatore è inizializzato a 2 (è superfluo verificare la divisibilità per 1). Il valore finale è pari al numero diminuito di un'unità. Al il programma accede solo se il dato fornito dall'utente, memorizzato nella variabile Numero, risulta intero positivo. Ad ogni iterazione, si fa uso dell'operatore Mod per verificare se il numero fornito in ingresso è divisibile per il valore della variabile Contatore. In caso affermativo, quest'ultimo è memorizzato nella variabile Divisore che, completato il ciclo, contiene il risultato desiderato. Il comando Exit For Si noti che, con la procedura sopra descritta, il numero delle ripetizioni aumenta all'aumentare del valore fornito in ingresso dall'utente. L'applicazione di tale algoritmo a un numero molto grande potrebbe pertanto causare, almeno in linea di principio, dei problemi di prestazioni. E' possibile scrivere una procedura più efficiente realizzando un ciclo con decremento. In questo caso, la struttura For ha come valore iniziale il dato fornito in ingresso diminuito di un'unità. Private Sub btnCalcola_click() Dim Contatore As Integer Dim Divisore As Integer Dim Numero As Double Numero = Val(txtNumero.Text) If Numero > 0 Then If Numero = Int(Numero) Then Divisore = Numero For Contatore = (Numero - 1) To 1 Step -1 If (Numero Mod Contatore) = 0 Then Divisore = Contatore Exit For End If Next Contatore lblRisultato.Caption = Divisore Else lblRisultato.Caption = "Numero non intero"

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

End If Else lblRisultato.Caption = "Numero negativo o nullo" End If End Sub Ad ogni iterazione è effettuato un controllo atto a stabilire se il contenuto della variabile Contatore è in grado di dividere il numero fornito dall'utente. Il primo valore di cui è rilevata la capacità di soddisfare questa condizione è sicuramente il maggior divisore. Una volta trovatolo, è pertanto inutile proseguire con le iterazioni. Per provocare l'uscita prematura dal ciclo, si fa uso del comando Exit For. In questo caso, il numero delle ripetizioni è quello strettamente necessario. Il vantaggio in termini di efficienza può essere notevole. E' tuttavia importante non abusare dell'uso di questo comando, in quanto ha influenza negativa sulla leggibilità del codice. Il ciclo While Una soluzione più elegante prevede l'uso del ciclo While, che permette la ripetizione di un segmento di codice per tutto il tempo in cui una condizione risulta vera. La sua sintassi è la seguente: While <condizione> <istruzione 1> <istruzione 2> ... <istruzione n> Wend Le istruzioni comprese fra le parole chiave While e Wend sono ripetute per un numero di volte non stabilito rigidamente a priori, bensì dipendente dalle stesse istruzioni, che devono essere in grado di fare in modo che la condizione ad un certo punto smetta di verificarsi. In caso contrario, si incappa in un errore molto diffuso fra i programmatori alle prime armi, ovvero si crea ciò che è usualmente detto ciclo infinito. Gli effetti di un'iterazione senza fine sono evidenti. Il programma di fatto si blocca e per terminarlo occorre far ricorso al task manager del sistema operativo. La procedura che costituisce la soluzione del secondo esercizio può essere riscritta utilizzando la struttura While nel modo seguente: Private Sub btnCalcola_click() Dim Contatore As Integer Dim Divisore As Integer Dim Numero As Double Numero = Val(txtNumero.Text) file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

If Numero > 0 Then If Numero = Int(Numero) Then Contatore = Numero - 1 While (Numero Mod Contatore) <> 0 Contatore = Contatore - 1 Wend lblRisultato.Caption = Contatore Else lblRisultato.Caption = "Numero non intero" End If Else lblRisultato.Caption = "Numero negativo o nullo" End If End Sub Il suo funzionamento è estremamente semplice: un contatore è inizializzato al massimo numero intero inferiore al dato fornito in ingresso ed è decrementato all'interno del ciclo più volte per tutto il tempo che il resto della divisione per il contatore del numero digitato dall'utente si mantiene diverso da zero. Quando il resto si annulla, ovvero quando la variabile Contatore contiene il divisore desiderato, la condizione (Numero Mod Contatore)<>0 diventa falsa e le iterazioni terminano. Il risultato può quindi essere visualizzato per mezzo dell'apposita label. Si noti che il ciclo non può mai essere infinito. La condizione infatti assume sicuramente un valore falso quando la variabile Contatore vale 1. Le parole chiave Do e Loop Il ciclo While può anche essere descritto in modo più elegante per mezzo delle parole chiave Do e Loop. In questo caso la sintassi diventa: Do While <condizione> <istruzione 1> <istruzione 2> ... <istruzione n> Loop Il comportamento è analogo a quello visto in precedenza: le istruzioni

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

contenute all'interno della struttura sono ripetute fintanto che la condizione indicata accanto alla parola While si verifica. La procedura dell'esempio precedente può quindi essere riscritta come segue: Private Sub btnCalcola_click() Dim Contatore As Integer Dim Divisore As Integer Dim Numero As Double Numero = Val(txtNumero.Text) If Numero > 0 Then If Numero = Int(Numero) Then Contatore = Numero - 1 Do While (Numero Mod Contatore) <> 0 Contatore = Contatore - 1 Loop lblRisultato.Caption = Contatore Else lblRisultato.Caption = "Numero non intero" End If Else lblRisultato.Caption = "Numero negativo o nullo" End If End Sub Il ciclo Do Until Pressoché analogo è il ciclo Do Until, caratterizzato dalla seguente sintassi: Do Until <condizione> <istruzione 1> <istruzione 2> ... <istruzione n> Loop In questo caso, le iterazioni avvengono quando la condizione è falsa e terminano quando essa si avvera. Il ciclo su cui si basa la soluzione del secondo esercizio può essere riscritto utilizzando la struttura Do Until nel modo seguente:

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

Do Until (Numero Mod Contatore) = 0 Contatore = Contatore - 1 Loop Si noti che l'uso di questa struttura in alternativa alla precedente non presenta dei vantaggi significativi. La scelta può pertanto essere effettuata caso per caso in base alla comprensibilità del codice e alle proprie preferenze personali. Si consideri ora il seguente esempio. Si desidera realizzare un programma che, ricevendo in ingresso due stringhe, sia in grado di indicare la posizione in cui la seconda è eventualmente contenuta nella prima. In pratica, si tratta di realizzare una procedura in grado di simulare il comportamento della funzione Instr. Per prima cosa si provvede a disegnare un form dotato di due caselle di testo, a cui è possibile dare i nomi txtStringa e txtDaCercare, e di un pulsante, a cui è dato il nome btnCerca. Ad esso è possibile associare la procedura che effettua la ricerca di una stringa nell'altra. Il codice è il seguente: Private Sub btnCerca_click() Dim Stringa As String Dim DaCercare As String Dim LunghStringa As Integer Dim LunghDaCercare As Integer Dim Posizione As Integer Dim Trovato As Boolean Stringa = txtStringa.Text DaCercare = txtDaCercare.Text LunghStringa = Len(Stringa) LunghDaCercare = Len(DaCercare) Posizione = 0 Trovato = False Do Until Trovato Or (Posizione + LunghDaCercare) > LunghStringa Posizione = Posizione + 1 Trovato = (Mid$(Stringa, Posizione, LunghDaCercare) = DaCercare) Loop If Trovato Then lblMessaggio.Caption = "Posizione = " & Str$(Posizione)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

Else lblMessaggio.Caption = "Stringa non trovata" End If End Sub La procedura dapprima calcola la lunghezza della stringa da cercare, poi estrae tutte le possibili sequenze di tale dimensione dal testo posto nella casella txtStringa. Il processo termina quando è estratta una sequenza uguale a quella oggetto di ricerca; in questo caso la variabile Trovato, contenente il risultato del confronto, assume il valore logico True. La condizione Trovato Or (Posizione + LunghDaCercare) > LunghStringa pertanto si verifica e il ciclo si conclude. La variabile Posizione, usata come contatore, contiene allora la posizione in cui la sequenza è stata localizzata. L'informazione in essa contenuta rappresenta il dato che il programma deve visualizzare per mezzo della label. Come si può facilmente notare, le iterazioni possono terminare anche quando il numero dei caratteri presenti nella stringa a partire dalla posizione indicata dal contatore risulta inferiore alla lunghezza della sequenza da cercare. In questo caso, il ciclo termina senza che sia stata trovata alcuna occorrenza; tale eventualità provoca la visualizzazione di un opportuno messaggio di avviso per mezzo della label. Si noti che se la stringa da cercare ha lunghezza inferiore a quella entro cui deve essere effettuata la ricerca, le istruzioni poste all'interno del ciclo non sono mai eseguite. Esercizio Si provi a realizzare un'applicazione che, ricevuta in ingresso una stringa alfabetica, indichi la posizione in essa occupata dalla prima lettera maiuscola, se presente. Ripetizione di un blocco di istruzioni per almeno una volta Spesso si rivela utile poter fare in modo che, indipendentemente dal verificarsi della condizione che regola il ciclo, il blocco di istruzioni in esso contenuto sia eseguito almeno una volta. Ad esempio, si supponga di voler realizzare un'applicazione in grado di estrarre a sorte dei numeri compresi fra 1 e 10 mentre la loro somma si mantiene inferiore a 15. A tal fine si utilizza la funzione Rnd, che restituisce un numero pseudocasuale (ovvero generato in modo da sembrare estratto a sorte) compreso fra 0 e 1. E' evidente che almeno una volta deve essere effettuata l'estrazione di un numero. Per fare in modo che ciò avvenga, è possibile posizionare la condizione che regola il ciclo alla fine di esso anziché all'inizio. In questo caso la sintassi diventa: Do <istruzione 1> <istruzione 2>

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

... <istruzione n> Loop Until <condizione> Per consentire all'estrazione di avere inizio in seguito alla pressione del pulsante btnEstrai e per far sì che i numeri generati siano visualizzati in una textbox, denominata txtNumeri, è necessario scrivere la seguente procedura: Private Sub btnEstrai_Click() Dim Somma As Integer Dim Numero As Integer Randomize Somma = 0 txtNumeri.Text = "" Do Numero = Int(10 * Rnd) + 1 Somma = Somma + Numero txtNumeri.Text = txtNumeri.Text + Str$(Numero) + "-" Loop Until Somma > 15 End Sub Il ciclo provvede a calcolare un numero casuale compreso fra 1 e 10 per mezzo della funzione Rnd, moltiplicando il valore da essa restituito per 10, estraendone la parte intera e sommando il valore 1. Siccome, come già accennato in precedenza, la funzione restituisce un numero decimale maggiore o uguale a 0 e minore di 1, la parte intera del prodotto risulta compresa fra 0 e 9. Per fare in modo che alla variabile Numero sia assegnato un valore compreso fra 1 e 10 occorre pertanto aggiungere un'unità. Il valore ottenuto è aggiunto alla variabile Somma. I numeri sono visualizzati, separati da un trattino, nella textbox txtNumeri. Le iterazioni terminano quando il valore della variabile Somma diventa maggiore di 15. Si noti l'uso dell'istruzione Randomize all'inizio della procedura. Esso ha lo scopo di inizializzare il generatore di numeri pseudocasuali. In assenza di tale operazione, i valori generati sarebbero sempre gli stessi ogni volta che è lanciato il programma. Anche quando la condizione è posta alla fine del ciclo è possibile sostituire la parola chiave Until con While. In questo caso, le iterazioni avvengono fintanto che si verifica la condizione indicata. Esercizio Per valutare la propria comprensione degli argomenti trattati, si realizzi un'applicazione che, ricevendo in ingresso una stringa per

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

mezzo di una textbox, restituisca la lunghezza della prima parola in essa contenuta. Conclusioni I calcolatori sono nati allo scopo di agevolare l'utente nello svolgimento delle operazioni ripetitive. Per questo motivo, le strutture che permettono di eseguire delle iterazioni rivestono una notevole importanza, tale da rendere la loro conoscenza imprescindibile per qualsiasi programmatore. Ancora una volta, pertanto, è rivolto al lettore l'invito ad esercitarsi per acquisire la necessaria dimestichezza con i concetti esposti. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


Maurizio Crespi - Corso di Visual Basic (Parte V)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb05/index.htm[26/09/2010 1:04:47]


La soluzione del primo esercizio

Figura 1 La soluzione del primo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb05/fig1.htm[26/09/2010 1:05:00]


L'applicazione che ricerca una stringa in un'altra

Figura 2 L'applicazione che ricerca una stringa in un'altra

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb05/fig2.htm[26/09/2010 1:05:07]


L'applicazione che genera numeri pseudocasuali

Figura 3 L'applicazione che genera numeri pseudocasuali

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb05/fig3.htm[26/09/2010 1:05:13]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Corso di Visual Basic (Parte 6)

Corso di Visual Basic (Parte 6) di Maurizio Crespi

Le soluzioni degli esercizi della lezione precedente Perché servono i vettori I vettori L'ordinamento per selezione diretta

Nella sesta parte, il corso dedicato alla programmazione in ambiente Microsoft Visual Basic punta il proprio obbiettivo su delle strutture dati di importanza fondamentale: i vettori.

La fortuna dei calcolatori si deve alla capacità di effettuare in breve tempo delle operazioni ripetitive su una grande quantità di informazioni. Fino ad ora, in questo corso, i dati da elaborare sono sempre stati considerati contenuti all'interno di comuni variabili. Figure Quando tuttavia il numero dei valori da gestire diventa elevato, esse si rivelano Figura 1 inadeguate a soddisfare le esigenze del programmatore. Lo scopo della lezione consiste Figura 2 nell'introdurre il concetto di vettore e di dimostrare quanto una struttura di questo tipo Figura 3 possa agevolare il compito dello sviluppatore in presenza di un'elevata mole di dati di tipo omogeneo. Prima di illustrare i nuovi concetti, è opportuno verificare la comprensione degli argomenti esposti nella precedente lezione. Lo spunto è come sempre (c) 1997, Edizioni Infomedia srl rappresentato dalla discussione delle soluzioni degli esercizi in essa proposti. Due esercizi

Rinfreschiamoci la memoria...

Le soluzioni degli esercizi della lezione precedente Nella scorsa lezione sono state descritte le strutture di iterazione basate sull'uso della parola chiave Do. Gli esercizi in essa proposti hanno perciò lo scopo di invitare il lettore a farne uso. Primo esercizio Il primo esercizio richiede la realizzazione di un programma che, ricevuta in ingresso una stringa alfabetica, indichi la posizione in essa occupata dalla prima lettera maiuscola, se presente. È evidente la necessità di implementare un ciclo che effettui una scansione della stringa, la cui lunghezza può variare indefinitamente e può anche essere nulla. Per questo motivo, occorre utilizzare una struttura che sia in grado di evitare le iterazioni qualora non siano necessarie. La scelta ricade sul ciclo Do While. Dopo aver realizzato un form dotato di una casella di testo, utilizzata per l'inserimento della stringa e di una label, mediante la quale è visualizzato il risultato dell'elaborazione, è possibile aggiungere un pulsante, avente lo scopo di avviare la ricerca. Esso deve pertanto essere in grado di rispondere all'evento Click con la seguente procedura: Private Sub btnCalcola_Click() Dim Stringa As String Dim Carattere As String * 1 Dim i As Integer Dim Lunghezza As Integer Dim Fine As Boolean Stringa = txtStringa.Text Lunghezza = Len(Stringa)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

i=1 Fine = False Do While Not (Fine) And (i <= Lunghezza) Carattere = Mid$(Stringa, i, 1) Select Case Carattere Case "A" To "Z": Fine = True Case Else: i=i+1 End Select Loop If Fine Then lblRisultato.Caption = "Posizione: " & i Else lblRisultato.Caption = "Nessuna lettera maiuscola" End If End Sub Il contenuto della casella di testo costituisce la stringa nella quale deve essere effettuata la ricerca. Per mezzo della funzione Mid$ è estratto un carattere per volta. La sua posizione è definita dalla variabile i. Se il carattere risulta maiuscolo, la variabile booleana Fine è posta al valore logico True e la ricerca termina. In caso contrario, è incrementato il contatore di un'unità ed è eseguita una nuova iterazione per verificare il carattere seguente. Si noti che se il contatore assume un valore superiore al numero dei caratteri di cui è composta la stringa, condizione immediatamente verificata se la lunghezza è nulla, il ciclo termina. Si noti altresì l'uso della struttura Select Case per verificare se il carattere estratto risulta maiuscolo. Permettendo di definire degli intervalli, infatti, essa rende estremamente agevole l'operazione di controllo, rendendo inoltre il codice molto semplice da comprendere. Secondo esercizio Anche il secondo esercizio richiede la scansione di una stringa fornita dall'utente. La sua soluzione consiste infatti nella realizzazione di un programma in grado di ricevere in ingresso una stringa per mezzo di una textbox e di restituire la lunghezza della prima parola in essa contenuta. È possibile far uso di un form analogo a quello dell'esercizio precedente. Anche in questo caso, l'elaborazione è avviata dalla pressione del pulsante. Il codice che la descrive è quindi ancora contenuto nella procedura btnCalcola_Click: Private Sub btnCalcola_Click() Dim Stringa As String Dim Carattere As String * 1 file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Dim i As Integer Dim Lunghezza As Integer Dim PosInizio As Integer Dim Fine As Boolean Stringa = txtStringa.Text Lunghezza = Len(Stringa) If Lunghezza > 0 Then i=1 Fine = False Rem Ricerca della posizione Rem del primo carattere alfabetico Do Carattere = Mid$(Stringa, i, 1) Select Case Carattere Case "A" To "Z", "a" To "z": Fine = True Case Else: i=i+1 End Select Loop Until Fine Or (i > Lunghezza) If Fine Then Fine = False PosInizio = i Rem Ricerca di uno spazio o di Rem un carattere di punteggiatura Rem che delimiti la parola Do While Not (Fine) And (i <= Lunghezza) Carattere = Mid$(Stringa, i, 1) Select Case Carattere Case " ", ",", ";", ".":

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Fine = True Case Else: i=i+1 End Select Loop lblRisultato.Caption = "Lunghezza prima parola:" & (i - PosInizio) Else lblRisultato.Caption = "La stringa non contiene parole" End If Else lblRisultato.Caption = "Nessuna lettera maiuscola" End If End Sub Dopo l'avvio, la procedura provvede a copiare il contenuto della textbox nella variabile denominata Stringa, di cui è calcolata la lunghezza per mezzo della funzione Len. Mediante un ciclo, è effettuata la ricerca del primo carattere alfabetico contenuto nella stringa. Se l'esito è positivo, ovvero se essa contiene almeno una parola, è utilizzato un ulteriore ciclo per ricercare il carattere che ne determina la fine. La differenza fra la posizione di quest'ultimo e quella del primo carattere costituisce la lunghezza della parola. Il valore è visualizzato per mezzo dell'etichetta testuale lblRisultato.

Perché servono i vettori Si supponga di voler realizzare una semplice applicazione in grado di ordinare in modo crescente tre valori numerici. Non si tratta di un compito gravoso. È infatti sufficiente disegnare un form e porre su di esso tre textbox, necessarie per l'acquisizione dei valori, nonché una label destinata ad ospitare l'elenco ordinato. Per avviare l'elaborazione, è possibile ancora una volta utilizzare una procedura associata all'evento Click generato dalla pressione di un pulsante. Il codice è il seguente: Private Sub btnOrdina_Click() Dim Valore1 As Double Dim Valore2 As Double Dim Valore3 As Double Dim temp As Double Valore1 = Val(txtValore1.Text)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Valore2 = Val(txtValore2.Text) Valore3 = Val(txtValore3.Text) If Valore2 < Valore1 Then temp = Valore2 Valore2 = Valore1 Valore1 = temp End If If Valore3 < Valore1 Then temp = Valore3 Valore3 = Valore1 Valore1 = temp End If If Valore3 < Valore2 Then temp = Valore3 Valore3 = Valore2 Valore2 = temp End If lblRisultato.Caption = Valore1 & " - " & Valore2 & " - " & Valore3 End Sub I dati forniti dall'utente, dopo essere stati convertiti in valori numerici, sono posti all'interno delle variabili Valore1, Valore2, Valore3. È successivamente effettuato un confronto fra i dati contenuti nelle variabili Valore1 e Valore2. Se il numero contenuto nella seconda è maggiore di quello memorizzato nella prima, i due valori sono scambiati. In modo analogo, è effettuato il confronto fra i numeri contenuti nelle variabili Valore2 e Valore3 ed è effettuato un ulteriore scambio qualora esso si riveli necessario per fare in modo che la variabile Valore3 contenga un dato maggiore di quello posto in Valore2. Un ulteriore verifica è eseguita per fare in modo che il dato contenuto in Valore3 sia maggiore di quello memorizzato in Valore1. In seguito all'esecuzione delle tre strutture If, si ottiene che: il dato contenuto nella variabile Valore2 risulta maggiore o uguale a quello posto in Valore1 il dato posto nella variabile Valore3 risulta maggiore o uguale a quelli posti in Valore2 e Valore1 La sequenza Valore1, Valore2, Valore3, risulta pertanto ordinata in modo crescente. I valori possono allora essere visualizzati utilizzando il carattere "-" come separatore. Sarebbe sicuramente molto meno agevole la realizzazione di un'applicazione analoga in file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

grado di gestire 100 numeri. Ancor più ardua si rivelerebbe la creazione di un programma in grado di operare su 1000 o 10000 valori. È evidente che le comuni variabili non permettono di sviluppare in modo ragionevolmente semplice dei programmi in grado di gestire un numero elevato di informazioni dello stesso tipo. Per queste realizzazioni, è necessario far ricorso ai vettori.

I vettori Fino ad ora, le variabili sono stare considerate come delle strutture in grado di associare a un nome simbolico un solo valore, secondo una relazione uno a uno. Saranno descritte ora delle speciali variabili, in grado di associare ad un unico nome uno o più valori, secondo una relazione uno a molti. Esse prendono il nome di vettori, o Array. Un array si presenta quindi come una variabile in grado di ospitare diversi valori in opportuni spazi numerati. L'accesso ad un elemento contenuto in un vettore non può pertanto essere effettuato indicando il solo nome della struttura, bensì richiede che sia specificato anche il numero corrispondente alla posizione, che prende il nome di indice. Per meglio comprendere il concetto di vettore, si provi ad immaginare una variabile come una sorta di cassetto in cui è possibile riporre un'informazione. Si supponga di applicare su questo cassetto un'etichetta su cui è riportata la scritta "Valori". Nel linguaggio naturale, per indicare a una persona di prendere il contenuto del cassetto caratterizzato dall'etichetta "Valori" e di porlo in un altro denominato "Risultato" si usa la frase: "Prendi il contenuto del cassetto Valori e ponilo nel cassetto Risultato". In Visual Basic, ricordando che tali cassetti sono in realtà delle variabili, è possibile scrivere: Risultato = Valori Si supponga ora di disporre di un'intera cassettiera, in cui ogni singolo cassetto è numerato in modo univoco e di spostare su di essa l'etichetta. In questo caso, per accedere a un oggetto, occorre specificare il nome della cassettiera e il numero che identifica il cassetto che lo contiene. Ad esempio, è possibile dire "Prendi il contenuto del cassetto numero 3 della cassettiera Valori e ponilo nel cassetto di nome Risultato". Ciò in Visual Basic è tradotto con la riga: Risultato = Valori(3) Si noti che l'indice dell'elemento è posto fra parentesi tonde. Grazie ai vettori, è ora possibile realizzare in modo molto semplice un'applicazione in grado di richiedere 100 numeri e di visualizzare in un'etichetta di testo l'elenco dei valori ordinato in modo crescente. Il codice può essere associato all'evento Load del form di avvio, affinché sia eseguito durante la fase di creazione. Private Sub Form_Load() Dim Stringa As String Dim Valori(100) As Double Dim Temp As Double Dim i As Integer Dim j As Integer

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Rem Acquisizione dei dati For i = 1 To 100 Stringa = InputBox("Inserire il numero") Valori(i) = Val(Stringa) Next i Rem Ordinamento con algoritmo di selezione diretta. For i = 1 To 99 For j = i + 1 To 100 If Valori(i) > Valori(j) Then Temp = Valori(i) Valori(i) = Valori(j) Valori(j) = Temp End If Next j, i Rem Inserimento dei risultati nella textbox lblRisultato.Caption = "" For i = 1 To 100 lblRisultato.Caption = lblRisultato.Caption & Valori(i) & Chr$(10) Next i End Sub Si noti che la dichiarazione del vettore Valori è eseguita per mezzo dell'istruzione Dim, in modo pressoché analogo a quanto previsto per una qualsiasi variabile. L'unica differenza è costituita dalla presenza delle parentesi contenenti un numero che rappresenta la dimensione, ovvero il massimo indice utilizzabile. Il valore minimo per l'indice è sempre 0, tranne quando si provvede ad indicare nella sezione destinata delle dichiarazioni delle variabili globali la clausola Option Base 1 In questo caso, l'indice minimo dei vettori è 1. Osservando la dichiarazione, si nota la presenza di un unico identificatore di tipo. Ciò rende immediatamente intuibile la necessità che tutti i dati presenti nel vettore siano omogenei. Nell'esempio, i valori sono acquisiti per mezzo della funzione InputBox, la cui sintassi è la seguente: <stringa>=InputBox(<Messaggio di richiesta> [, <titolo della finestra>]

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

[, <valore di default>] [, <posizione orizzontale>] [, <posizione verticale>]) Essa visualizza una finestra di dialogo che invita l'utente a digitare una stringa. Come è possibile notare, il programmatore deve specificare il messaggio di richiesta. Inoltre, egli può provvedere a un ulteriore personalizzazione indicando il titolo della finestra (in caso di omissione è utilizzato quello dell'applicazione), il valore di default, che è restituito se l'utente agisce sul pulsante Annulla e le coordinate orizzontale e verticale del punto di origine. Si noti che il riempimento del vettore avviene per mezzo di un ciclo For, che provvede a richiedere il valore di ogni singolo elemento richiamando 100 volte la funzione InputBox.

L'ordinamento per selezione diretta Dopo l'acquisizione dei dati, è possibile provvedere al loro ordinamento. A tal fine, si fa uso dell'algoritmo detto di selezione diretta. Non si tratta del metodo più efficiente, ma si presta molto bene agli scopi didattici, in quanto è caratterizzato da un'estrema semplicità. Eccone una breve descrizione. Si supponga che i sia l'indice di un elemento del vettore. Affinché l'ordinamento sia crescente, è necessario che tutti gli oggetti caratterizzati dal possedere un indice superiore a i abbiano un valore maggiore di quello dell'elemento di indice i. Per fare in modo che ciò avvenga, per ogni posizione j maggiore di i è effettuato un confronto. Se l'elemento di indice j contiene un valore inferiore a quello dell'oggetto di posizione i, i dati sono scambiati. Al termine dell'iterazione, l'elemento di indice i contiene sicuramente un valore inferiore a tutti quelli che lo seguono. La ripetizione di questa operazione per tutti gli elementi del vettore ne provoca l'ordinamento. L'implementazione è basata sull'uso di due cicli For nidificati. Il più interno effettua la scansione del vettore alla ricerca dei valori inferiori a quello contenuto nell'elemento di indice i. Il più esterno varia i per fare in modo che tale scansione sia ripetuta per tutti gli elementi del vettore, tranne l'ultimo, per il quale l'operazione sarebbe evidentemente inutile. La terza parte del programma è ancora una volta costituita da un ciclo, la cui funzione è quella di copiare nella label i dati contenuti nel vettore ordinato, separandoli con il carattere caratterizzato dal codice ASCII 10, che corrisponde al ritorno a capo. In tal modo i valori sono visualizzati su righe separate. Si noti l'uso della funzione Chr$ per generare un carattere a partire dal suo codice ASCII. L'applicazione descritta si caratterizza per la presenza di ben quattro cicli. Ciò non è casuale. I vettori, infatti, essendo costituiti da dati di tipo omogeneo, sui quali in genere devono essere effettuate le stesse operazioni, si prestano molto bene ad essere utilizzati nelle procedure basate sull'uso delle strutture di iterazione.

Due esercizi Per verificare la comprensione degli argomenti esposti, si provi ad eseguire i seguenti esercizi: Primo esercizio Si modifichi l'applicazione dell'esempio affinché effettui l'ordinamento in modo decrescente. Secondo esercizio file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

Si realizzi un'applicazione in grado di estrarre a sorte 30 numeri, di calcolarne la media aritmetica e di visualizzare all'interno di una textbox solo quelli che risultano inferiori ad essa. I vettori sono strutture di dati dall'importanza fondamentale, il cui uso si rivela spesso indispensabile per la realizzazione di programmi in grado di gestire grandi quantità di dati di tipo omogeneo. Nel prossimo numero si parlerà ancora degli array e saranno illustrati alcuni concetti più avanzati. Per la loro comprensione è quindi importante esercitarsi su quanto appreso questo mese.

Rinfreschiamoci la memoria... Questa lezione si chiude in un modo un po' diverso, con una serie di domande aventi lo scopo di consentire un'autoverifica del livello di comprensione degli argomenti esposti in questi sei mesi. Le risposte corrette sono elencate di seguito, in corsivo. Qual è la differenza che intercorre fra una textbox e una label? La label permette solo di visualizzare una stringa. La textbox permette anche l'inserimento del dato da parte dell'utente. A quale evento occorre associare del codice per fare in modo che sia eseguito in corrispondenza della pressione di un pulsante? L'evento generato dalla pressione di un pulsante è denominato Click. Può una variaibile di tipo Integer contenere il dato 23.45? No, perché le variabili di tipo Integer non possono contenere numeri con cifre decimali. Quale istruzione permette di dichiarare una variabile? La dichiarazione di una variabile è possibile per mezzo dell'istru- zione Dim. È consentito utilizzare più strutture If nidificate? Si, in Visual Basic non ci sono limiti al livello di nidificazione delle strutture If. Quali istruzioni sono eseguite se la condizione che regola una struttura If è falsa? Sono eseguite le istruzioni comprese fra le parole chiave Else e End If A cosa serve la funzione Val? La funzione Val converte una stringa in un valore numerico Cosa restituisce l'operatore logico And applicato a due condizioni? L'operatore logico And, se applicato a due condizioni, restituisce il valore True se e solo se entrambe sono verificate. A cosa serve l'operatore logico Not? L'operatore logico Not serve per negare una condizione. A cosa serve la parola chiave Next?

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

La parola chiave Next è utilizzata per delimitare il blocco di istruzioni contenuto in un ciclo For. A cosa serve la funzione Len? La funzione Len restituisce la lunghezza della stringa fornitale come parametro A cosa serve la parola chiave Step? La parola chiave Step permette di specificare l'incremento della variabile di controllo ad ogni iterazione in un ciclo For. Se è omessa, l'incremento è di un'unità. È possibile interrompere prematuramente un ciclo For? Si, per mezzo dell'istruzione Exit For Un ciclo While può ripetere un blocco di istruzioni per un qualsiasi numero di volte. Se la condizione non è verificata, può non eseguire alcuna iterazione. Quando un ciclo Do Until ripete un blocco di istruzioni? Un ciclo Do Until ripete un blocco di istruzioni fino a quando si verifica la condizione specificata dopo la parola Until La clausola Option Base 1 serve per fare in modo che l'indice minimo dei vettori all'interno del progetto sia 1, anziché 0. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


Maurizio Crespi - Corso di Visual Basic (Parte 6)

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb06/index.htm[26/09/2010 1:06:00]


La soluzione del primo esercizio

Figura 1 La soluzione del primo esercizio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb06/fig1.htm[26/09/2010 1:06:18]


L'applicazione che ordina 3 valori

Figura 2 L'applicazione che ordina 3 valori

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb06/fig2.htm[26/09/2010 1:06:25]


L'applicazione che ordina 100 valori

Figura 3 L'applicazione che ordina 100 valori

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb06/fig3.htm[26/09/2010 1:06:32]


Corso di Visual Basic (Parte 7)

Corso di Corso di Visual Basic Visual Basic (Parte 7) Le soluzioni degli esercizi proposti nella precedente lezione

(Parte 7) di Maurizio Crespi

Vettori con indice minimo diverso da 0 o 1 I vettori a dimensione variabile La clausola Preserve Vettori a due indici I vettori di controlli Conclusioni

Continua lo studio dei vettori; questo mese sono protagonisti quelli a più dimensioni, le strutture caratterizzate dal poter variare dinamicamente il numero degli elementi che le compongono e gli array di controlli Nella scorsa lezione è stata introdotta la nozione di vettore, o array. Per mezzo di questa struttura di dati, è possibile associare un unico nome a un insieme di posizioni di memoria dello stesso tipo, ognuna delle quali può contenere un dato diverso. In questa settima puntata del corso dedicato alla programmazione in Visual Basic sarà esteso il concetto e ne saranno descritte le evoluzioni, ovvero saranno studiati i vettori caratterizzati dal possedere più di una dimensione e gli utilissimi array di controlli, che talvolta contribuiscono notevolmente a semplificare il compito del programmatore.

Listati Listato 1 - La soluzione del secondo esercizio dello scorso numero Listato 2 - Una prima versione della procedura che calcola la media fra le temperature di più giorni Listato 3 - La procedura che calcola la media fra le temperature di più giorni modificata per l'uso di array dinamici Listato 4 - La procedura che calcola la media fra le temperature di più giorni modificata per l'uso di array a dimensione variabile Listato 5 - La procedura modificata per gestire le temperature minima e massima Listato 6 - La procedura che gestisce le

Le soluzioni degli esercizi proposti nella precedente lezione Il primo passo, prima di procedere allo studio dei nuovi argomenti, prevede come sempre la verifica della comprensione di quelli esposti nel numero precedente, mediante la correzione degli esercizi in esso proposti. Primo esercizio Il primo esercizio richiede la modifica dell'applicazione, descritta nello scorsa puntata, in grado di leggere 100 numeri e di elencarli in ordine crescente all'interno di una casella di testo. È infatti richiesto di far sì che effettui l'ordinamento in modo decrescente. La soluzione è banale, in quanto richiede semplicemente l'inversione dell'operatore di confronto all'interno del ciclo che provvede all'ordinamento. Il codice necessario per ordinare un vettore contenente 100 valori numerici in modo decrescente per mezzo dell'algoritmo di selezione diretta è pertanto quello indicato di seguito: For i = 1 To 99 For j = i + 1 To 100 If Valori(i) < Valori(j) Then Temp = Valori(i) Valori(i) = Valori(j) Valori(j) = Temp End If

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


Corso di Visual Basic (Parte 7)

temperature minima e massima con un vettore a 2 dimensioni

(c) 1997, Edizioni Infomedia srl

Next j, i Secondo esercizio Il secondo esercizio presenta una complessità leggermente superiore. Esso richiede infatti di realizzare un'applicazione in grado di estrarre a sorte 30 numeri, di calcolarne la media aritmetica e di visualizzare all'interno di una label solo quelli che risultano inferiori ad essa. Per la sua realizzazione, l'applicazione richiede la creazione di un form, in cui va posta un'etichetta testuale denominata lblRisultato. Il codice che provvede al suo riempimento deve essere eseguito all'avvio. Può pertanto essere associato all'evento Load del form. La procedura, che è possibile osservare nel Listato 1, è costituita da 3 cicli. Il primo ha lo scopo di estrarre a sorte 30 valori interi compresi fra 1 e 100. Di essi è calcolata la media aritmetica per mezzo della seconda struttura di iterazione. Tutti i valori che risultano inferiori a questo numero sono elencati, uno sotto l'altro, all'interno della casella di testo. Ciò avviene per mezzo del terzo ciclo.

Vettori con indice minimo diverso da 0 o 1 Si noti che la dichiarazione del vettore risulta leggermente diversa da quelle viste nella scorsa lezione. In questo caso, infatti, è stato specificato anche l'indice minimo, secondo la sintassi Dim <nome> (<indice_minimo> To <indice_massimo>) As <tipo> Ciò consente di creare dei vettori in cui gli indici possono essere anche negativi, oppure appartenere a un campo di valori molto diverso da quello usuale. Ad esempio, supponendo di voler creare un array in grado di ospitare un dato numerico indicante il prodotto interno lordo dello Stato italiano negli anni compresi fra il 1989 ad oggi, è possibile dichiarare la variabile PIL come segue: Dim PIL(1989 To 1998) As Double Naturalmente, il vettore è del tutto equivalente a uno di 10 elementi dichiarato con il metodo usuale, però l'uso di indici strettamente correlati alle informazioni contenute nella struttura offre il vantaggio di migliorare la leggibilità del codice.

I vettori a dimensione variabile Si supponga di voler scrivere un'applicazione in grado di leggere un dato numerico corrispondente alla temperatura massima per ogni giorno di un mese, di calcolare la media di tutti i valori e di indicare in quali giorni la temperatura si è mantenuta al di sotto del valore medio calcolato. In pratica, l'applicazione risulta estremamente simile a quella descritta in precedenza. In questo caso, tuttavia, i valori non sono casuali, bensì inseriti dall'utente. Inoltre, il loro numero non è fisso, in quanto dipendente dal mese a cui si riferiscono i dati. Una possibile soluzione è quella indicata nel Listato 2. ReDim [Preserve] <nome> (<dimensione>) Il suo scopo è di variare la dimensione del vettore di cui è specificato il nome. L'istruzione può essere ripetuta all'interno del programma per un numero di volte teoricamente infinito. La procedura descritta nel Listato 2 può essere resa più efficiente mediante l'uso di un vettore dinamico, come indicato nel Listato 3. Si noti che è cambiata la dichiarazione del vettore, che nella nuova procedura costituita dalla riga

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


Corso di Visual Basic (Parte 7)

Dim V() As Integer La dimensione questa volta non è stata specificata; il compito di allocare la giusta quantità di memoria per le informazioni è demandato alla riga ReDim V(NumGiorni) che provvede a dimensionare il vettore in modo che il massimo indice sia pari al valore della variabile intera NumGiorni, il cui valore è fornito dall'utente.

La clausola Preserve Si supponga ora di voler modificare la procedura sopra descritta per fare in modo che non richieda all'avvio il numero dei valori da elaborare, bensì acquisisca ciclicamente dei dati fino alla digitazione da parte dell'utente della stringa "Fine". In questo caso, non è possibile conoscere la dimensione del vettore prima dell'inserimento dei dati. Esso quindi deve essere in grado di crescere continuamente. Il codice necessario per svolgere il compito richiesto è descritto nel Listato 4. Si noti la presenza di un ciclo delimitato dalle parole chiave Do e Loop. Esso risulta privo delle clausole While o Until. L'uscita è infatti causata dall'istruzione Exit For, che è eseguita quando l'utente digita la parola "Fine". Osservando il codice, è possibile constatare che la stringa inserita dall'utente è convertita in maiuscolo per mezzo della funzione UCase ed è privata degli eventuali spazi iniziali e finali per mezzo della funzione Trim. In tal modo, il confronto risulta indipendente dall'uso delle lettere maiuscole. L'istruzione ReDim è invocata ad ogni iterazione, al fine di incrementare la dimensione del vettore di un'unità per fare posto al dato appena letto. Dovendo intervenire su una struttura già contenente dei dati e volendo fare in modo che essi non siano persi, occorre utilizzare l'istruzione ReDim con la clausola Preserve; in sua assenza, il ridimensionamento dell'array comporterebbe la cancellazione di tutti i valori contenuti. All'interno della procedura si è fatto uso anche della funzione UBound, che ha lo scopo di calcolare il massimo indice previsto dal vettore, ovvero la sua dimensione. Esercizio Si provi a realizzare un'applicazione in grado di simulare lo spoglio delle schede elettorali. Essa deve leggere per ogni scheda il numero del candidato votato. Alla fine, deve essere in grado di indicare la classifica in ordine decrescente.

Vettori a due indici Si supponga ora di voler modificare il programma per fare in modo che sia in grado di effettuare le proprie valutazioni facendo riferimento sia alle temperature massime, sia alle minime e che indichi i giorni in cui almeno uno dei due valori è risultato al di sotto della media. In questo caso, quindi, per ogni giorno è necessario acquisire due valori. Una soluzione consiste nell'utilizzare due vettori, uno dedicato alle temperature massime e l'altro alle minime. Il codice è descritto nel Listato 5. Esso non costituisce un esempio di compattezza ed efficienza. Infatti, le istruzioni utilizzate per gestire le temperature minime sono praticamente duplicate per gestire le massime. La lunghezza del codice può essere ridotta facendo ricorso a una matrice costituita da due colonne, di cui una è dedicata alle temperature minime e l'altra alle massime. La procedura così modificata è descritta nel Listato 6. Il primo indice determina la colonna della matrice. file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


Corso di Visual Basic (Parte 7)

Il valore 1 fa riferimento alle temperature minime, mentre il valore 2 si riferisce alle massime. Il secondo, ridimensionabile per mezzo dell'istruzione ReDim, è invece utilizzato per far riferimento al giorno. Si osservi che l'uso dell'istruzione ReDim non è possibile sul primo indice. Infatti, solo l'indice posto più a destra nella dichiarazione di una matrice può essere ridimensionato. L'introduzione di una seconda dimensione comporta una semplificazione del codice. Per operazioni più complesse, è possibile incrementare ulteriormente il numero delle dimensioni di un vettore, purché rimanga inferiore a 60. Nella procedura appena descritta, si è fatto nuovamente uso della funzione UBound, che in questo caso richiede un ulteriore parametro indicante la posizione della dimensione di cui si desidera conoscere la grandezza.

I vettori di controlli Si supponga ora di voler modificare l'applicazione per fare in modo che sia in grado di richiedere su un unico form i valori delle temperature minime e massime rilevate in tutti i giorni di una settimana. L'interfaccia deve prevedere l'acquisizione dei dati che avviene per mezzo di caselle di testo. Si tratta di creare un form e di aggiungere le textbox necessarie, che si supporranno denominate LunediMin, LunediMax, MartediMin, MartediMax, ecc. Occorre poi modificare la procedura precedentemente descritta sostituendo la parte dedicata all'inserimento dei dati nella matrice con il seguente codice: V(1,1)=Val(LunediMin.Text) V(2,1)=Val(LunediMax.Text) V(1,2)=Val(MartediMin.Text) V(2,2)=Val(MartediMax.Text) V(1,3)=Val(MercolediMin.Text) V(2,3)=Val(MercolediMax.Text) V(1,4)=Val(GiovediMin.Text) V(2,4)=Val(GiovediMax.Text) V(1,5)=Val(VenerdiMin.Text) V(2,5)=Val(VenerdiMax.Text) V(1,6)=Val(SabatoMin.Text) V(2,6)=Val(SabatoMax.Text) V(1,7)=Val(DomenicaMin.Text) V(2,7)=Val(DomenicaMax.Text) La sequenza di istruzioni presentata non rappresenta un esempio di semplicità. Nel caso in cui le caselle di testo, anziché essere 14, fossero in un numero sensibilmente maggiore, il programma potrebbe diventare poco leggibile. Si osservi che di fatto le righe sono estremamente simili fra loro. Ciò che varia è il nome della textbox. Grazie alle caratteristiche di Visual Basic, è possibile operare una notevole semplificazione del codice utilizzando un

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


Corso di Visual Basic (Parte 7)

vettore di controlli, nella fattispecie rappresentati da caselle di testo. Un array di questo tipo non richiede alcuna dichiarazione. È sufficiente far uso della proprietà Index dei controlli. Ad esempio, si supponga di voler realizzare il form in grado di acquisire tutte le temperature rilevate nell'arco della settimana. Dopo aver agito sul menu Progetto ed aver selezionato la voce Inserisci form, si provvede ad inserire sul modulo creato una casella di testo e ad assegnarle il nome txtMinima. Ad essa possono successivamente essere assegnati i valori desiderati delle proprietà che definiscono il carattere, il colore e la dimensione. Si crea così l'elemento campione, che può essere duplicato per mezzo di una normale operazione di copia e incolla. Si noti che, nel momento in cui si incolla il primo elemento, appare un messaggio che segnala la presenza sul form di un altro oggetto denominato txtMinima e presenta una finestra di dialogo che ha lo scopo di chiedere al programmatore se desidera creare un array. Rispondendo Si, si crea un vettore di caselle di testo denominato txtMinima, in cui gli elementi che lo compongono sono caratterizzati dal possedere un diverso valore della variabile Index. Quest'ultima costituisce l'indice che identifica in modo univoco l'elemento nel vettore. È tuttavia possibile realizzare una matrice anche riunendo dei controlli aventi dei nomi diversi, purché siano dello stesso tipo. In questo caso, occorre inserire tutti gli elementi nel form e successivamente associare ad essi dei diversi valori della proprietà Index. Dopo aver fatto ciò, è possibile variare il contenuto delle proprietà Name ed assegnare a tutti la stessa stringa. Tornando all'esempio, si supponga di creare 7 copie dell'oggetto txtMinima. Si supponga altresì di agire in modo analogo con un'altra casella di testo, denominata txtMassima. In tal modo, si creano 2 vettori, destinati a contenere rispettivamente le temperature minime e massime rilevate. Grazie ad essi, il codice necessario per riempire il vettore V si riduce a poche righe: For i=1 to 7 V(1,i)=val(txtMinima(i).Text) V(2,i)=val(txtMassima(i).Text) Next i Si noti la notevole compattezza che lo caratterizza e la possibilità di adattarlo alla gestione di un numero maggiore di textbox semplicemente variando il valore massimo della variabile di controllo del ciclo. L'accesso alle proprietà e ai metodi di ogni elemento del vettore richiede obbligatoriamente l'indicazione dell'indice fra parentesi tonde. Un'interessante caratteristica dei vettori di controlli consiste nell'utilizzo della stessa procedura per rispondere agli eventi generati da ogni singolo elemento. Ad esempio, si supponga di disporre di un form dotato di 3 pulsanti, etichettati Primo, Secondo, Terzo, che costituiscono un vettore denominato btnBottoni. Volendo generare un messaggio alla pressione di un pulsante che indichi quale di essi è stato premuto, è possibile scrivere la seguente procedura: Private Sub btnBottoni_Click(Index As Integer) MsgBox btnBottoni(Index).Caption End Sub Essa è associata all'evento Click di tutti gli elementi del vettore. Si noti che fra parentesi è specificata la variabile Index. Essa ha valore solo all'interno della procedura ed identifica l'indice dell'elemento che ha generato l'evento. Per mezzo della funzione MsgBox, in grado di far apparire sullo schermo una finestra contenente un messaggio, è possibile visualizzare l'etichetta testuale del pulsante premuto, facendo riferimento alla proprietà Caption dell'elemento di indice corrispondente al valore della variabile Index.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


Corso di Visual Basic (Parte 7)

La procedura descritta risulta adatta a gestire vettori di dimensione qualsiasi. Ancora una volta appare evidente la caratteristica fondamentale degli array: lo stesso codice può gestire allo stesso modo e con la stessa facilità delle strutture sia di piccole, sia di grandi dimensioni. Esercizio Si provi a realizzare un'applicazione che preveda una pulsantiera costituita da tasti numerati da 1 a 9. La pressione di uno di essi deve provocare l'incremento di un contatore numerico di un'entità pari all'indicazione presente sulla sua etichetta. Il valore del contatore deve essere visualizzato per mezzo di una label.

Conclusioni L'uso dei vettori permette di aumentare notevolmente la flessibilità e il livello di astrazione del proprio codice. Per mezzo di quelli a più dimensioni e agli array di controlli, diventa spesso possibile ridurre notevolmente la quantità di codice necessaria per realizzare un'applicazione, a tutto vantaggio della leggibilità. Data l'importanza degli argomenti proposti, l'invito rivolto al lettore è come sempre di esercitarsi su di essi, al fine di raggiungere un buon livello di comprensione. (c) 1998 Edizioni Infomedia srl

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb07/index.htm[26/09/2010 1:08:29]


La soluzione del secondo esercizio dello scorso numero

Private Sub Form_Load() Dim i As Integer Dim Somma As Integer Dim Media As Double Dim V(1 To 30) As Integer

Rem Estrazione valori Randomize For i = 1 To 30 V(i) = Int(Rnd() * 100) Next i

Rem Calcolo della media Somma = 0 For i = 1 To 30 Somma = Somma + V(i) Next i Media = Somma / 30

Rem Inserimento dei risultati nella label lblRisultato.Caption = "" For i = 1 To 30 If V(i) < Media Then lblRisultato.Caption = lblRisultato. Caption & V(i) & Chr$(10) End If Next i End Sub

Listato 1 La soluzione del secondo esercizio dello scorso numero

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis1.htm[26/09/2010 1:08:39]


Una prima versione della procedura che calcola la media fra le temperature di pi첫 giorni

Private Sub Form_Load() Dim V(1 To 31) As Integer Dim i As Integer Dim NumGiorni As Integer Dim Stringa As String Dim Messaggio As String Dim Somma As Integer Dim Media As Double

Rem Acquisizione valori Stringa = InputBox("Numero dei giorni") NumGiorni = Val(Stringa) For i = 1 To NumGiorni Messaggio = "Temperatura giorno" & Str$(i) Stringa = InputBox(Messaggio) V(i) = Int(Val(Stringa)) Next i

Rem Calcolo della media Somma = 0 For i = 1 To NumGiorni Somma = Somma + V(i) Next i Media = Somma / NumGiorni

Rem Generazione elenco valori '

al di sotto della media

lblRisultato.Caption = "" For i = 1 To NumGiorni If V(i) < Media Then lblRisultato.Caption = lblRisultato.Caption & i & Chr$(10) End If Next i End Sub

Listato 2 Una prima versione della procedura che calcola la media fra le temperature di pi첫 giorni

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis2.htm[26/09/2010 1:08:49]


Una prima versione della procedura che calcola la media fra le temperature di pi첫 giorni

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis2.htm[26/09/2010 1:08:49]


La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array dinamici

Private Sub Form_Load() Dim V() As Integer Dim i As Integer Dim NumGiorni As Integer Dim Stringa As String Dim Messaggio As String Dim Somma As Integer Dim Media As Double

Rem Acquisizione valori Stringa = InputBox("Numero dei giorni") NumGiorni = Val(Stringa) ReDim V(NumGiorni) For i = 1 To NumGiorni Messaggio = "Temperatura giorno" & Str$(i) Stringa = InputBox(Messaggio) V(i) = Int(Val(Stringa)) Next i Rem Calcolo della media Somma = 0 For i = 1 To NumGiorni Somma = Somma + V(i) Next i Media = Somma / NumGiorni

Rem Generazione elenco valori '

al di sotto della media

lblRisultato.Caption = "" For i = 1 To NumGiorni If V(i) < Media Then lblRisultato.Caption = lblRisultato.Caption & i & Chr$(10) End If Next i End Sub

Listato 3 La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array dinamici

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis3.htm[26/09/2010 1:08:58]


La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array dinamici

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis3.htm[26/09/2010 1:08:58]


La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array a dimensione variabile

Private Sub Form_Load() Dim V() As Integer Dim i As Integer Dim NumGiorni As Integer Dim Stringa As String Dim Messaggio As String Dim Somma As Integer Dim Media As Double

Rem Acquisizione valori i = 0 Stringa = "" Do i = i + 1 Messaggio = "Temperatura giorno" & Str$(i) Stringa = InputBox(Messaggio) Stringa = UCase(Stringa) Stringa = Trim(Stringa) If Stringa = "FINE" Then Exit Do Else ReDim Preserve V(i) V(i) = Int(Val(Stringa)) End If Loop NumGiorni = UBound(V)

Rem Calcolo della media Somma = 0 For i = 1 To NumGiorni Somma = Somma + V(i) Next i Media = Somma / NumGiorni

Rem Generazione elenco valori '

al di sotto della media

lblRisultato.Caption = "" For i = 1 To NumGiorni If V(i) < Media Then lblRisultato.Caption = lblRisultato.Caption & i

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis4.htm[26/09/2010 1:10:14]


La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array a dimensione variabile

& Chr$(10) End If Next i End Sub

Listato 4 La procedura che calcola la media fra le temperature di pi첫 giorni modificata per l'uso di array a dimensione variabile

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis4.htm[26/09/2010 1:10:14]


La procedura modificata per gestire le temperature minima e massima

Private Sub Form_Load() Dim Vmin() As Integer Dim Vmax() As Integer Dim i As Integer Dim NumGiorni As Integer Dim Stringa As String Dim Messaggio As String Dim Somma As Integer Dim MediaMin As Double Dim MediaMax As Double

Rem Acquisizione valori i = 0 Stringa = "" Do i = i + 1 Messaggio = "Temperatura minima giorno" & Str$(i) Stringa = InputBox(Messaggio) Stringa = UCase(Stringa) Stringa = Trim(Stringa) If Stringa = "FINE" Then Exit Do Else ReDim Preserve Vmin(i) ReDim Preserve Vmax(i) Vmin(i) = Int(Val(Stringa)) Messaggio = "Temperatura massima giorno" & Str$(i) Stringa = InputBox(Messaggio) Stringa = UCase(Stringa) Stringa = Trim(Stringa) Vmax(i) = Int(Val(Stringa)) End If Loop NumGiorni = UBound(Vmin)

Rem Calcolo della media delle '

temperature minime

Somma = 0 For i = 1 To NumGiorni Somma = Somma + Vmin(i)

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis5.htm[26/09/2010 1:10:30]


La procedura modificata per gestire le temperature minima e massima

Next i MediaMin = Somma / NumGiorni

Rem Calcolo della media delle '

temperature massime

Somma = 0 For i = 1 To NumGiorni Somma = Somma + Vmax(i) Next i MediaMax = Somma / NumGiorni

Rem Generazione elenco giorni con Rem temperature al di sotto della media lblRisultato.Caption = "" For i = 1 To NumGiorni If (Vmin(i) < MediaMin) Or (Vmax(i) < MediaMax) Then lblRisultato.Caption = lblRisultato.Caption & i & Chr$(10) End If Next i End Sub

Listato 5 La procedura modificata per gestire le temperature minima e massima

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis5.htm[26/09/2010 1:10:30]


La procedura che gestisce le temperature minima e massima con un vettore a 2 dimensioni

Private Sub Form_Load() Dim V() As Integer Dim i As Integer Dim j As Integer Dim NumGiorni As Integer Dim Stringa(2) As String Dim Messaggio As String Dim Somma As Integer Dim MediaMin As Double Dim MediaMax As Double

Rem Acquisizione valori i = 0 Do i = i + 1 For j = 1 To 2 Stringa(j) = "" If j = 1 Then Messaggio = "Temperatura minima giorno" & Str$(i) Else Messaggio = "Temperatura massima giorno" & Str$(i) End If Stringa(j) = InputBox(Messaggio) Stringa(j) = UCase(Stringa(j)) Stringa(j) = Trim(Stringa(j)) Next j If (Stringa(1) = "FINE") Or (Stringa(2) = "FINE") Exit Do Else ReDim Preserve V(2, i) V(2, i) = Int(Val(Stringa(1))) V(1, i) = Int(Val(Stringa(2))) End If Loop NumGiorni = UBound(V, 2)

Rem Calcolo della media delle '

delle temperature minime

Somma = 0 For i = 1 To NumGiorni

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis6.htm[26/09/2010 1:10:38]

Then


La procedura che gestisce le temperature minima e massima con un vettore a 2 dimensioni

Somma = Somma + V(1, i) Next i MediaMin = Somma / NumGiorni

Rem Calcolo della media delle '

temperature massime

Somma = 0 For i = 1 To NumGiorni Somma = Somma + V(2, i) Next i MediaMax = Somma / NumGiorni

Rem Generazione elenco giorni con Rem temperature al di sotto della media lblRisultato.Caption = "" For i = 1 To NumGiorni If (V(1, i) < MediaMin) Or (V(2, i) < MediaMax) lblRisultato.Caption = lblRisultato.Caption & i & Chr$(10) End If Next i End Sub

Listato 6 La procedura che gestisce le temperature minima e massima con un vettore a 2 dimensioni

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb07/lis6.htm[26/09/2010 1:10:38]

Then


Corso di Visual Basic (Parte 8) DI MAURIZIO CRESPI

Q

uesto mese il corso di programmazione in Visual Basic focalizza la propria attenzione sulle procedure, talvolta dette subroutine

L’oggetto dell’ottava puntata del corso dedicato alla programmazione in ambiente Microsoft Visual Basic è rappresentato dalle procedure definibili dal programmatore. Come si potrà osservare in seguito, si tratta di strutture di fondamentale importanza, in quanto il loro uso permette di rendere notevolmente più compatto e leggibile il codice di un’applicazione.

LE SOLUZIONI DEGLI ESERCIZI DELLA SCORSA LEZIONE Come sempre, prima di affrontare i nuovi argomenti sarà fornito al lettore uno spunto per rinfrescare la propria memoria su quanto appreso nella scorsa lezione. L’occasione è data dalla correzione degli esercizi in essa proposti. Primo esercizio Il primo esercizio richiede la realizzazione di un programma in grado di simulare lo spoglio delle schede elettorali. Per ogni scheda, l’applicazione deve leggere il numero del candidato votato e redigere, a scrutinio terminato, una classifica in ordine decrescente. Il compito può essere svolto dalla seguente procedura, che è eseguita nella fase di caricamento di un form contenente un’etichetta di testo (lblClassifica) destinata a contenere la classifica finale. Private Sub Form_load() Dim ElencoVoti() As Integer Dim Classifica() As Integer Dim Stringa As String Dim Candidato As Integer Dim NumeroCandidati As Integer Dim i As Integer Dim j As Integer Dim x As Integer Dim y As Integer Stringa = InputBox(“Numero candidati”) NumeroCandidati = Int(Val(Stringa)) ReDim ElencoVoti(NumeroCandidati) ReDim Classifica(NumeroCandidati) Rem Acquisizione dei dati Do Stringa = InputBox(“N. candidato votato (0 per finire)”) Candidato = Int(Val(Stringa)) If Candidato > 0 Then

86 SETTEMBRE 1998 - PROGRAMMO SUBITO n.8

ElencoVoti(Candidato) = ElencoVoti(Candidato) + 1 End If Loop Until Candidato = 0 Rem Preparazione vettore classifica For i = 1 To NumeroCandidati Classifica(i) = i Next i For i = 1 To NumeroCandidati - 1 For j = i + 1 To NumeroCandidati x = Classifica(i) y = Classifica(j) If ElencoVoti(x) < ElencoVoti(y) Then Temp = Classifica(i) Classifica(i) = Classifica(j) Classifica(j) = Temp End If Next j, i Rem Visualizzazione classifica lblClassifica.Caption = “” For i = 1 To NumeroCandidati lblClassifica.Caption = lblClassifica.Caption & Classifica(i) & Chr$(10) Next i End Sub

La lettura dei dati è, per semplicità, affidata a delle finestre di input, realizzate per mezzo della funzione InputBox. Sono previsti due vettori; il primo, denominato ElencoVoti, associa all’elemento di indice n il numero dei voti collezionati dal candidato numero n. Ogni elemento contiene un numero che è incrementato ogniqualvolta è estratta una scheda sui cui è espressa una preferenza riferita al candidato corrispondente. Un secondo vettore, denominato Classifica, ha lo scopo di memorizzare i numeri associati ai candidati in modo che leggendo sequenzialmente la struttura si possa leggere la classifica in ordine decrescente di voti. Entrambi i vettori sono dimensionati all’avvio del programma per prevedere un elemento per ogni candidato. La procedura provvede a leggere tutti i voti di preferenza, aggiornando volta per volta il vettore ad essi dedicato. Dopo aver fatto ciò, è inizializzato il vettore Classifica con i numeri corrispondenti a tutti i candidati; tali valori sono in seguito scambiati fra loro in modo tale per cui al termine del ciclo il vettore contenga la classifica in ordine decrescente di preferenze. Si noti che per effettuare ciò è applicata una variante all’algoritmo di ordinamento per selezione diretta visto nella scorsa lezione, in cui l’ordinamento è eseguito sull’array Classifica ma i confronti sono effettuati fra gli elementi del vettore ElencoVoti. Si desidera infatti fare in modo

○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○


FIGURA 1 L’inter faccia utente della soluzione del secondo esercizio proposto nella scorsa lezione

n2 = Val(Stringa) Loop Until (n2 > 0) And (n2 < 50) Somma = n1 + n2 MsgBox (“La somma è “ & Somma) End Sub

L’acquisizione dei valori avviene per mezzo di due cicli. Il loro scopo consiste nel richiedere la digitazione di una stringa all’utente e nell’effettuare la conversione in un valore numerico per mezzo

Mediante l’uso delle procedure è possibile migliorare la leggibilità del codice

che, dati due elementi qualsiasi x e y del vettore Classifica, x preceda y se ElencoVoti(x)>ElencoVoti(y). Secondo esercizio Il secondo esercizio prevede la realizzazione di un programma dotato di una pulsantiera costituita da tasti numerati da 1 a 9. La pressione di uno di essi deve provocare l’incremento di un contatore numerico di un’entità pari all’indicazione presente sulla sua etichetta. Il valore del contatore deve essere visualizzato per mezzo di una label. Se si fa uso di un vettore di controlli, la soluzione diventa estremamente semplice, al punto da non necessitare di alcun commento. Si supponga di disegnare un form dotato di nove pulsanti, che costituiscono gli elementi del vettore btnNumeri. Alla pressione di uno di essi, ovvero al verificarsi dell’evento Click su un elemento del vettore, può essere associata la seguente procedura: Private Sub btnNumeri_click(index As Integer) Dim Contatore As Integer Dim Incremento As Integer Contatore = Val(lblContatore.Caption) Incremento = Val(btnNumeri(index).Caption) Contatore = Contatore + Incremento lblContatore.Caption = Contatore End Sub

LE PROCEDURE Si supponga di voler realizzare un’applicazione in grado di calcolare la somma di due valori numerici inseriti dall’utente dopo aver verificato che siano positivi e, rispettivamente, inferiori a 10 e 50. Una possibile implementazione è la seguente: Private Sub Form_Load() Dim Stringa As String Dim n1 As Double Dim n2 As Double Dim Somma As Double Rem Primo valore Do Stringa = InputBox(“Primo valore:”) n1 = Val(Stringa) Loop Until (n1 > 0) And (n1 < 10) Rem Secondo valore Do Stringa = InputBox(“Secondo valore:”)

della funzione Val. Tale dato è successivamente sottoposto a verifica per determinarne la conformità alle condizioni richieste. Qualora essa non fosse riscontrata, la presenza del ciclo fa sì che sia richiesto nuovamente il dato all’utente. Si noti che le due strutture di iterazione sono estremamente simili. Ciò che cambia è rappresentato solamente dalla variabile da acquisire e dal valore massimo consentito. Se Visual Basic disponesse di un’istruzione in grado di richiedere un dato e di verificarne l’appartenenza ad un intervallo, il codice sarebbe notevolmente più semplice e privo di ripetizioni. Una simile istruzione non è prevista nella libreria standard dello strumento di sviluppo. Tuttavia, come tutti i linguaggi di programmazione moderni, Visual Basic permette la creazione di procedure, o subroutine. Esse rappresentano gruppi di istruzioni racchiuse in strutture identificate univocamente dai propri nomi. Una sequenza di questo tipo può essere eseguita più volte all’interno di un programma senza che sia necessario ripeterne il codice; basta infatti richiamarla indicandone il nome. La definizione di una procedura prevede la seguente sintassi: [Public|Private] Sub <nome> [(<definizione_parametro_1>, ... <definizione_parametro_n>)] [<dichiarazione_variabili_locali>] <istruzione_1> ... <istruzione_n> End Sub

Dopo la parola chiave Sub è necessario specificare un identificatore che costituisce il nome della struttura. Come tutti gli altri identificatori, deve essere composto da lettere, numeri o dal carattere di sottolineatura (undescore) e il primo carattere deve essere necessariamente costituito da una lettera dell’alfabeto. Si noti che non è la prima volta che si usa la parola chiave Sub all’interno di questo corso. Infatti, le porzioni di codice da associare come risposta agli eventi sono anch’esse delle procedure. Quando un controllo genera un evento, l’interprete provvede automaticamente a verificare l’esistenza di una procedura avente un nome composto dall’identificatore del controllo seguito dal carattere di sottolineatura e dal tipo di evento (ad esempio btnPulsante_Click). Se tale struttura esiste, è eseguita. Le procedure oggetto di trattazione in questa lezione sono invece definite dall’utente con lo scopo di migliorare la leggibilità del programma e riciclare il codice già scritto, evitando la ripetizione di linee pressoché identiche. Le procedure, analogamente alle variabili, sono soggette alle regole di scope. Pertanto, se sono definite all’interno di un form, risultano locali a quest’ultimo, quindi

○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○

PROGRAMMO SUBITO n.8 - SETTEMBRE 1998 87


pressoché invisibili agli altri moduli. Qualora si desiderasse creare delle procedure globali, da utilizzare indifferentemente in tutti i form come se si trattasse di comandi standard previsti dal linguaggio di programmazione, è necessario creare un nuovo modulo globale, agendo sul menu Progetto alla voce Inserisci modulo. L’uso dei moduli globali permette anche di creare delle librerie di procedure che possono essere agevolmente riutilizzate per lo sviluppo di altre applicazioni, semplicemente includendo il file all’interno dei progetti.

UNA FUNZIONE IN UN MODULO Per inserire una procedura in un modulo occorre selezionare il file nella finestra Progetto e premere il pulsante di visualizzazione del codice. A questo punto è possibile utilizzare la voce Inserisci routine del menu Strumenti. Appare così una finestra che permette di specificare il nome della procedura, unitamente ad altre opzioni che per ora non saranno descritte. Agendo in questo modo sul form di avvio dell’applicazione descritta nell’esempio precedente, è possibile inserire in esso la procedura LeggiValore, in grado di leggere un dato e di convertirlo in un valore numerico. La sua definizione è la seguente: Sub LeggiValore() Dim Stringa As String Do Stringa = InputBox(MessaggioRichiesta) n = Val(Stringa) Loop Until (n > 0) And (n < Massimo) End Sub

Si noti la dichiarazione della variabile Stringa, che risulta locale alla procedura, essendo stata definita al suo interno. Pertanto, è creata quando il programma inizia ad eseguire la routine ed è distrutta in corrispondenza dell’uscita dal blocco di codice. Risulta quindi evidente che il suo valore non può essere utilizzato al di fuori della procedura. Inoltre, non è conservato nelle chiamate successive, a meno che non si sostituisca la parola chiave Dim con Static. In questo caso, la variabile è detta statica. Tornando alla procedura LeggiValore, si nota che essa fa riferimento anche alle variabili n, MessaggioRichiesta e Massimo, di cui tuttavia non è specificata la definizione. Ciò è corretto se si tratta di due variabili globali, ovvero se sono definite all’interno della sezione Generale del form o in un modulo globale facendo uso della parola chiave Global. Nel primo caso esse risultano visibili a tutte le procedure definite all’interno del form. Nel secondo, possono essere utilizzate addirittura da tutte le routine contenute nell’applicazione. Con l’introduzione della procedura LeggiValore, il codice da associare all’evento Load del form principale, diventa il seguente: Private Sub Form_Load() Dim Stringa As String Dim n1 As Double Dim n2 As Double Dim Somma As Double Rem Primo valore MessaggioRichiesta = “Primo valore:” Massimo = 10 LeggiValore n1 = n Rem Secondo valore MessaggioRichiesta = “Secondo valore:” Massimo = 50 LeggiValore n2 = n

88 SETTEMBRE 1998 - PROGRAMMO SUBITO n.8

Somma = n1 + n2 MsgBox (“La somma è “ & Somma) End Sub

Si noti l’uso delle variabili globali per comunicare alla procedura il valore massimo accettabile, nonché il messaggio da visualizzare. Si noti altresì che la routine provvede ad utilizzare un’altra variabile globale (n) per restituire il valore letto. Questo primo esempio di utilizzo di una procedura ha sortito un effetto pressoché deludente, in quanto non ha comportato una sensibile semplificazione del codice. Ciò a causa della necessità di utilizzare delle variabili globali per scambiare le informazioni fra i due blocchi di istruzioni e dalla conseguente presenza di numerose operazioni di assegnamento. Al fine di ottenere un consistente miglioramento della leggibilità del codice, nonché una sua semplificazione, è necessario modificare la procedura LeggiValore per fare in modo che sia in grado di accettare dei parametri, ovvero che permetta di inizializzare le variabili MessaggioRichiesta e Massimo nel momento della sua invocazione, senza che sia richiesto l’uso delle istruzioni di assegnamento.

I PARAMETRI Il metodo più semplice ed efficace per comunicare delle informazioni a una procedura consiste nell’uso dei parametri, ognuno dei quali deve essere dichiarato secondo la sintassi: [ByVal|ByRef] <nome> As <Tipo>

Un parametro, talvolta detto argomento, per il codice contenuto all’interno della routine equivale a una variabile. Da essa si differenzia per il fatto che la sua inizializzazione non avviene all’interno della procedura, bensì quando essa è richiamata. Si supponga ad esempio di definire la seguente subroutine: Sub Prova(Param1 As String, Param2 As Integer) MsgBox(Param1 & “-” & Param2) End Sub

Se si digita la riga Prova “Dev”, 1998

si richiama la procedura Prova e si inizializzano i parametri Param1 e Param2 rispettivamente con la stringa “Dev” e con il numero 1998. Il messaggio visualizzato è pertanto il seguente: Dev-1998

Si noti che un parametro può essere di un qualsiasi tipo base previsto da Visual Basic. Come accade per le variabili, se il formato non è dichiarato, il dato è considerato Variant. La procedura LeggiValore può pertanto essere riscritta in modo da accettare come parametri il messaggio da visualizzare al momento della richiesta del dato e il valore massimo consentito. Sub LeggiValore(MessaggioRichiesta As String, Massimo As Integer) Dim Stringa As String Do Stringa = InputBox(MessaggioRichiesta) n = Val(Stringa) Loop Until (n > 0) And (n < Massimo) End Sub

Per effetto di questa modifica, il codice da associare al caricamento del form principale si semplifica notevolmente:

○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○


Sub Form_Load() Dim n1 As Double Dim n2 As Double Dim Somma As Double LeggiValore “Primo valore:”, 10 n1 = n LeggiValore “Secondo valore:”, 50 n2 = n Somma = n1 + n2 MsgBox (“La somma è “ & Somma) End Sub

Le modifiche apportate fanno sì che non sia più necessario dichiarare le variabili globali MessaggioRichiesta e Massimo. Un’ulteriore semplificazione potrebbe essere introdotta rendendo la procedura in grado di aggiornare automaticamente le variabili n1 e n2. Ciò è possibile introducendo un terzo parametro. La procedura LeggiValore diventa pertanto la seguente: Sub LeggiValore(MessaggioRichiesta As String, Massimo As Integer, n As Double) Dim Stringa As String Do Stringa = InputBox(MessaggioRichiesta) n = Val(Stringa) Loop Until (n > 0) And (n < Massimo) End Sub

Il codice da eseguire in fase di caricamento del form diventa: Sub Form_Load() Dim n1 As Double Dim n2 As Double Dim Somma As Double LeggiValore “Primo valore:”, 10, n1 LeggiValore “Secondo valore:”, 50, n2 Somma = n1 + n2 MsgBox (“La somma è “ & Somma) End Sub

L’applicazione ora non necessità più di alcuna variabile globale.

considerato dall’interprete come passato per riferimento. È quindi evidente che la clausola ByRef risulta di fatto superflua, in quanto ha solo lo scopo di rendere il codice più rapidamente comprensibile. Passaggio dei parametri per valore Se nella dichiarazione di un parametro si antepone la clausola ByVal, si stabilisce che l’informazione è passata per valore. Ciò significa che la procedura riceve un valore ma non la facoltà di variarlo. In pratica il dato deve essere considerato dalla routine alla stregua di una costante. In realtà, la procedura può effettuare delle modifiche al valore del parametro, ma esse non hanno effetto nel blocco chiamante. Ad esempio, si supponga di dichiarare le seguenti procedure: Sub Prova1(ByVal Testo As String) Testo = Testo & “ 5.0” MsgBox Testo End Sub Sub Prova2(ByRef Testo as String) Testo = Testo & “ 5.0” MsgBox Testo End Sub

Si supponga altresì di dichiarare una variabile di tipo stringa denominata Messaggio e di inserirvi la frase “Visual Basic”. La riga Prova1 Messaggio

provoca pertanto la visualizzazione di una finestra in cui appare la scritta “Visual Basic 5.0”. Il contenuto della variabile Messaggio, tuttavia, non varia, in quanto essa è stata passata per valore. Al contrario, l’esecuzione della riga Prova2 Messaggio

provoca la visualizzazione di una finestra perfettamente identica a quella descritta in precedenza, ma comporta anche la modifica del contenuto della variabile Messaggio.

LE MODALITÀ DI PASSAGGIO DEI PARAMETRI

DUE SEMPLICI ESERCIZI

I parametri possono essere passati a una procedura secondo due diverse modalità: per valore e per riferimento; la scelta è effettuata utilizzando per ogni singolo parametro in alternativa le clausole ByVal o ByRef.

Al fine di verificare la comprensione degli argomenti esposti, si provi a realizzare una procedura in grado di restituire il valore assoluto di un numero intero, usando a tal fine un parametro passato per riferimento. Si realizzi poi una seconda procedura che richiami la prima per calcolare la somma dei valori assoluti di 3 numeri passati come parametri per valore.

Passaggio dei parametri per riferimento Nell’esempio precedente, la variabile n è stata passata alla procedura LeggiValore non per fornire ad essa un’informazione, bensì per fare in modo che sia la routine a restituire un valore al blocco di istruzioni chiamante. Infatti, nel momento in cui è eseguita la riga LeggiValore “Primo valore:”, 10, n1

alla variabile n1 non è stato ancora assegnato un valore. Questo compito spetta alla procedura. Si dice allora che la variabile n1 è stata passata per riferimento, ovverosia che è stato fornito alla procedura l’indirizzo della locazione di memoria in cui risiede n1 per fare in modo che il dato in essa contenuto sia modificato. Questo è metodo di passaggio delle informazioni predefinito in Visual Basic. Quando alla dichiarazione di un parametro non è anteposta la clausola ByVal, esso è

CONCLUSIONI Un uso corretto delle procedure è di fondamentale importanza per la scrittura di codice leggibile e di facile manutenzione. Inoltre, il loro raggruppamento in librerie permette di creare dei moduli che possono essere riutilizzati nella realizzazione di applicazioni da parte di uno o più utenti come se si trattasse di estensioni del linguaggio di programmazione.

Maurizio Crespi si occupa principalmente di grafica e multimedia. Svolge la funzione di responsabile tecnico presso Datanord Multimedia, società specializzata nella realizzazione di software orientato al marketing e all’editoria, per la quale progetta e sviluppa applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato per e-mail come crespi@programmers.net.

○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○ ○

PROGRAMMO SUBITO n.8 - SETTEMBRE 1998 89


.

Corso di Visual Basic (Parte 9) di Maurizio Crespi

La nona lezione del corso dedicato alla programmazione in Visual Basic si pone lo scopo di illustrare le funzioni definibili dall'utente e il concetto di ricorsione Nella scorsa lezione sono state descritte le subroutine e sono stati evidenziati i benefici che il loro uso dà al programmatore. Questo mese l'argomento sarà ulteriormente approfondito con l'introduzione delle funzioni, ovvero di procedure in grado di restituire un valore senza l'ausilio di una variabile globale o di un parametro passato per riferimento, nonché con la descrizione dell'uso avanzato che è possibile fare di esse. Prima però è opportuno compiere un passo indietro per riportare alla mente i concetti esposti nella precedente puntata del corso. Come sempre, il fine è raggiunto mediante l'illustrazione delle soluzioni degli esercizi in essa proposti.

Le soluzioni degli esercizi della scorsa lezione Si tratta di due semplicissimi esercizi, il cui scopo è quello di aiutare il lettore a riconoscere la differenza fra la modalità di passaggio dei parametri per valore e quella per riferimento. Primo esercizio Il primo esercizio prevede la realizzazione di una procedura in grado di restituire il valore assoluto di un numero intero per mezzo di un parametro passato per riferimento. Dai testi scolastici è noto che il valore assoluto di un numero è pari ad esso se è positivo oppure, in caso contrario, al suo opposto. Volendo fare a meno di ricorrere alla funzione Abs prevista dalla libreria standard, è possibile effettuare il calcolo per mezzo di una struttura If. La soluzione dell'esercizio è pertanto la seguente: Sub ValAssoluto(ByVal Numero As Double, ByRef Risultato As Double) If Numero > 0 Then Risultato = Numero Else Risultato = -1 * Numero End If End Sub Si noti che il numero di cui deve essere calcolato il valore assoluto è fornito alla procedura tramite un parametro passato per valore. Si supponga ora di voler eseguire la seguente porzione di codice: r=0 n=45

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


.

ValAssoluto n, r MsgBox(Str$(r)) Un eventuale tentativo da parte della routine di modificare il dato fornitole come primo parametro non ha effetto sulla variabile n posta nel blocco di codice chiamante. Diverso è invece il discorso per quanto riguarda la variabile r. Essa, infatti, è passata come parametro per riferimento; la procedura può quindi intervenire direttamente sul suo valore. Ciò permette alla routine di restituire un dato senza far uso di variabili globali. Secondo esercizio Il secondo esercizio richiede la realizzazione di una procedura in grado di richiamare quella appena illustrata per calcolare la somma dei valori assoluti di 3 numeri passati come parametri per valore. La soluzione è banale ed è rappresentata dal codice riportato di seguito: Sub SommaVAssoluti(ByVal n1 As Double, ByVal n2 As Double, ByVal n3 As Double, ByRef Somma As Double) Dim r1 As Double Dim r2 As Double Dim r3 As Double ValAssoluto n1, r1 ValAssoluto n2, r2 ValAssoluto n3, r3 Somma = r1 + r2 + r3 End Sub Anche in questo caso, il risultato è restituito al blocco di codice chiamante per mezzo di un parametro passato per riferimento.

Le funzioni Un sensibile miglioramento della leggibilità del codice e della comodità d'uso dello strumento di sviluppo deriva dalla possibilità di restituire un valore evitando l'uso di una variabile globale o di un parametro passato per riferimento. Ciò è possibile per mezzo delle funzioni. Il linguaggio prevede una quantità elevatissima di funzioni standard. Ad esempio, per calcolare il valore assoluto di un numero, esiste la funzione Abs, che riceve in ingresso un dato numerico e ne restituisce il modulo. La riga x = Abs(y) fa sì che alla variabile x sia assegnato il valore assoluto del numero contenuto nella variabile y. Come accade per le procedure, è possibile incrementare l'insieme delle funzioni disponibili creandone ad hoc per soddisfare le proprie esigenze. A tal fine è necessario racchiudere le istruzioni in strutture dichiarate per mezzo della parola chiave Function, secondo la sintassi di seguito riportata: [Public|Private] Function <nome> [(<definizione_parametro_1>, ... <definizione_parametro_n>)] As <tipo> [<dichiarazione_variabili_locali>] <istruzione_1> ... <istruzione_n> <nome>=<valore> End Function Com'è possibile notare, l'analogia con le procedure è notevole. A differenza di esse, è necessario indicare un tipo di dati standard al termine della riga di dichiarazione. Esso identifica il formato in cui deve essere restituito il risultato. È inoltre necessario fare in modo che all'interno del blocco di codice sia presente una riga che preveda l'assegnamento di un valore a una variabile avente lo stesso nome della funzione. Tale dato è quello restituito al blocco chiamante. file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


.

Si supponga di voler realizzare una semplice funzione in grado di moltiplicare un numero intero per 4. Il codice necessario è il seguente: Function Quadruplo(Numero As Integer) Quadruplo = Numero * 4 End Function Il valore assunto dal parametro Numero è moltiplicato per 4 e restituito dalla funzione. È possibile utilizzare la struttura appena creata in un'istruzione di assegnamento scrivendo il suo nome seguito dai parametri posti fra parentesi tonde, come nell'esempio che segue, in cui il risultato della valutazione della funzione Quadruplo è assegnato alla variabile x. x = Quadruplo(y) Lo stesso scopo può essere ottenuto anche per mezzo di una procedura dotata di un parametro passato per riferimento. In questo caso il codice è il seguente: Sub Quadruplo(Numero As Integer, Risultato As Integer) Risultato = Numero * 4 End Sub In questo caso, volendo assegnare alla variabile x il risultato, è necessario scrivere: Quadruplo(y,x) Pur essendo le due soluzioni del tutto equivalenti, appare evidente la maggiore semplicità della prima. Si noti che una funzione può restituire un solo valore. Qualora si presentasse la necessità di fornire al blocco chiamante più di un'informazione, è necessario ricorrere ai parametri passati per riferimento. Esercizio Si provi a realizzare una funzione in grado di ricevere come parametro una stringa alfanumerica e restituire il valore logico True se essa contiene il nome di un giorno della settimana.

La ricorsione Si supponga di voler realizzare una funzione in grado di calcolare il fattoriale di un numero intero. Ricordando che il fattoriale è definito solo per valori numerici positivi o nulli (in quest'ultimo caso giova ricordare che il fattoriale di 0 è 1), è possibile prevedere la seguente implementazione: Function Fattoriale(ByVal n As Integer) As Long Dim i As Integer Dim Risultato As Long If n >= 0 Then Risultato = 1 For i = 2 To n Risultato = Risultato * i Next i Else Risultato = 0 End If Fattoriale = Risultato End Function Si tratta di una funzione in grado di ricevere come parametro (per valore) un dato di tipo numerico intero e di restituire un long. L'algoritmo prevede dapprima la verifica che il numero oggetto di elaborazione sia positivo o nullo; successivamente, esegue un ciclo che provvede ad effettuare la serie di moltiplicazioni necessaria per il calcolo del risultato.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


.

Tale valore è infine assegnato alla funzione per fare in modo che essa lo restituisca. Si noti che se il dato fornito in ingresso è negativo, la funzione restituisce il valore 0. Ciò è accettabile, non essendo possibile che il fattoriale di un numero sia nullo; si tratta quindi di un valido indicatore della presenza di un errore. L'algoritmo appena descritto non è l'unico in grado di effettuare il calcolo del fattoriale di un numero. Ad esempio, è possibile scrivere la seguente implementazione: Function Fattoriale(ByVal n As Integer) As Long If n >= 0 Then If n = 0 Then Fattoriale = 1 Else Fattoriale = n * Fattoriale(n - 1) End If End If End Function Il numero delle righe di codice si è ridotto, a vantaggio della leggibilità. Tuttavia, a prima vista il lettore può rimanere sconcertato dall'uso della funzione Fattoriale all'interno della propria definizione. Ciò può apparire come un errore. In realtà, tale tecnica è perfettamente lecita e prende il nome di ricorsione. Per rendersi conto del corretto funzionamento, si provi ad osservare ciò che avviene calcolando il fattoriale di un numero qualsiasi, ad esempio 3. Essendo n pari a 3, la funzione esegue il calcolo Fattoriale(3)=3*Fattoriale(2) Ma, analogamente Fattoriale(2)=2*Fattoriale(1) e Fattoriale(1)=1*Fattoriale(0) Per mezzo di una struttura If , è distinto il caso in cui n è nullo. In questa condizione la funzione restituisce il valore 1. Quindi, Fattoriale(3)=3*(2*(1*(1))) Ciò concorda con la definizione matematica del fattoriale. L'uso della ricorsione permette in alcuni casi di semplificare notevolmente la scrittura di una funzione e di migliorarne al tempo stesso la leggibilità. Tuttavia, presenta numerose insidie. Si provi a valutare il risultato prodotto dalla riga Calcola(7) dove la funzione Calcola è definita come segue: Function Calcola(n As Integer) As Integer Calcola = n + Calcola(n - 1) End Function Il risultato è costituito da un errore di sistema. Infatti, non essendo prevista alcuna condizione di uscita, ovvero non esistendo un valore del parametro per cui è restituito un risultato non dipendente da una successiva chiamata della funzione, si genera una successione di invocazioni di quest'ultima destinata a non avere fine, almeno sino all'esaurimento dello spazio di memoria dedicato allo stack del sistema. Appare quindi

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


.

evidente una condizione fondamentale che deve essere soddisfatta da tutte le funzioni ricorsive: deve sempre essere prevista una condizione di uscita. È bene tuttavia non abusare della ricorsione. Infatti, sebbene in alcuni casi semplifichi notevolmente il compito del programmatore, talvolta può comportare un sensibile aumento della richiesta di risorse da parte del sistema, data la necessità che esso ha di mantenere contemporaneamente attive più istanze della stessa funzione. Esercizio Si provi a realizzare una funzione che, dato un parametro n intero positivo passato per valore, sia in grado di restituire la somma dei primi n numeri naturali. A tal fine si faccia uso della ricorsione.

La procedura Main Lo studio delle subroutine termina con una procedura un po' particolare, la cui importanza è tutt'altro che trascurabile. Si tratta della procedura Main. Un'applicazione realizzata in Visual Basic è generalmente dotata di un'interfaccia utente grafica, in cui l'interazione con gli elementi attivi determina il flusso del programma. Tuttavia, in alcuni casi, soprattutto per la realizzazione di semplici utility in grado di operare in modo invisibile all'utente, è necessario sopprimere l'interfaccia grafica. Quando ciò avviene, il progetto risulta privo di form. Il codice deve pertanto essere posto altrove, ovvero all'interno di moduli. Affinché una sequenza di istruzioni sia eseguita all'avvio di un'applicazione è necessario inserirla all'interno di una procedura denominata Main. Occorre inoltre selezionare tale routine come oggetto di avvio nella finestra delle proprietà del progetto in luogo di un form. Una semplice procedura Main è la seguente: Sub Main() If Date$ = "12-25-1998" Then MsgBox "Buon Natale" End If End Sub Si tratta di una piccola applicazione che può essere eseguita automaticamente all'avvio di Windows e che normalmente non fornisce alcun feedback all'utente. Solo il giorno di Natale del 1998 essa ha un effetto visibile, in quanto provvede a visualizzare un messaggio di auguri. Si noti l'uso della funzione standard Date$ che restituisce una stringa contenente la data corrente. Il ricorso alla procedura Main non è tuttavia riservato solo alle applicazioni prive di form. A volte può essere utile fare in modo che un programma all'avvio sia in grado di valutare una condizione e in base ad essa scegliere fra i form che lo compongono quello che deve essere visualizzato. Si supponga di disporre di una funzione denominata SelezionaForm, di cui saranno trascurati i dettagli implementativi, in grado di leggere il registro di sistema per determinare la lingua utilizzata dalla versione in uso del sistema operativo e di restituire una stringa contenente una delle seguenti sequenze alfanumeriche: "Italiano", "Inglese", "Tedesco", "Francese". Si supponga altresì di aver realizzato un progetto caratterizzato dalla presenza di 4 form, differenti fra loro per la lingua in cui sono scritte le etichette che identificano i controlli e di aver dato ad essi rispettivamente i nomi Ita, Ing, Ted, Fra. È allora possibile scrivere una procedura Main in grado di avviare il form corrispondente alla lingua presente nel sistema. Il codice è il seguente: Sub Main() Select Case SelezionaForm() Case "Italiano": Ita.Show vbModal Case "Inglese": Ing.Show vbModal Case "Tedesco": Ted.Show vbModal Case "Francese" file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


.

Fra.Show vbModal End Select End Sub Si notino alcune particolarità; la funzione SelezionaForm, ad esempio, non prevede parametri. Affinché sia utilizzabile correttamente, è comunque necessario richiamarla specificando le parentesi, sebbene fra esse non sia posto alcun dato o nome di variabile. Si noti inoltre l'uso del metodo Show, che permette di avviare il caricamento e la successiva visualizzazione di un form. L'uso della costante predefinita vbModal accanto ad esso stabilisce che la procedura in fase di esecuzione non può passare all'istruzione successiva finché il form risulta visibile. Solo dopo la sua chiusura il flusso delle istruzioni può riprendere e, non essendo presente altro codice, il programma può terminare.

Conclusioni Le procedure e le funzioni sono strumenti estremamente efficaci, in grado di fornire un notevole aiuto al programmatore. I moderni linguaggi di programmazione orientati agli eventi, come Visual Basic, si fondano in modo pressoché totale sulla presenza di tali strutture. L'acquisizione della necessaria dimestichezza nel loro uso diventa pertanto un obbligo per colui che desidera sfruttare al meglio le potenzialità dello strumento. Per questo motivo, ancora una volta la lezione si chiude rivolgendo al lettore un invito ad esercitarsi sugli argomenti trattati, servendosi a tal fine anche degli esercizi proposti.

Maurizio Crespi si occupa principalmente di grafica e multimedia. Svolge la funzione di responsabile tecnico presso Datanord Multimedia, società specializzata nella realizzazione di software orientato al marketing e all'editoria, per la quale progetta e sviluppa applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato per e-

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB09/index.htm[26/09/2010 1:14:19]


. Figura1

Figura2 Listato1

Corso di Visual Basic Questo mese il corso dedicato alla programmazione in Visual Basic ha come obbiettivo la gestione dei file di testo, ovvero del più semplice formato di memorizzazione permanente previsto dallo strumento Microsoft

Corso di Visual Basic - parte X di Maurizio Crespi La maggior parte delle applicazioni deve essere in grado di memorizzare delle informazioni su un supporto di memoria di massa, costituito in genere da un'unità a disco, in modo tale da renderle reperibili nelle sessioni successive. La struttura destinata ad accogliere questi dati, oggetto di studio in questa lezione, prende il nome di file. Le soluzioni degli esercizi proposti nella scorsa lezione Prima di avventurarsi nello studio dei file, è bene focalizzare come di consueto l'attenzione sugli esercizi proposti nello scorso numero. Eccone, in breve, le soluzioni. Primo esercizio Il primo esercizio prevede lo sviluppo di una funzione booleana in grado di ricevere come parametro una stringa alfanumerica e di restituire True se essa contiene il nome di un giorno della settimana. In caso contrario, il valore ritornato deve essere False. La soluzione, pressoché banale, è la seguente: Function Giorno(Stringa As String) As Boolean Dim Risultato As Boolean Select Case UCase(Stringa) Case "LUNEDI", "MARTEDI", "MERCOLEDI", "GIOVEDI", "VENERDI", "SABATO", "DOMENICA" Risultato = True Case Else Risultato = False End Select Giorno = Risultato End Function

Il valore restituito corrisponde a quello della variabile Risultato, che è aggiornato da una semplice struttura Select Case effettuata sulla stringa convertita in maiuscolo. Secondo esercizio Il secondo esercizio prevede la realizzazione di una funzione ricorsiva che, dato un parametro n intero positivo passato per valore, sia in grado di restituire la somma dei primi n numeri naturali. La soluzione è rappresentata dalla funzione Calcola descritta di seguito. Function Calcola(n As Integer)As Long Dim Somma As Long If n > 0 Then Somma = n + Calcola(n - 1) End If Calcola = Somma End Function Se il parametro n ha un valore non nullo, è sommato al risultato dell'applicazione della funzione a n-1. Se invece n è uguale a zero, si verifica la condizione di uscita. I file Un file è un agglomerato di informazioni residente su un supporto di memorizzazione di massa, ovvero su un dispositivo caratterizzato dalla capacità di mantenere i dati anche dopo lo spegnimento e il successivo riavvio del sistema. Di solito si tratta di un'unità a disco fisso o rimovibile. Le informazioni contenute in un file non devono essere necessariamente di tipo omogeneo. Esiste infatti la possibilità di creare dei file strutturati, in grado cioè di contenere elementi di pari caratteristiche, oppure composti da informazioni di natura anche profondamente diversa. Visual Basic permette di creare 3 diversi tipi di file, con accesso sequenziale o casuale. In questa lezione sono oggetto di studio le strutture ad accesso sequenziale.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb10/index.htm[26/09/2010 5:12:01]


.

I file ad accesso sequenziale Le strutture più elementari sono i file ad accesso sequenziale, il cui uso è in genere riservato alla memorizzazione delle informazioni testuali. Si tratta di strutture organizzate in righe, da utilizzare quando si desidera salvare dei documenti da stampare oppure per la memorizzazione di limitate quantità di dati (come ad esempio quelle riguardanti le impostazioni di un programma). Il vantaggio offerto dai file ad accesso sequenziale è rappresentato dalla semplicità con cui è possibile accedere al loro contenuto mediante un qualsiasi editor di testo, come il Blocco Note di Windows. Sono di questo tipo, ad esempio, i file Win.ini e System.ini, contenenti le informazioni riguardanti la configurazione dell'ambiente Windows a 16 bit. L'organizzazione dei dati, tuttavia, fa sì che le strutture di questo tipo non siano adatte a contenere una grande quantità di informazioni, a causa del dilatarsi dei tempi di accesso dovuto al fatto che la ricerca di un particolare dato può comportare la lettura dell'intero file. L'apertura di un file sequenziale Un file, di qualsiasi tipo esso sia, per poter essere utilizzato deve necessariamente essere aperto. È possibile effettuare ciò per mezzo del comando Open, la cui sintassi, per le strutture ad accesso sequenziale, è la seguente: Open <percorso_file> [For <modalità>] As [#]<numero_identificatore> [Len=<lunghezza_record>]

dove <percorso_file> è una stringa che identifica il percorso del file che si desidera creare o leggere. Se si sta usando una versione a 32 bit dello strumento e quindi si sta realizzando un'applicazione funzionante solo su Windows 95, 98 o NT, è possibile far uso dei nomi di file lunghi. Ciò non è consentito invece alle applicazioni destinate ad essere compilate con una versione a 16 bit di Visual Basic. In questo caso, occorre adeguarsi al formato previsto da MS-DOS e dalla macchina virtuale a 16 bit di Windows, che prevede un massimo di 8 caratteri per i nomi dei file e di 3 per le estensioni. Il carattere separatore è in tutti i casi costituito dalla barra retroversa "\".Dopo aver specificato il nome del file da gestire, è necessario indicare la modalità con cui si desidera accedere ad esso. La scelta è fra Input, Output e Append. Nel primo caso, il file è aperto in lettura, ovvero è utilizzato esclusivamente per reperire delle informazioni senza effettuare su di esse alcuna modifica. È evidente che l'apertura di un file in questa modalità richiede che esso sia stato in precedenza creato sul disco, altrimenti provoca la notifica di un errore.Diversamente accade invece per i file aperti in output. In questo caso, infatti, si provoca la generazione di una nuova struttura e la sovrascrittura del file eventualmente già presente sul disco con il nome specificato dopo la parola chiave Open. Com'è facile intuire, l'accesso in output ha il fine di permettere la scrittura delle informazioni sui file. In alcuni casi, tuttavia, risulta necessario inserire all'interno di uno di essi dei nuovi dati senza distruggere quelli inseriti in una o più sessioni precedenti. La modalità da utilizzare per raggiungere tale scopo è denominata Append. Il numero identificatore Dopo aver dichiarato l'uso che si desidera fare del file, è necessario assegnare ad esso un numero, che ne costituisce un identificatore univoco. Tale valore deve essere un intero compreso fra 1 e 511 e va specificato dopo la parola chiave As. Per le strutture non destinate alla condivisione con altre applicazioni, è opportuno utilizzare i numeri compresi fra 1 e 255, riservando i rimanenti ai file che devono essere resi accessibili da più processi nello stesso momento. Si noti che, per compatibilità con il linguaggio BASIC classico, il numero di identificazione si può far precedere dal carattere #. Il parametro Len L'ultimo parametro che resta da esaminare è quello che definisce la lunghezza di ogni blocco di informazioni interessato dalle operazioni di lettura o scrittura. Esso è opzionale e rappresenta la dimensione dello spazio di memoria temporanea (denominato buffer) allocato dal sistema. Tale valore non può essere superiore a 32767. L'istruzione Close Se il comando Open rende possibile accedere a un file e crea per esso un identificatore, l'effetto contrario, ovvero il rilascio della struttura e l'eliminazione del numero di riferimento, è sortito dall'istruzione Close. Si supponga di aver aperto un file e di aver assegnato ad esso l'identificatore 1. La riga Close #1

determina la fine dell'uso della struttura da parte del programma, pur rendendone possibile la successiva riapertura. Il numero di riferimento ritorna così ad essere utilizzabile per la gestione di un altro file. La lettura di un file di testo

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb10/index.htm[26/09/2010 5:12:01]


.

Si supponga di voler realizzare un'applicazione in grado di visualizzare in una casella di testo il contenuto del file di sistema Win.ini. In primo luogo, è necessario disegnare un form analogo a quello rappresentato nella figura 1, in cui è presente una textbox, che si suppone denominata txtTesto. È poi necessario fare in modo che all'avvio del programma essa sia riempita con il testo contenuto nel file da leggere. A tal fine, si può associare il seguente codice all'evento Load del form: Private Sub Form_Load() Dim Riga As String txtTesto.Text = "" Open "c:\windows\win.ini" For Input As #1 Do Until EOF(1) Line Input #1, Riga txtTesto.Text = txtTesto.Text & Riga & Chr$(13) & Chr$(10) Loop Close #1 End Sub

Dopo aver eliminato i caratteri eventualmente presenti nella textbox, la procedura provvede ad aprire in input il file, che si suppone contenuto nella cartella "C:\Windows" e ad associargli il numero identificatore 1. Tutte le operazioni che in seguito sono effettuate sul file sono prodotte da istruzioni riceventi tale valore come parametro.Il file da leggere è notoriamente composto da testo organizzato in righe. Lo scopo dell'applicazione illustrata in questo esempio è di leggere tutte le righe e di copiarle, una di seguito all'altra, nella textbox. A tal fine è necessario creare un ciclo in grado di svolgere le operazioni di lettura. La condizione che deve causare il termine delle iterazioni è rappresentata dal raggiungimento della fine del file. Ciò si verifica quando tutti i dati sono stati letti. Il file, tuttavia, potrebbe anche essere vuoto. È pertanto necessario fare in modo che il ciclo preveda il test all'ingresso, ovvero che la condizione sia specificata accanto alla parola chiave Do, al fine di evitare le iterazioni quando essa risulti vera già immediatamente dopo l'esecuzione del comando Open. La funzione EOF Un file sequenziale può essere paragonato a un nastro magnetico. Per sapere se l'ipotetica testina di lettura ha raggiunto la posizione di fine, è necessario ricorrere alla funzione EOF (End Of File), alla quale, come di consueto, va passato come parametro il numero identificatore della struttura a cui si desidera far riferimento. Il valore restituito è di tipo logico e vale True se è raggiunta la fine del file; ovviamente, in caso contrario, il risultato è False. La funzione Line Input La lettura di una riga di un file di testo è effettuata per mezzo dell'istruzione Line Input. Essa prevede due parametri; il primo è costituito ancora una volta dall'identificatore del file su cui è eseguita l'operazione. Il secondo, invece, è rappresentato dalla variabile di tipo stringa destinata ad ospitare la riga di testo da leggere. Nell'esempio è stata utilizzata la variabile denominata Riga. In esso, il dato letto è aggiunto al contenuto della casella testuale per mezzo dell'operatore di concatenazione di stringhe (&). Si noti che per passare alla riga successiva della textbox si fa uso di una sequenza composta dal carattere di ritorno del carrello (Chr$(13)) e da quello di avanzamento di una riga (Chr$(10)). La scrittura su un file di testo Si supponga ora di voler realizzare un programma in grado di effettuare l'esatto contrario del precedente, ovvero di trasferire su un file di testo il contenuto di una textbox. La sua implementazione risulta estremamente semplice. In pratica richiede esclusivamente l'uso di un'istruzione Print.Si consideri il form rappresentato in figura 2, caratterizzato dalla presenza di 3 pulsanti. Il primo è denominato btnCarica ed ha lo scopo di caricare nella textbox txtTesto il contenuto del file di cui è specificato il nome nella casella txtNomeFile. Un secondo pulsante, denominato btnCancella, ha lo scopo di eliminare il contenuto della textbox, mentre il terzo serve per memorizzare in un file le informazioni presenti all'interno del controllo txtTesto. Il codice è riportato nel listato 1. Si noti che la procedura che si occupa del caricamento dei dati è pressoché identica a quella dell'esempio precedente; si differenzia solo perché il nome del file da leggere è acquisito dal controllo txtNomeFile, anziché essere fisso. Il salvataggio del file sul disco è eseguito in modo estremamente semplice; in pratica il programma non deve far altro che aprire il la struttura in output ed eseguire su di essa l'istruzione Print, la quale riceve come parametri, rispettivamente, il numero identificatore e la stringa da scrivere, nella fattispecie costituita dal contenuto del controllo txtTesto. Un semplice esercizio Per esercitarsi sugli argomenti esposti, si provi a realizzare un'applicazione in grado di leggere, per mezzo di opportune textbox, tre valori numerici interi e una stringa. Si preveda poi la possibilità di salvarli in un file in seguito alla pressione di un pulsante. Mediante un altro bottone, si faccia in modo che l'utente possa ripristinare all'interno delle caselle di testo i valori salvati sul disco. Nella prossima lezione…

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb10/index.htm[26/09/2010 5:12:01]


.

I file di testo sono solo un tipo di struttura di memorizzazione permanente su supporti di memoria di massa. Visual Basic permette di gestire anche dei file strutturati in modo diverso, adatti per esigenze differenti e per realizzazioni più impegnative, quali ad esempio quelle che accedono a una grande quantità di informazioni in modo non conforme a uno schema rigidamente sequenziale come quello descritto nei paragrafi precedenti. Per sapere com'è possibile fare ciò, occorre semplicemente attendere la prossima lezione. Bibliografia Visual Basic 5- McGrawHill – ISBN 88-386-0436-3

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb10/index.htm[26/09/2010 5:12:01]


Figura 1 L

Figura 1 L'applicazione che visualizza il contenuto del file Win.ini

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb10/figura1.htm[26/09/2010 5:12:29]


Figura 2 L

Figura 2 L'applicazione in grado di eseguire delle operazioni di caricamento e salvataggio dei dati su un file di testo.

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb10/figura2.htm[26/09/2010 5:12:46]


Listato 1 Il listato dell

Listato 1 Il listato dell'applicazione in grado di eseguire delle operazioni di caricamento e salvataggio dei dati su un file di testo. Private Sub btnCarica_Click() Dim Riga As String Dim NomeFile As String txtTesto.Text = "" NomeFile = txtNomeFile.Text Open NomeFile For Input As #1 Do Until EOF(1) Line Input #1, Riga txtTesto.Text = txtTesto.Text & Riga & Chr$(13) & Chr$(10) Loop Close #1 End Sub Private Sub btnCancella_Click() txtTesto.Text = "" End Sub Private Sub btnSalva_Click() Dim NomeFile As String NomeFile = txtNomeFile.Text Open NomeFile For Output As #1 Print #1, txtTesto.Text Close #1 End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb10/listato1.htm[26/09/2010 5:12:57]


. Figura1

Figura2

Listato1

Listato2

Corso di Visual Basic (Parte 11)

uesto mese il corso di Visual Basic focalizza l’attenzione sui file ad accesso casuale, che si distinguono per essere dotati di una struttura rigida; ciò li rende in grado di offrire una maggiore velocità di accesso alle informazioni Nella scorsa lezione sono stati presi in considerazione i file di testo, in cui l’accesso alle informazioni avviene in modo sequenziale. Essi presentano un limite, ovvero la scarsa idoneità alla memorizzazione di grandi quantità di dati, a causa dei talvolta elevati tempi di ricerca. In queste condizioni sono spesso preferibili delle strutture più sofisticate, quali ad esempio i file ad accesso casuale, che sono oggetto di studio in questa puntata del corso. Come sempre, tuttavia, prima di affrontare i nuovi argomenti, è opportuno un ripasso dei concetti esposti in precedenza; lo spunto è fornito dalla correzione dell’esercizio proposto nella scorsa lezione. La soluzione dell’esercizio proposto nella scorsa lezione L’esercizio proposto nello scorso numero prevede la realizzazione di un programma in grado di leggere, per mezzo di opportune textbox, tre valori numerici interi e una stringa, nonché di offrire la possibilità di salvare questi dati su richiesta dell’utente. La pressione di un pulsante deve provocare il ripristino all’interno delle caselle di testo dei valori salvati. Il codice è contenuto nel Listato 1. L’applicazione è composta da due procedure; la prima, associata alla pressione del pulsante btnSalva, ha lo scopo di scrivere le informazioni sul file Archivio.dat. Si noti che è copiata sul disco solo la parte intera dei numeri; l’eventuale parte decimale, non prevista dall’esercizio, è troncata. I dati sono letti dalla procedura associata alla pressione del pulsante btnCarica, che fa uso dell’istruzione Line Input. I file ad accesso casuale I file ad accesso casuale sono caratterizzati dall’organizzazione molto rigida in strutture dette record. Un file è quindi composto da un numero variabile di record accodati. Al fine di comprendere meglio il concetto, si pensi a uno schedario, quale ad esempio l’anagrafica dei clienti di un’azienda. L’archivio è composto da schede aventi tutte la stessa dimensione e contenenti lo stesso tipo di informazione. Ogni scheda rappresenta un record. I record Per poter inserire in un file più informazioni, anche di tipo non omogeneo, raggruppate in "schede", è necessario riunirle in un’unica struttura. Si deve quindi creare un nuovo tipo di dati. Tale operazione è eseguita per mezzo della struttura Type, la cui sintassi è: Type <nome> <nome_campo_1> As <tipo_1> <nome_campo_2> As <tipo_2> … <nome_campo_n> As <tipo_n> End Type All’interno della struttura devono essere dichiarati gli elementi che la compongono, che sono denominati campi. Per ognuno di essi deve essere specificato il tipo di dati che lo caratterizza. I campi possono essere anche di tipo totalmente diverso. Si possono infatti definire dei record contenenti contemporaneamente delle informazioni di tipo testuale, numerico e logico. Ad esempio, la seguente dichiarazione è corretta: Type Automobile Marca As String*50 Modello As String*50

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB11/index.htm[26/09/2010 5:15:21]


.

Cilindrata As Integer Diesel As Boolean End Type Si noti che sono stati dichiarati due campi di tipo alfanumerico, uno di tipo logico e uno numerico intero. La struttura è denominata Automobile. In questo modo si è provveduto ad aggiungere un nuovo tipo di dati a quelli standard previsti da Visual Basic. È quindi possibile dichiarare la variabile MiaVettura, di tipo Automobile digitando: Dim MiaVettura As Automobile Riempimento dei campi di un record Le variabili definite come record prevedono, data la propria conformazione, una modalità di assegnamento dei valori leggermente diversa rispetto a quella prevista dalle strutture convenzionali. In genere, si esegue un’operazione di assegnamento per ogni campo, secondo la sintassi: <variabile>.<campo> = <valore> Ad esempio, volendo assegnare il valore 2499 al campo Cilindrata della variabile MiaVettura, definita in precedenza, occorre scrivere: MiaVettura.Cilindrata = 2499 L’apertura di un file ad accesso casuale Come per le strutture sequenziali, l’apertura di un file ad accesso casuale avviene per mezzo dell’istruzione Open che, in questo caso, assume la forma: Open <percorso_file> For Random As [#]<identificatore> Len = <lunghezza_record> dove percorso_file indica il percorso completo del file che si desidera aprire, mentre identificatore costituisce un numero utilizzato per contraddistinguere in modo univoco tale struttura e pertanto va fornito come parametro a tutti i comandi che sono destinati a gestirla. Si noti che la modalità di accesso è indicata per mezzo della parola chiave Random, che deve essere obbligatoriamente specificata, indipendentemente dal tipo di operazione che si desidera effettuare sul file, sia essa di lettura o scrittura. Si noti altresì che anche il parametro Len è obbligatorio. Esso deve contenere l’esatta dimensione del record che costituisce l’unità di informazione memorizzata nel file. Qualora essa non sia nota, può essere determinata per mezzo della funzione Len. Ad esempio, volendo assegnare alla variabile DimRec la dimensione del record MiaVettura, è necessario digitare: DimRec = Len(MiaVettura) Il contenuto della variabile DimRec costituisce il valore da passare come ultimo parametro all’istruzione Open per consentire la gestione di un file composto da elementi di tipo Automobile. Analogamente ai file sequenziali, anche le strutture ad accesso casuale devono essere chiuse dopo l’uso per mezzo dell’istruzione Close. La lettura di un record La lettura di un record contenuto in un file ad accesso casuale avviene per mezzo dell’istruzione Get, caratterizzata dalla seguente sintassi: Get [#]<identificatore>, <posizione>, <variabile> dove <identificatore> rappresenta il numero che univocamente identifica il file oggetto dell’operazione di lettura e <variabile> è il nome della variabile in cui i dati letti devono essere posti. Il parametro <posizione> indica la posizione del record da leggere. Si tratta di un valore intero compreso fra 1 e il numero dei record presenti nel file. Ad esempio, si supponga di voler accedere al quarto record presente nel file di identificatore 1 e di voler porre il suo contenuto nella variabile Dato. Ciò è possibile per mezzo della riga: Get #1, 4, Dato Solo in un caso il valore del parametro <posizione> può essere omesso; ciò si verifica in occasione dell’effettuazione di operazioni di lettura in sequenza; l’assenza del numero indicante la posizione provoca

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB11/index.htm[26/09/2010 5:15:21]


.

infatti l’accesso al record successivo a quello corrente. Non possono tuttavia essere omesse le virgole di separazione. Ad esempio, la sequenza Get #1, 4, Dato Get #1,, Dato1 provoca la lettura del quarto e del quinto record del file identificato dal numero 1. La scrittura di un record Per scrivere il contenuto di un record in un file ad accesso casuale è possibile utilizzare l’istruzione Put, la cui sintassi è pressoché identica a quella del comando Get: Put [#]<identificatore>, <posizione>, <variabile> In questo caso, la variabile indicata come terzo parametro contiene il dato da scrivere. Ad esempio, la riga Put #1, 5, Dato scrive il contenuto della variabile Dato nel quinto elemento del file identificato dal numero 1. Il valore assunto dal parametro <posizione> assume un’importanza fondamentale, in quanto determina se è aggiunto un nuovo record all’archivio o se ne è sovrascritto uno già esistente. Quest’ultima evenienza si verifica quando è indicata una posizione già occupata da un elemento. Per aggiungere un nuovo record al file, invece, è necessario indicare un valore pari al numero totale dei record incrementato di un’unità. La cancellazione logica di un record Il metodo più semplice per cancellare un record consiste nel sovrascriverlo con un elemento vuoto. In questo modo, tuttavia, non è possibile recuperare lo spazio da esso occupato sul disco. Si tratta cioè di una cancellazione logica, non fisica, in quanto Visual Basic non dispone di un’istruzione in grado di rimuovere un record e di recuperare automaticamente lo spazio da esso occupato. È possibile sfruttare a proprio vantaggio la possibilità di effettuare solo una cancellazione logica dei record contenuti in un file per fare in modo che degli elementi eventualmente eliminati per sbaglio possano essere agevolmente recuperati. Ciò è possibile aggiungendo un campo booleano alla struttura dei record e facendo in modo che il programma che accede all’archivio consideri cancellati tutti gli elementi caratterizzati dal contenere il valore logico True all’interno di questo campo. L’eliminazione di un record comporta quindi la semplice variazione del valore di un suo campo. Analogamente, è possibile recuperare un elemento cancellato per errore impostando nuovamente al valore False il campo booleano. La struttura Automobile può pertanto essere modificata come segue: Type Automobile1 Marca As String*50 Modello As String*50 Cilindrata As Integer Diesel As Boolean Cancellato As Boolean End Type La cancellazione fisica di un record Quando la quantità di informazioni da gestire diventa elevata, la necessità di recuperare lo spazio occupato dai record cancellati diventa evidente, sia per evitare lo spreco di spazio sul disco, sia per non ridurre drasticamente i tempi di accesso alle informazioni costringendo il programma a leggere dei dati inutili. Come già osservato in precedenza, Visual Basic non dispone di un’istruzione in grado di provvedere automaticamente alla cancellazione fisica di un record. Tuttavia, la scrittura di una simile procedura non presenta un livello di difficoltà elevato. Essa deve solo creare un nuovo file e copiare al suo interno tutti i record non vuoti. Successivamente, deve eliminare il primo file ed assegnare il suo nome alla nuova struttura. È ciò che fa la procedura di seguito descritta, che riceve come parametro il nome del file da compattare, che si suppone composto da record di tipo Automobile1: Sub CompattaFile(ByVal NomeFile As String) Dim ID_old As Integer Dim ID_new As Integer Dim Dato As Automobile1 Dim Lunghezza As Integer Lunghezza = Len(Dato) ID_old = FreeFile Open NomeFile For Random As ID_old Len = Lunghezza ID_new = FreeFile Open "Temp.dat" For Random As ID_new Len = Lunghezza

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB11/index.htm[26/09/2010 5:15:21]


.

Do While Not EOF(ID_old) Get ID_old, , Dato If Not Dato.Cancellato Then Put ID_new, , Dato End If Loop Close ID_old, ID_new Kill NomeFile Name "Temp.dat" As NomeFile End Sub Si noti l’uso della funzione FreeFile, che restituisce un numero adatto ad essere utilizzato come identificatore di file ed evita così il rischio di utilizzare degli identificatori già in uso in altre parti del programma. La procedura provvede a leggere in modo sequenziale il file di cui è specificato il nome come parametro e a copiare in un file denominato Temp.dat tutti i record per i quali il campo Cancellato assume il valore False. Si noti che le operazioni di lettura e scrittura sono eseguite sequenzialmente, in quanto è stato omesso il valore indicante la posizione nelle istruzioni Get e Put. Il ciclo di copiatura termina quando sono esauriti i record da leggere. Quando ciò avviene, la funzione EOF (End Of File), già descritta nella scorsa lezione, restituisce il valore True. Dopo aver copiato tutti i record non cancellati logicamente, la procedura provvede a chiudere entrambi i file. Si noti che a tal fine utilizza un’unica istruzione Close, in cui gli identificatori dei file da chiudere sono separati da una virgola. Il passo successivo consiste nel sostituire il file originale con quello creato. Ciò comporta l’esecuzione di due operazioni: la cancellazione del file di origine e la ridenominazione di quello generato dalla procedura. L’eliminazione avviene per mezzo dell’istruzione Kill, la cui sintassi è Kill <Nome_file> Il file Temp.dat è quindi rinominato per mezzo dell’istruzione Name, che è caratterizzata dalla seguente sintassi: Name <Vecchio_nome> As <Nuovo_nome> Un esempio… Il Listato 2 contiene il codice di un’applicazione in grado di archiviare i dati relativi a dei siti Internet. Per ognuno di essi, è possibile indicare l’indirizzo e una breve descrizione. È possibile creare dei nuovi record vuoti in grado di ospitare i dati relativi a nuovi siti, oppure modificare le informazioni riferite a quelli esistenti, nonché scorrere l’archivio nei due sensi. Il file è composto da record del tipo DatiURL, definito all’inizio. Si noti che la definizione è preceduta dalla parola chiave Private per indicare che il suo campo di validità è limitato al form che la contiene. I record sono letti e scritti rispettivamente per mezzo delle procedure LeggiRecord e ScriviRecord. La variabile globale Posizione stabilisce il numero del record da leggere o aggiornare. Si noti la presenza della funzione ContaRecord, che ha lo scopo di calcolare il numero dei record presenti in archivio come rapporto fra la dimensione del file, restituita dalla funzione LOF (Length Of File) e la lunghezza di un singolo elemento.L’apertura del file avviene in corrispondenza dell’avvio dell’applicazione, quindi al verificarsi dell’evento Load. Analogamente, per assicurare la chiusura dell’archivio quando cessa l’uso del programma, l’istruzione Close è stata posta fra il codice associato all’evento Unload. … e un esercizio Per esercitarsi sui concetti esposti, si provi a modificare l’esempio sopra descritto aggiungendo la possibilità di cancellare logicamente e, su richiesta, fisicamente dei record. Conclusioni I file rivestono un’importanza fondamentale nella maggior parte delle applicazioni, in quanto consentono di trattare una quantità di dati superiore a quella che può essere contenuta nella memoria dell’elaboratore. Inoltre, trattandosi di strutture permanenti, permettono di mantenere tali informazioni anche dopo lo spegnimento o il riavvio del sistema. L’utilizzo di strutture ad accesso casuale rende ancora più evidenti i vantaggi offerti dai file, permettendo una maggiore flessibilità d’uso. Maurizio Crespi si occupa principalmente di grafica e multimedia. Svolge la funzione di responsabile tecnico presso Datanord Multimedia, società specializzata nella realizzazione di software orientato al marketing e all’editoria, per la quale progetta e sviluppa applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato per e-mail come crespi@programmers.net.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB11/index.htm[26/09/2010 5:15:21]


FIGURA 1 L

FIGURA 1 L'interfaccia della soluzione dell'esercizio proposto nello scorso numero

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/figura1.htm[26/09/2010 5:15:28]


FIGURA 2 L

FIGURA 2 L'interfaccia dell'applicazione d'esempio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/figura2.htm[26/09/2010 5:15:39]


LISTATO 1 La soluzione dell

LISTATO 1 La soluzione dell'esercizio proposto nello scorso numero Private Sub btnSalva_Click() Dim Numero1 As Integer Dim Numero2 As Integer Dim Numero3 As Integer Dim Stringa As String Open "archivio.dat" For Output As #1 Numero1 = Int(Val(txtNum1.Text)) Numero2 = Int(Val(txtNum2.Text)) Numero3 = Int(Val(txtNum3.Text)) Stringa = txtStringa.Text Print #1, Numero1 Print #1, Numero2 Print #1, Numero3 Print #1, Stringa Close #1 End Sub

Private Sub btnCarica_Click() Dim Numero1 As String Dim Numero2 As String Dim Numero3 As String Dim Stringa As String Open "archivio.dat" For Input As #1 If Not EOF(1) Then Line Input #1, Numero1 Line Input #1, Numero2 Line Input #1, Numero3 Line Input #1, Stringa txtNum1.Text = Numero1 txtNum2.Text = Numero2 txtNum3.Text = Numero3

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/listato1.htm[26/09/2010 5:15:47]


LISTATO 1 La soluzione dell

txtStringa.Text = Stringa End If Close #1 End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/listato1.htm[26/09/2010 5:15:47]


LISTATO 2 L

LISTATO 2 L'applicazione di esempio Private Type DatiURL Indirizzo As String * 100 Descrizione As String * 100 End Type

Dim Posizione As Long Dim LunghezzaRecord As Long

Sub LeggiRecord() Dim Dato As DatiURL Get #1, Posizione, Dato txtURL.Text = Dato.Indirizzo txtDescrizione.Text = Dato.Descrizione End Sub

Sub ScriviRecord() Dim Dato As DatiURL Dato.Indirizzo = txtURL.Text Dato.Descrizione = txtDescrizione.Text Put #1, Posizione, Dato End Sub

Function ContaRecord() As Long ContaRecord = (LOF(1) / LunghezzaRecord) End Function

Private Sub Form_Load() Dim Dato As DatiURL LunghezzaRecord = Len(Dato) Open "archivio.dat" For Random As #1 Len = LunghezzaRecord Posizione = 1

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/Listato2.htm[26/09/2010 5:15:54]


LISTATO 2 L

LeggiRecord End Sub

Private Sub btnNuovo_Click() txtURL.Text = "" txtDescrizione.Text = "" Posizione = 1 + ContaRecord() ScriviRecord End Sub

Private Sub BtnSalva_Click() ScriviRecord End Sub

Private Sub btnPrecedente_Click() If Posizione > 1 Then Posizione = Posizione - 1 LeggiRecord Else Beep End If End Sub

Private Sub btnSuccessivo_Click() If Posizione < ContaRecord() Then Posizione = Posizione + 1 LeggiRecord Else Beep End If End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/Listato2.htm[26/09/2010 5:15:54]


LISTATO 2 L

Private Sub Form_Unload(Cancel As Integer) Close #1 End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB11/Listato2.htm[26/09/2010 5:15:54]


.

Listato

Corso di Visual Basic VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT è la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it. Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri a risolvere i propri. Sarà anche un modo per instaurare nuovi rapporti di lavoro, collaborazione ed amicizia! uesto mese il corso dedicato a Visual Basic ha come tema lo sviluppo delle applicazioni in grado di far uso dei database, ovvero di strutture in grado di ospitare grandi quantità di dati in modo particolarmente efficiente.

Un database è una struttura residente su un’unità a disco che si caratterizza per la capacità di contenere ingenti quantità di dati organizzati in record. Ciò che fa la differenza fra un database e un normale file ad accesso casuale è la presenza di un modulo, detto generalmente database engine, che permette di effettuare ricerche e inserimenti all’interno dell’archivio in modo semplice e veloce. Esiste quindi un componente che si fa carico di tutta la gestione dei dati, lasciando al programmatore il solo compito di definire i parametri in base ai quali effettuare le operazioni di ricerca. Visual Basic, fin dalle sue origini, ha sempre annoverato fra i suoi punti di forza la capacità di agevolare al massimo lo sviluppo delle applicazioni in grado di gestire dei database. Questa sua caratteristica è andata evolvendosi nel tempo al punto che oggi è uno degli strumenti più utilizzati nel campo della realizzazione di applicazioni gestionali che accedono ad archivi locali o posti su un sistema remoto. Le soluzioni dell’esercizio proposto nella scorsa lezione Prima di affrontare lo studio dei database, è opportuno come sempre effettuare un breve ripasso di ciò che si è appreso nella scorsa lezione. Lo spunto è dato dalla correzione dell’esercizio in essa proposto, che prevede la modifica del programma descritto come esempio, in grado di visualizzare un elenco di siti Internet, per consentirgli di gestire la cancellazione logica e, su richiesta, fisica dei record. Questi ultimi sono del tipo DatiURL, di cui è di seguito riportata la definizione: Private Type DatiURL Indirizzo As String * 100 Descrizione As String * 100 End Type Per consentire la cancellazione degli elementi, è necessario modificare la struttura aggiungendole un campo booleano, che è utilizzato per contrassegnare i record logicamente rimossi. La definizione del tipo DatiURL diventa pertanto la seguente: Private Type DatiURL Indirizzo As String * 100 Descrizione As String * 100 Cancellato As Boolean End Type Per consentire la cancellazione del record corrente è necessario modificare la procedura ScriviRecord in modo da tenere conto del nuovo campo. Sub ScriviRecord(Cancella As Boolean) Dim Dato As DatiURL Dato.Indirizzo = txtURL.Text Dato.Descrizione = txtDescrizione.Text Dato.Cancellato = Cancella Put #1, Posizione, Dato

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB12/index.htm[26/09/2010 5:18:08]


.

End Sub Si noti che ora accetta un parametro booleano che stabilisce se il record che deve essere scritto sul disco deve essere cancellato logicamente. Il codice da associare alla pressione del pulsante btnCancella, è pertanto il seguente: Private Sub btnCancella_Click() ScriviRecord True End Sub È inoltre possibile inserire un pulsante in grado di recuperare tutti gli elementi cancellati. La sua pressione deve semplicemente richiamare la procedura Ripristina, composta da un ciclo in grado di leggere tutti i record presenti in archivio e di riscriverli dopo aver modificato il valore del campo Cancellato. Private Sub Ripristina() Dim i As Long Dim NumElementi As Long Dim Dato As DatiURL NumElementi = ContaRecord() For i = 1 To NumElementi Get #1, i, Dato Dato.Cancellato = False Put #1, i, Dato Next i End Sub La rimozione fisica di tutti gli elementi cancellati può invece avvenire per mezzo della funzione CompattaFile, che provvede a copiare in un nuovo file tutti i record caratterizzati dal contenere il valore False all’interno del campo Cancellato. Dopo essere stato creato, il nuovo file sostituisce quello di partenza. Private Sub CompattaFile() Dim Dato As DatiURL Dim Lunghezza As Long Dim NumElementi As Long Dim i As Long NumElementi = ContaRecord() Open "temp.dat" For Random As #2 Len = LunghezzaRecord For i = 1 To NumElementi Get #1, i, Dato If Not Dato.Cancellato Then Put #2, , Dato End If Next i Close #1, #2 Kill "archivio.dat" Name "temp.dat" As "archivio.dat" Open "archivio.dat" For Random As #1 Len = LunghezzaRecord End Sub Il codice completo del programma sopra descritto è riportato nel Listato 1. La sua lunghezza si sarebbe notevolmente ridotta se fosse stato utilizzato un database in luogo del file ad accesso casuale. Nel seguito di questa lezione si vedrà come è possibile fare ciò. I tipi di database utilizzabili da Visual Basic Esistono sul mercato molti sistemi di gestione dei database. Ognuno di essi è caratterizzato da un diverso modo di organizzare le informazioni sul disco. Per questo motivo, i file prodotti con tali strumenti presentano spesso dei formati molto diversi. I prodotti più noti sono Microsoft Access e FoxPro, nonché Borland DBase e Paradox. Visual Basic è in grado di gestire tutti questi formati, grazie a dei moduli supplementari denominati ISAM (Indexed Sequential Access Method) che possono essere utilizzati dal motore di gestione dei database su richiesta dell’applicazione. Oltre ai formati gestibili per mezzo dei moduli ISAM, Visual Basic è in grado di leggere e scrivere dei dati anche in strutture di diverso tipo, eventualmente poste su server remoti, grazie al supporto per la tecnologia ODBC (Open Database Connectivity). Ciò estende notevolmente il campo di utilizzo dello strumento, facendo sì che esso sia in grado di utilizzare qualunque formato di database per il quale esista un driver ODBC. La struttura di un database Le informazioni contenute all’interno di un database, essendo spesso in grande quantità, sono raggruppate in tabelle, al fine di minimizzare lo spreco di spazio sul disco e di agevolare le operazioni di ricerca. Ad esempio, supponendo di voler gestire l’inventario di una libreria, sarà necessario conoscere per ciascun libro almeno il titolo, l’autore, l’editore e lo scaffale che lo contiene. È tuttavia verosimile attendersi che molti editori abbiano pubblicato più di un libro. Se ad ogni opera è dedicato un record e se in ognuno di essi sono presenti anche i dati relativi all’editore, è evidente che le informazioni riguardanti gli editori che hanno pubblicato più di un libro sono inutilmente duplicate. L’ingombro degli archivi non risulta pertanto ottimizzato in relazione ai dati contenuti. Ciò si traduce in uno spreco di spazio sul disco e in una maggior quantità di informazioni da leggere durante l’effettuazione delle operazioni di ricerca. Inoltre, la presenza di più copie dello stesso dato può portare a problemi di inconsistenza dovuti ad errori di inserimento o alla mancata sincronizzazione in caso di modifica. Per evitare ciò, è conveniente suddividere l’archivio in più strutture, dette tabelle, raggruppando fra loro le informazioni dello stesso tipo. Fra le tabelle è possibile stabilire delle relazioni. Nel caso della libreria, ad esempio, è possibile inserire i dati relativi agli editori in una tabella a parte ed associare ad ognuno di essi un identificatore univoco. Le altre informazioni relative ai libri possono essere contenute in una seconda tabella, costituita da record in cui in luogo dei dati relativi agli editori sono presenti solo i loro identificatori. Ciò fa sì che un’eventuale modifica delle informazioni relative a una casa editrice, dovute ad esempio ad un cambio di indirizzo o di ragione sociale, comporti la variazione del contenuto di un solo record e non metta a repentaglio la consistenza dei dati. L’oggetto data La gestione dei database in Visual Basic è resa estremamente semplice da uno speciale controllo: l’oggetto

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB12/index.htm[26/09/2010 5:18:08]


.

data. Si tratta di un componente che presenta il caratteristico aspetto illustrato nella Figura 1; come è possibile osservare, è composto da 4 pulsanti, su cui sono presenti i simboli tipici dei registratori a nastro, posti alle estremità di un’etichetta testuale. Tutte le operazioni che devono essere effettuate sull’archivio devono far riferimento all’oggetto data ad esso associato. Per poter utilizzare il suddetto componente, occorre assegnare dei valori ad alcune sue proprietà. In primo luogo è necessario specificare il tipo di database che si prevede di utilizzare. Ciò è possibile agendo, per mezzo dell’apposita finestra, sulla proprietà Connect. Il valore predefinito è Access. Infatti, il motore di gestione dei database utilizzato da Visual Basic, denominato Jet, prevede come formato nativo quello di Microsoft Access, che ha la caratteristica di incorporare tutte le informazioni all’interno di un file di estensione mdb. Scorrendo la lista che appare nella finestra delle proprietà, è possibile osservare l’elenco degli altri formati supportati per mezzo dei driver ISAM. La lunghezza di questa lista è variabile in base al numero dei moduli installati nel sistema. Si noti che la decisione di utilizzare un formato diverso da quello standard comporta l’aggiunta al disco di distribuzione del necessario modulo ISAM. Dopo averne definito il tipo, è possibile indicare il nome del database. Ciò è possibile agendo sull’attributo DatabaseName. Si noti che, facendo doppio clic sulla voce nella casella delle proprietà, si provoca l’apertura di una finestra che invita a selezionare un file. Nel caso di archivi contenuti interamente all’interno di un unico file, come quelli in formato Access, esso rappresenta il database da utilizzare. In altri casi, quali ad esempio le strutture di tipo xBase (DBase o FoxPro), in cui ogni tabella è memorizzata sul disco in un file a sé stante caratterizzato dall’estensione dbf, il database è costituito dalla directory che contiene i dati. Un’altra proprietà a cui è necessario assegnare un valore è denominata RecordSource. Essa deve contenere l’espressione che permette al motore di gestione degli archivi di scegliere la fonte dei dati da visualizzare. Il valore da indicare è il nome della tabella da cui si desidera prelevare le informazioni. La realizzazione di un programma in grado di accedere a un database Si supponga di voler realizzare un’applicazione analoga a quella dell’esercizio proposto nella scorsa lezione, in grado di visualizzare le informazioni relative a un elenco di siti Internet. Questa volta, tuttavia, si desidera far uso di un database. L’archivio può essere creato mediante un prodotto come Microsoft Access. Con questo strumento è possibile definire una tabella costituita da record aventi due campi di tipo alfanumerico, denominati Indirizzo e Descrizione. Si supponga di assegnarle il nome TabellaURL e di salvare il database nel file Web.mdb. Il passo successivo consiste nel creare un form, su cui occorre trascinare dalla casella degli strumenti un oggetto di tipo Data. Ad esso si suppone di assegnare il nome dbArchivio. Si procede poi a scegliere il formato da utilizzare assegnando alla proprietà Connect il valore Access e ad assegnare il corretto valore alla proprietà DatabaseName. A tal fine si seleziona il file Web.mdb per mezzo dell’apposita opzione presente nella finestra delle proprietà. L’ultimo attributo da impostare riguarda la fonte dei dati. Essendo il database composto da una sola tabella, la scelta del valore della proprietà RecordSource è pressoché obbligata. La lista posta nella finestra delle proprietà è infatti composta dalla sola voce TabellaURL. Dopo aver assegnato i valori alle proprietà fondamentali dell’oggetto di tipo data, non resta che inserire sul form le caselle testuali che permettono la visualizzazione e la modifica dei dati presenti in archivio. Il loro collegamento al database può essere effettuato senza bisogno di scrivere del codice, in quanto avviene semplicemente impostando le proprietà DataSource e DataField. La proprietà DataSource permette di indicare l’oggetto di tipo data da cui una textbox deve attingere i valori da visualizzare. Nell’apposita finestra è possibile selezionare l’unico valore proposto, ovvero dbArchivio. La proprietà DataField, invece, permette di indicare il nome del campo da visualizzare. Nel caso dell’esempio, i valori possibili sono Indirizzo e Descrizione. Senza scrivere alcuna riga di codice, bensì semplicemente seguendo le istruzioni sopra riportate, è possibile realizzare un’applicazione in grado di visualizzare un archivio di siti Internet, caratterizzata dalla possibilità di scorrere i record agendo sui pulsanti posti all’interno del controllo di tipo data. Il metodo UpdateControls L’applicazione creata consente anche la modifica dei dati presenti in archivio. Se il contenuto di almeno una delle textbox subisce delle variazioni, la pressione di uno dei pulsanti di cui è dotato il controllo dbArchivio provoca il salvataggio nel database delle informazioni modificate. Si supponga ora di voler aggiungere all’applicazione un pulsante, a cui si dà il nome btnRipristina, in grado di annullare le eventuali modifiche effettuate accidentalmente. Si tratta in pratica di costringere l’oggetto dbArchivio a rileggere il record corrente e a sovrascrivere le informazioni poste nelle textbox collegate. Ciò è possibile semplicemente invocando il metodo UpdateControls. Il codice da associare al pulsante è il seguente: Private Sub btnRipristina_Click() dbArchivio.UpdateControls End Sub La proprietà Recordset L’insieme dei record presenti in archivio è identificato dalla proprietà Recordset. Si tratta in sintesi di un oggetto su cui è possibile invocare dei metodi per aggiungere, togliere o modificare gli elementi posti nella base di dati. L’aggiunta di un record all’archivio L’aggiunta di un nuovo record all’archivio richiede l’invocazione del metodo AddNew dell’oggetto Recordset. Supponendo di voler inserire nel form il pulsante btnNuovoRecord, il codice da associare alla sua pressione è il seguente: Private Sub btnNuovoRecord_Click() dbArchivio.Recordset.AddNew End Sub Dopo aver inserito nelle caselle di testo il contenuto del nuovo record, è necessario trasferirlo nel database. Per fare ciò, occorre eseguire il metodo Update dell’oggetto Recordset. Questa operazione può essere

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB12/index.htm[26/09/2010 5:18:08]


.

effettuata come risposta alla pressione di un pulsante che si suppone denominato btnAggiorna. Private Sub btnAggiorna_Click() dbArchivio.Recordset.Update End Sub La cancellazione di un record Anche per cancellare un record è sufficiente utilizzare un semplice metodo dell’oggetto Recordset. Si tratta del metodo Delete. Volendo inserire nel form un pulsante in grado di rimuovere il record corrente, è necessario scrivere il seguente codice: Private Sub btnCancella_Click() dbArchivio.Recordset.Delete End Sub Un semplice esercizio Per esercitarsi sui concetti esposti, si provi a realizzare un programma in grado di gestire una semplice rubrica telefonica. Conclusioni L’uso di un database consente il trattamento di cospicue quantità di informazioni in modo molto semplice e veloce. Per questo motivo, la stragrande maggioranza delle applicazioni gestionali ne fa uso. A questo tipo di strutture, data l’importanza che le caratterizza, sarà dedicata anche la prossima lezione. Per agevolarne la comprensione, il lettore è quindi invitato ad esercitarsi sui concetti sopra esposti. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB12/index.htm[26/09/2010 5:18:08]


LISTATO 1 Il listato della soluzione dell

LISTATO 1 Il listato della soluzione dell'esercizio proposto nella scorsa lezione Private Type DatiURL Indirizzo As String * 100 Descrizione As String * 100 Cancellato As Boolean End Type

Dim Posizione As Long Dim LunghezzaRecord As Long

Private Sub Form_Load() Dim Dato As DatiURL LunghezzaRecord = Len(Dato) Open "archivio.dat" For Random As #1 Len = LunghezzaRecord Posizione = 1 LeggiRecord End Sub

Function LeggiRecord() As Boolean Dim Dato As DatiURL Get #1, Posizione, Dato If Not Dato.Cancellato Then txtURL.Text = Dato.Indirizzo txtDescrizione.Text = Dato.Descrizione End If LeggiRecord = Not Dato.Cancellato End Function

Sub ScriviRecord(Cancella As Boolean) Dim Dato As DatiURL Dato.Indirizzo = txtURL.Text Dato.Descrizione = txtDescrizione.Text

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB12/listato1.htm[26/09/2010 5:18:19]


LISTATO 1 Il listato della soluzione dell

Dato.Cancellato = Cancella Put #1, Posizione, Dato End Sub

Function ContaRecord() As Long ContaRecord = (LOF(1) / LunghezzaRecord) End Function

Private Sub Ripristina() Dim i As Long Dim NumElementi As Long Dim Dato As DatiURL NumElementi = ContaRecord() For i = 1 To NumElementi Get #1, i, Dato Dato.Cancellato = False Put #1, i, Dato Next i End Sub

Private Sub CompattaFile() Dim Dato As DatiURL Dim Lunghezza As Long Dim NumElementi As Long Dim i As Long NumElementi = ContaRecord()

Open "temp.dat" For Random As #2 Len = LunghezzaRecord For i = 1 To NumElementi Get #1, i, Dato If Not Dato.Cancellato Then Put #2, , Dato

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB12/listato1.htm[26/09/2010 5:18:19]


LISTATO 1 Il listato della soluzione dell

End If Next i Close #1, #2 Kill "archivio.dat" Name "temp.dat" As "archivio.dat" Open "archivio.dat" For Random As #1 Len = LunghezzaRecord End Sub

Private Sub btnNuovo_Click() txtURL.Text = "" txtDescrizione.Text = "" Posizione = 1 + ContaRecord() ScriviRecord False End Sub

Private Sub BtnSalva_Click() ScriviRecord False End Sub

Private Sub btnPrecedente_Click() Dim Termina As Boolean Do If Posizione > 1 Then Posizione = Posizione - 1 Termina = LeggiRecord() Else Termina = True End If Loop Until Termina End Sub

Private Sub btnSuccessivo_Click() Dim Termina As Boolean

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB12/listato1.htm[26/09/2010 5:18:19]


LISTATO 1 Il listato della soluzione dell

Do If Posizione < ContaRecord() Then Posizione = Posizione + 1 Termina = LeggiRecord() Else Termina = True End If Loop Until Termina End Sub

Private Sub btnCancella_Click() ScriviRecord True End Sub

Private Sub btnRipristina_Click() Ripristina End Sub

Private Sub btnCompatta_Click() CompattaFile End Sub

Private Sub Form_Unload(Cancel As Integer) Close #1 End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB12/listato1.htm[26/09/2010 5:18:19]


. Figura1

Figura2 Figura3

Questo mese il corso dedicato a Visual Basic è ancora dedicato ai database. Oggetto di studio sono questa volta i metodi dell’oggetto Recordset che permettono di effettuare delle ricerche all’interno degli archivi

Corso di Visual Basic (Parte 13) di Maurizio Crespi database sono insiemi di dati organizzati secondo strutture ben definite, aventi lo scopo di rendere agevole la gestione e la ricerca delle informazioni. Lo studio delle modalità con cui è possibile localizzare dei record all’interno di un archivio costituisce lo scopo di questa lezione, che ha come protagonista l’oggetto Recordset. La soluzione dell’esercizio proposto nella scorsa lezione Come sempre, prima dell’introduzione dei nuovi concetti, è offerta un’occasione di ripasso di quelli già acquisiti in precedenza. Lo spunto è dato dalla descrizione del programma che costituisce la soluzione dell’esercizio proposto nella scorsa lezione. L’applicazione rappresenta una semplice rubrica telefonica, in grado di consentire l’inserimento di nuove voci e la cancellazione di quelle eventualmente esistenti. La sua realizzazione prevede dapprima la creazione di un database per mezzo di un apposito strumento (ad esempio Microsoft Access) e l’inserimento in esso di una tabella, a cui si dà il nome Rubrica, caratterizzata dal possedere 7 campi di tipo alfanumerico, denominati Cognome, Nome, Indirizzo, Comune, Telefono, Fax, eMail. Il passo successivo prevede la creazione di un form, su cui va inserito un oggetto di tipo Data, a cui è assegnato il nome dbArchivio. Esso è collegato al database assegnando il nome del file alla proprietà DatabaseName. Inoltre, deve essere collegato alla tabella. Per fare ciò occorre impostare la stringa "Rubrica" come valore della proprietà RecordSource. Il form deve poi essere completato con le caselle di testo destinate ad accogliere le stringhe contenute nei campi dei record. Ad ogni textbox deve essere assegnata la stringa "dbArchivio" come valore della proprietà DataSource. Per mezzo dell’attributo DataField è inoltre possibile specificare il campo contenente le informazioni da visualizzare. L’applicazione è completata con l’inserimento nel form dei pulsanti che permettono l’aggiunta di un nuovo record, la memorizzazione dei dati in esso inseriti e la cancellazione di un elemento. Per consentire ciò, alla pressione dei tasti deve corrispondere l’invocazione, rispettivamente, dei metodi AddNew, Update e Delete dell’oggetto Recordset. Quest’ultimo, come si è osservato nella scorsa lezione, costituisce una proprietà del componente di tipo Data. Le procedure associate ai pulsanti btnNuovo, btnCancella e btnAggiorna sono pertanto le seguenti: Private Sub btnNuovo_Click() dbArchivio.Recordset.AddNew End Sub Private Sub btnCancella_Click() dbArchivio.Recordset.Delete End Sub Private Sub btnAggiorna_Click() dbArchivio.Recordset.Update End Sub Il passaggio al primo o all’ultimo record presente in archivio A volte, per motivi di estetica, si sente la necessità di rendere invisibile all’utente l’oggetto di tipo Data. In questi casi occorre inserire nel form dei pulsanti che consentano la selezione degli elementi posti in

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB13/index.htm[26/09/2010 5:21:23]


.

archivio. Per mezzo del metodo MoveFirst dell’oggetto Recordset, è possibile fare in modo che il primo elemento presente in archivio diventi il record corrente. In pratica, il suddetto metodo provoca un effetto analogo a quello della pressione del pulsante posto all’estrema sinistra dell’oggetto Data. Volendo quindi inserire nel form il pulsante btnPrimo, in grado di selezionare il primo record presente in archivio, occorre digitare il seguente codice: Private Sub btnPrimo_Click() dbArchivio.Recordset.MoveFirst End Sub Un metodo analogo a quello appena descritto consente invece il posizionamento sull’ultimo record. Il suo nome è MoveLast. La procedura da associare al pulsante btnUltimo, in grado di selezionare l’elemento posto in coda all’archivio, è la seguente: Private Sub btnUltimo_Click() dbArchivio.Recordset.MoveLast End Sub Il passaggio al record successivo o precedente Anche per accedere ad un record adiacente è necessario utilizzare l’oggetto Recordset. Il metodo MoveNext, infatti, provvede a fare del record successivo il record corrente. Analogamente, il passaggio all’elemento precedente avviene invocando il metodo MovePrevious. Volendo inserire nel form i pulsanti btnPrecedente e btnSeguente, in grado di consentire lo scorrimento del database in entrambi i sensi, occorre digitare il seguente codice: Private Sub btnPrecedente_Click() If not dbArchivio.Recordset.BOF Then dbArchivio.Recordset.MovePrevious End If End Sub Private Sub btnSeguente_Click() If not dbArchivio.Recordset.EOF Then dbArchivio.Recordset.MoveNext End If End Sub Le proprietà BOF e EOF Si noti che il frammento di codice sopra riportato provvede a verificare i valori delle proprietà BOF (Beginning Of File) e EOF (End Of File) prima di accedere rispettivamente al record precedente o al successivo. Ciò ha il fine di evitare che siano effettuati dei tentativi di lettura di elementi inesistenti. La ricerca delle informazioni Si supponga di voler dotare la rubrica telefonica della possibilità di ricercare dei nominativi. A tal fine, si aggiunge al form il pulsante btnCerca, a cui è associato il seguente codice: Private Sub btnCerca_Click() Dim Ripeti As Boolean Dim Trovato As Boolean Dim DaCercare As String DaCercare = InputBox("Stringa da cercare:") dbArchivio.Recordset.MoveFirst Do Trovato = (txtCognome.Text = DaCercare) Ripeti = Not (dbArchivio.EOF Or Trovato) If Ripeti Then dbArchivio.Recordset.MoveNext End If Loop While Ripeti If Not Trovato Then MsgBox "Stringa non trovata" End If End Sub La stringa da cercare, richiesta per mezzo della funzione InputBox, è confrontata con il contenuto del campo Cognome, associato all’elemento txtCognome. La ricerca avviene in modo sequenziale a partire dal primo record. La soluzione presentata permette di ricercare il primo record caratterizzato dall’uguaglianza del contenuto del campo Cognome rispetto alla stringa inserita dall’utente. Tuttavia, il numero delle righe di codice necessarie per la sua realizzazione è elevato. Ciò è in contrasto con una della caratteristiche che fanno dei database delle strutture pressoché onnipresenti in tutte le applicazioni gestionali, ovvero la possibilità di effettuare delle ricerche in modo semplice e veloce. In realtà, la capacità che il modulo di gestione dei database in dotazione a Visual Basic ha di effettuare

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB13/index.htm[26/09/2010 5:21:23]


.

ricerche va ben oltre quanto illustrato fino ad ora. Per la localizzazione di elementi fra quelli posti in archivio, infatti, prevede degli appositi metodi dell’oggetto Recordset, denominati FindFirst, FindLast, FindPrevious, FindNext. Com’è facile intuire dai nomi, FindFirst e FindLast hanno lo scopo di ricercare rispettivamente il primo e l’ultimo elemento in grado di soddisfare il criterio specificato. FindNext e FindPrevious permettono invece rispettivamente la localizzazione del record successivo e del precedente fra quelli in grado di soddisfare una data condizione. La sintassi è pressoché identica per tutti e 4 i metodi e prevede un parametro costituito dall’espressione che descrive il criterio di ricerca, secondo lo schema: <oggetto_data>.Recordset.<comando> "<espressione>" dove <espressione> ha la forma <confronto> [AND | OR <confronto>]. . . [AND | OR <confronto>] e ogni confronto è del tipo <nome_campo> = | <> | > | < | >= | <= LIKE <valore> in cui <nome_campo> rappresenta il nome del campo da usare come oggetto di ricerca e <valore> indica il valore da ricercare. Si noti che ai comuni operatori di confronto (=, >, <, <>, >=, <=) ne è stato aggiunto un altro, denominato LIKE. Quest’ultimo permette di confrontare due stringhe in modo meno rigido rispetto al normale operatore di uguaglianza. In sostanza, fa sì che la verifica abbia esito positivo non solo se due stringhe sono identiche, bensì anche quando una costituisce solo l’inizio dell’altra. Per comprendere questo concetto, si consideri l’esempio che segue. Si supponga di disporre di un database in cui sono presenti dei record aventi fra gli altri un campo denominato Nome. Si supponga che esista un elemento contenente nel campo Nome la stringa "Dev, Developing software solutions". Se l’archivio è accessibile per mezzo dell’oggetto Data1, l’esecuzione del metodo Data1.FindFirst "Nome = ’Dev’" fornisce un esito negativo, in quanto nessun campo denominato Nome contiene esattamente la stringa "Dev". Invece, la riga Data1.FindFirst "Nome LIKE ’Dev’" ha esito positivo perché esiste un elemento che contiene una stringa che inizia con la sequenza "Dev". Si noti che per delimitare le stringhe negli esempi si è fatto uso dell’apice (‘). L’uso di questo carattere può talvolta essere causa di problemi, in quanto è spesso utilizzato all’interno delle frasi scritte in lingua italiana. Ad esempio, si osservi la riga Data1.FindFirst "Nome = ’Viva l’informatica’" La presenza dell’apostrofo fa sì che la stringa da cercare sia interpretata in modo errato; il motore di gestione del database riconosce infatti la sequenza "Viva l". I caratteri mancanti, non essendo riconosciuti come parte della stringa, causano la generazione di un messaggio di errore. Per ovviare a questo inconveniente, è opportuno l’utilizzo delle virgolette (") per delimitare le stringhe da cercare. Per consentire che siano interpretate da Visual Basic correttamente, essendo esse utilizzate anche per racchiudere la stringa che costituisce l’intero criterio di ricerca, occorre raddoppiarle. La riga Data1.FindFirst "Nome = ""Viva l’informatica""" ottiene l’effetto desiderato. La proprietà NoMatch L’oggetto Recordset è dotato della proprietà NoMatch, che assume un valore booleano che indica se l’ultima ricerca effettuata è andata a buon fine. Dopo aver eseguito una ricerca per mezzo di uno fra i metodi FindFirst, FindLast, FindNext e FindPrevious, è necessario verificare il valore assunto dalla proprietà NoMatch per sapere se il record desiderato è stato trovato oppure se la ricerca non ha avuto successo. In quest’ultimo caso, la proprietà assume il valore logico True.Si supponga di voler modificare la procedura, descritta in precedenza, associata al pulsante Cerca in modo da far uso del metodo FindFirst. Il codice è il seguente: Private Sub btnCerca_Click() Dim DaCercare As String Dim Criterio As String DaCercare = InputBox("Stringa da cercare:") Criterio = "Nome = """ & DaCercare & """" dbArchivio.Recordset.FindFirst If dbArchivio.Recordset.NoMatch Then MsgBox "Stringa non trovata" End If End Sub Com’è possibile notare, il numero delle righe di codice è diminuito. La nuova procedura si limita a chiedere

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB13/index.htm[26/09/2010 5:21:23]


.

la stringa da cercare ed a comporre il parametro da passare al metodo FindFirst. Una successiva verifica della proprietà NoMatch permette di stabilire l’opportunità della visualizzazione di un messaggio di errore indicante che la ricerca non ha avuto esito positivo. Un esempio Quanto appreso in questa lezione può essere applicato all’esercizio descritto all’inizio dell’articolo. È possibile dotare la rubrica telefonica di un completo insieme di opzioni di ricerca dei dati. Il codice che costituisce l’applicazione modificata è visibile nel listato 1 ed è disponibile su Internet per il download all’indirizzo http://www.infomedia.it. Com’è possibile osservare in figura, sono stati aggiunti al form una casella di testo, denominata txtCerca, un pulsante (btnCerca) e 4 option button. La textbox ha lo scopo di contenere la stringa da cercare nel campo Cognome. Si noti che, per esigenze di semplicità, la ricerca è stata limitata a un solo campo. La modalità di ricerca è richiesta all’utente per mezzo degli option button. Si tratta di pulsanti caratterizzati dall’annullarsi a vicenda. Questo tipo di componenti prende spesso il nome radio button, in quanto ricorda i comandi che permettono di cambiare la banda di frequenze nelle radio. Per mezzo degli option button, l’utente può selezionare una sola modalità di ricerca fra quelle disponibili. Esse corrispondono ai metodi FindFirst, FindLast, FindNext, FindPrevious. La ricerca è avviata dalla pressione del pulsante btnCerca. Il codice ad esso associato si limita a comporre la stringa che costituisce il criterio di selezione dei record ed a passarla al corretto metodo in funzione dell’option button selezionato, riconosciuto controllando il valori della proprietà value. Se la ricerca non va a buon fine, ovvero se la proprietà NoMatch dell’oggetto Recordset assume il valore logico true, è visualizzato un messaggio di errore. Conclusioni La potenza e la flessibilità dei database permettono di gestire grandi quantità di informazioni. Grazie ai metodi di ricerca, diventa estremamente semplice provvedere alla localizzazione all’interno degli archivi delle informazioni desiderate. In attesa di approfondire ulteriormente l’argomento database nel prossimo numero, si provi ad aggiungere alla rubrica telefonica descritta in precedenza la capacità di richiedere una stringa e di contare i record presenti in archivio che contengono nel campo Cognome la sequenza alfanumerica indicata. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all’indirizzo mcrespi@infomedia.it.

VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT e' la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a

majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri VB-IT è sufficiente inviare un messaggio a

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB13/index.htm[26/09/2010 5:21:23]


Figura 1 La soluzione all

Figura 1 La soluzione all’esercizio proposto nella scorsa lezione

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB13/figura1.htm[26/09/2010 5:21:29]


Figura 2 La rubrica telefonica in cui è stato nascosto l

Figura 2 La rubrica telefonica in cui è stato nascosto l’oggetto di tipo Data

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB13/figura2.htm[26/09/2010 5:21:39]


Figura 3 La rubrica telefonica con l

Figura 3 La rubrica telefonica con l’aggiunta della funzione di ricerca dei cognomi

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB13/figura3.htm[26/09/2010 5:21:49]


. Figura1 Listato1

PROGRAMMO SUBITO n.14 - Corso di Visual Basic Questo mese il corso dedicato a Visual Basic da nuovamente spazio ai database. Oggetto di studio sono infatti le modalità che permettono di interrogare una struttura per mezzo del linguaggio SQL

Corso di Visual Basic Come interrogare i database (Parte 14) di Maurizio Crespi Spesso si sente parlare dei database come di strutture che devono essere "interrogate", ovvero di oggetti pressoché attivi in grado di restituire delle informazioni a comando. In realtà ciò che è attivo non è il database vero e proprio, bensì il motore che lo gestisce. In questa lezione saranno descritte le modalità con cui è possibile richiedere al modulo responsabile della gestione degli archivi di effettuare delle ricerche e di fornire dei dati organizzati secondo una struttura differente da quella con cui essi sono memorizzati sul disco. La soluzione dell'esercizio proposto nella scorsa lezione Come sempre, prima di introdurre i nuovi argomenti, sarà presentata la soluzione dell'esercizio proposto nella scorsa lezione. Nello numero precedente, è stato descritto un programma in grado di gestire una semplice rubrica telefonica. L'esercizio ne prevede la modifica con l'aggiunta di un pulsante in grado di contare gli elementi dell'archivio contenenti nel campo Cognome una sequenza di caratteri indicata dall'utente. Supponendo di assegnare al nuovo tasto il nome btnConta, il codice che deve essere associato alla sua pressione è il seguente: Private Sub btnConta_Click() Dim Criterio As String Dim Contatore As Integer Contatore = 0 Criterio = "Cognome LIKE ""*" & txtCerca.Text & "*""" dbArchivio.Recordset.FindFirst (Criterio) Do While Not dbArchivio.Recordset.NoMatch Contatore = Contatore + 1 dbArchivio.Recordset.FindNext (Criterio) Loop MsgBox "Sono stati trovati " & Contatore & " record" End Sub Per leggere la stringa da cercare si fa uso della casella di testo txtCerca, già presente nell'applicazione in quanto usata dal codice associato alla pressione del tasto di ricerca (btnCerca). Si noti il criterio di selezione, basato sull'operatore LIKE. Per fare in modo che siano trovati tutti i record che contengano la scritta inserita dall'utente in una qualsiasi posizione, occorre introdurre prima e dopo la sequenza da cercare il carattere jolly *. La stringa che costituisce il criterio di ricerca, supponendo di aver digitato nella casella txtCerca la sequenza "Dev", è la seguente: Cognome LIKE "*Dev*" L'asterisco è in grado di sostituire un numero variabile di caratteri. Ciò significa che sono considerate rispondenti al criterio tutte le stringhe costituite da una sequenza qualsiasi, eventualmente nulla, seguita dalla parola "Dev" e da un'altra sequenza qualsiasi, anch'essa eventualmente nulla. Per mezzo del metodo FindFirst dell'oggetto Recordset associato all'archivio, è ricercato il primo record che soddisfa il criterio. Un ciclo, che si interrompe solo quando la proprietà NoMatch diventa positiva, ovvero quando non sono più trovati elementi corrispondenti ai parametri di ricerca indicati, fa sì che sia più volte invocato il metodo FindNext, che provoca la lettura del successivo elemento soddisfacente i

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB14/index.htm[26/09/2010 5:23:38]


.

criteri. Il codice dell'applicazione completa è riportato nel listato 1. Cosa significa "interrogare un database" Un'applicazione che fa uso di un database percepisce tale struttura come attiva, cioè in grado di rispondere a delle richieste. Il programmatore può infatti creare diverse viste dell'archivio, scegliendo solo i campi desiderati e ordinando i record secondo le proprie preferenze. La creazione di una vista non cambia la conformazione fisica del database, bensì comporta la generazione di una struttura logica personalizzata che permette all'applicazione che accede all'archivio di avere di esso una visione adeguata alle proprie esigenze. Una struttura logica di questo tipo prende il nome di dynaset (abbreviazione di dynamic set, ovvero insieme dinamico) e l'operazione che porta alla sua creazione è in genere detta interrogazione del database. e query Un termine che si usa spesso quando si parla di database è costituito dalla parola query. Una query non è altro che un'interrogazione del database, ovvero l'estrazione da esso dell'insieme costituito dai dati in grado di soddisfare delle condizioni specificate. Una query quindi rappresenta un'operazione effettuata sull'archivio secondo delle modalità ben precise, che sono descritte tipicamente per mezzo di una stringa contenente un testo composto da nomi di elementi del database correlati per mezzo di parole chiave appartenenti ad un linguaggio particolare (esso è detto in genere linguaggio di interrogazione o, dagli amanti della lingua inglese, query language). Sulla scena esistono molti linguaggi di questo tipo. In passato, infatti, ogni motore di database tendeva a possedere un proprio linguaggio di interrogazione proprietario. Col passare del tempo, tuttavia, l'esigenza di creare uno standard che permettesse di operare con prodotti diversi riducendo al minimo i costosi corsi di formazione si è sempre più fatta sentire. I moderni strumenti, quindi, sono andati via via adeguandosi alle richieste dell'utenza e oggi, sebbene sopravvivano ancora molti linguaggi proprietari, si può affermare che lo standard mondiale, almeno per alcune categorie di prodotti, sia costituito dallo Structured Query Language (linguaggio strutturato di interrogazione), il cui nome è noto ai più sotto forma di sigla (SQL). I vantaggi principali offerti da questo linguaggio sono rappresentati dalla semplicità, dalla notevole potenza e dalla portabilità da uno strumento di gestione dei database a un altro. Quest'ultima caratteristica non è tuttavia valida al 100%, in quanto spesso si possono osservare delle piccole variazioni fra i linguaggi previsti dai vari prodotti. Il linguaggio SQL Il linguaggio SQL rappresenta uno standard per tutti i recenti prodotti Microsoft in grado di accedere a dei database. Anche il motore di gestione degli archivi integrato in Visual Basic non si sottrae questa regola. Per mezzo di una stringa SQL è quindi possibile definire la struttura logica, i requisiti, nonché l'ordinamento dei record che devono essere utilizzati da un controllo di tipo data. L'istruzione SQL di più frequente utilizzo è denominata SELECT. La sua sintassi è la seguente: SELECT <elenco_campi>; FROM <tabella> dove <elenco_campi> ha la sintassi: <campo_1>[,<campo_2>,…, <campo_n>] Per mezzo dell'istruzione SELECT è possibile specificare un elenco di campi che costituisce la struttura logica da attribuire ai record da prelevare dal database. La tabella in cui essi sono contenuti è specificata dopo la clausola FROM. Ad esempio, si supponga di disporre di un database denominato VeicoliAziendali, in cui ciascun record contiene tutte le informazioni riguardati un veicolo aziendale. All'atto dell'acquisto di una nuova automobile, in archivio sono inserite tutte le informazioni atte a identificarla in modo preciso. Il database deve pertanto prevedere una tabella, che si supporrà denominata Automobili, in cui sono presenti dei campi in grado di ospitare la marca, il modello, la versione, il numero di telaio, la targa, il numero del contratto di assicurazione, la data di immatricolazione, ecc. Si supponga di voler realizzare un'applicazione che consenta al responsabile della gestione del parco veicoli di verificare quali autovetture hanno superato i 5 anni di età e necessitano quindi di essere sostituite. È evidente che un'applicazione di questo tipo necessita per ogni veicolo delle informazioni relative all'anno di immatricolazione, al numero identificativo attribuito dall'azienda e al nominativo della persona a cui è stato affidato. Sicuramente non risulta utile conoscere il colore del l'auto, né il numero di telaio o la scadenza del contratto di assicurazione. Per fare in modo che sia caricata in memoria una minore quantità di informazioni, rendendo meno gravoso il compito del sistema e agevolando le operazioni di debug al programmatore, è possibile fare in modo che il controllo di tipo data preposto alla

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB14/index.htm[26/09/2010 5:23:38]


.

lettura delle informazioni abbia una percezione dell'archivio diversa da quella reale, ovvero sia in grado di leggere dei record composti dai soli campi necessari. Ciò è possibile provvedendo a fornire all'oggetto la stringa SQL: SELECT Anno, Numero, Utente; FROM Automobili Tale sequenza fa sì che il modulo di accesso ai dati provveda a creare un recordset composto da record caratterizzati dalla presenza dei soli 3 campi Anno, Numero, Utente. I dati sono prelevati dalla tabella Automobili. L'applicazione può eseguire qualsiasi operazione sugli elementi del dynaset, ivi compresa la modifica dei contenuti o la loro cancellazione. Naturalmente, le informazioni poste nella tabella di provenienza sono costantemente mantenute sincronizzate con quelle presenti nel dynaset, per cui ogni operazione effettuata sulla struttura logica influenza l'archivio memorizzato fisicamente sul disco. Per poter rendere ancora più veloce l'applicazione e per semplificare ulteriormente il compito del programmatore, sarebbe senz'altro utile disporre di un archivio costituito esclusivamente dai record che descrivono i veicoli che hanno almeno 5 anni. In tal modo, non sarebbero necessari altri controlli sui dati e il programma dovrebbe semplicemente limitarsi a visualizzare sequenzialmente tutti gli elementi forniti dal motore di gestione del database. Per mezzo della clausola WHERE, da utilizzare in combinazione con l'istruzione SELECT, è possibile fare in modo che il programma veda i dati relativi ai veicoli più anziani come contenuti all'interno di una tabella ad hoc, sebbene in realtà siano posti nella stessa struttura che contiene le informazioni relative alle altre vetture. La sintassi è la seguente: SELECT <elenco_campi>; FROM <tabella>; WHERE <condizione> dove <condizione> rappresenta un'espressione di confronto valida, definita secondo lo schema <confronto> [And|Or <confronto>… And|Or <confonto>] <confronto> è definito come <campo> =|<>|<|>|<=|>=|Like [<valore>|<campo>] oppure <campo> Between <valore> And <valore> L'uso della clausola WHERE implica la presenza di un criterio di scelta, che è descritto da una o più condizioni combinate per mezzo dei canonici operatori logici. Si noti che oltre ai tipici operatori di confronto è possibile utilizzare la parola Between per verificare l'appartenenza del contenuto di un campo a un preciso intervallo di valori. Ad esempio, volendo estrarre dall'archivio delle vetture aziendali tutti i veicoli immatricolati prima del 1995, è necessario effettuare una query descritta dalla stringa SELECT Anno, Numero, Utente; FROM Automobili; WHERE Anno<1995 I campi indicati nei criteri di selezione non devono necessariamente essere menzionati anche dopo il comando SELECT. Nel caso della query SELECT Anno, Numero, Utente; FROM Automobili; WHERE (Anno<1995) And (Tipo='Station Wagon')

non ha alcun senso prelevare il campo Tipo dall'archivio, in quanto la condizione indicata fa sì che possa solo essere costituito dalla stringa "Station Wagon".Osservando la frase SQL appena descritta, si può notare che il criterio di scelta è costituito da due condizioni racchiuse fra parentesi e combinate per mezzo dell'operatore logico And. L'uso delle parentesi, sebbene spesso non sia obbligatorio, risulta consigliabile in presenza delle parole chiave And e Or al fine di favorire la leggibilità de codice. Inoltre, la stringa alfanumerica da confrontare con il contenuto del campo Tipo è racchiusa fra apici. In alcuni casi, ad esempio in presenza di frasi contenenti degli apostrofi, può rivelarsi necessario l'utilizzo di un diverso delimitatore per le stringhe. L'alternativa è costituita dall'uso delle virgolette (").

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB14/index.htm[26/09/2010 5:23:38]


.

La selezione di tutti i campi Talvolta si rivela necessario utilizzare una query per leggere tutti i record che soddisfano una condizione senza che sia necessario variare la loro struttura logica, ovvero rendendo disponibili all'applicazione tutti i campi che li compongono. In questi casi, può risultare scomodo dover fornire l'elenco completo dei campi dopo la parola SELECT, soprattutto se il loro numero è elevato. È allora possibile utilizzare il carattere *, che significa tutti i campi. La stringa SELECT *; FROM Automobili; WHERE Anno<1995 crea pertanto una query che provvede a prelevare dal database tutti i campi di tutti i record presenti nella tabella Automobili che sono caratterizzati dal contenere un valore inferiore a 1995 nel campo Anno. Un esempio… Si supponga di voler realizzare un'applicazione in grado di estrarre da un archivio di auto aziendali, contenuto in una tabella denominata Automobili, l'elenco dei veicoli immatricolati nell'anno 1998. Si supponga che nell'archivio esistano almeno i campi Anno, Targa, Modello, Sede, contenenti rispettivamente le informazioni riguardanti l'anno di immatricolazione, la targa, il modello e la sede alla quale il veicolo è stato assegnato. Come sempre, il primo passo da compiere riguarda la creazione di un form, in cui è necessario inserire un oggetto di tipo data, utilizzato per leggere le informazioni contenute nel database e quattro etichette, destinate ad accogliere i dati contenuti nei campi. Come per tutte le altre applicazioni facenti uso dei database, occorre collegare l'oggetto di tipo data, a cui sarà dato il nome Query, all'archivio. Il passo successivo consiste nel collegare all'elemento Query le etichette testuali usate per visualizzare il contenuto dei campi Anno, Targa, Modello e Sede. Si agisce quindi come se si volesse realizzare un'applicazione in grado di leggere sequenzialmente tutti i record dell'archivio. La differenza rispetto a un programma di questo tipo consiste esclusivamente nel valore assunto dalle proprietà RecordsetType e RecordSource dell'oggetto di tipo Data. La prima deve essere impostata al valore Dynaset in luogo di Table (tabella), mentre la seconda, anziché contenere il nome della tabella da cui devono essere prelevati i dati, deve ospitare la stringa SQL che descrive la query da effettuare, ovvero: SELECT Anno, Targa, Modello, Sede; FROM Automobili; WHERE Anno=1998 Conclusioni La possibilità di eseguire su un archivio locale o remoto delle query descritte da stringhe in linguaggio SQL fa di Visual Basic uno strumento particolarmente indicato per gestire i database. Non è quindi un caso che il prodotto Microsoft si stia sempre più affermando come uno degli strumenti standard per la realizzazione di software gestionale in ambiente Windows. Data l'importanza dell'argomento, anche la prossima lezione di questo corso sarà dedicata alla realizzazione e alla gestione delle query. Per saperne di più, al lettore non resta che attendere il prossimo numero… Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all'indirizzo mcrespi@infomedia.it. VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT e' la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB14/index.htm[26/09/2010 5:23:38]


.

Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri a risolvere i propri. SarĂ

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB14/index.htm[26/09/2010 5:23:38]


Figura 1 L

Figura 1 L’interfaccia utente della soluzione all’esercizio proposto nella scorsa lezione

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB14/figura1.htm[26/09/2010 5:23:45]


LISTATO 1 Il listato del programma che gestisce una rubrica telefonica

LISTATO 1 Il listato del programma che gestisce una rubrica telefonica, soluzione dell’esercizio proposto nella scorsa lezione Private Sub btnAggiorna_Click() dbArchivio.Recordset.Update End Sub Private Sub btnCancella_Click() dbArchivio.Recordset.Delete End Sub Private Sub btnCerca_Click() Dim Criterio As String Criterio = "Cognome LIKE """ & txtCerca.Text & "*""" If obPrecedente.Value Then dbArchivio.Recordset.FindPrevious Criterio ElseIf obProssimo.Value Then dbArchivio.Recordset.FindNext Criterio ElseIf obPrimo.Value Then dbArchivio.Recordset.FindFirst Criterio Else dbArchivio.Recordset.FindLast Criterio End If If dbArchivio.Recordset.NoMatch Then MsgBox "Elemento non trovato" End If End Sub Private Sub btnNuovo_Click() dbArchivio.Recordset.AddNew End Sub Private Sub btnPrecedente_Click() If Not dbArchivio.Recordset.BOF Then dbArchivio.Recordset.MovePrevious End If End Sub Private Sub btnPrimo_Click() If Not dbArchivio.Recordset.BOF Then dbArchivio.Recordset.MoveFirst End If End Sub Private Sub btnSeguente_Click() If Not dbArchivio.Recordset.EOF Then dbArchivio.Recordset.MoveNext End If End Sub Private Sub btnUltimo_Click() If Not dbArchivio.Recordset.EOF Then dbArchivio.Recordset.MoveLast End If End Sub Private Sub btnConta_Click() Dim Criterio As String Dim Contatore As Integer Contatore = 0 Criterio = "Cognome LIKE ""*" & txtCerca.Text & "*""" dbArchivio.Recordset.FindFirst (Criterio)

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB14/listato1.htm[26/09/2010 5:23:52]


LISTATO 1 Il listato del programma che gestisce una rubrica telefonica

Do While Not dbArchivio.Recordset.NoMatch Contatore = Contatore + 1 dbArchivio.Recordset.FindNext (Criterio) Loop MsgBox "Sono stati trovati " & Contatore & " record" End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB14/listato1.htm[26/09/2010 5:23:52]


. Figura1

Figura2 Listato1

Programmo Subito - 2 Livello - Corso di Visual Basic Anche questo mese il corso dedicato a Visual Basic dà spazio ai database, con la trattazione di alcune clausole previste dal comando SQL SELECT

Corso di Visual Basic Le query SQL (parte XV) di Maurizio Crespi Continua la trattazione della gestione dei database in Visual Basic. Questo mese sono ancora protagoniste la query e in particolare alcune utili clausole previste dal comando SQL SELECT. Non mancherà, inoltre, un’occasione per rivedere i concetti esposti nelle ultime 10 lezioni di questo corso. L’ordinamento dei dati risultanti dall’esecuzione di una query Spesso si rivela opportuno fare in modo che i dati risultanti dall’esecuzione di una query siano presentati secondo un particolare ordine. Ad esempio, si supponga di disporre di un database contenente i dati anagrafici di tutti gli abitanti di un piccolo comune e di voler creare un’applicazione che permetta di estrarre l’elenco degli abitanti che nel corso del 1999 hanno compiuto o compieranno il diciottesimo anno di età. Si supponga che l’archivio preveda una tabella denominata Anagrafica, composta da record contenenti i campi Nome, Cognome, Indirizzo, AnnoNascita. Per estrarre dall’archivio tutti i nati nell’anno 1981 è necessaria una query descritta dalla seguente stringa SQL: SELECT Nome, Cognome, Indirizzo FROM Anagrafica WHERE AnnoNascita=1981

Generalmente, quando si gestiscono delle anagrafiche, si tende ad agevolare l’utente presentando i nominativi in ordine alfabetico. La query descritta dalla stringa sopra menzionata non garantisce che ciò avvenga, in quanto non impone alcuna condizione in merito all’ordinamento dei dati. Per fare in modo che essi siano presentati secondo un preciso ordine, è necessario introdurre una clausola aggiuntiva. La sintassi del comando SELECT diventa pertanto la seguente: SELECT <elenco_campi> FROM <nome_tabella> [WHERE <condizione>] [ORDER BY <ordinamento>]

dove <ordinamento> è descritto da <ordinamento> = <campo 1> [, <campo 2>, ..., <campo n>]

Il primo campo indicato dopo la clausola ORDER BY è quello secondo il quale è effettuato il primo ordinamento dei dati. Qualora alcuni record prevedano valori analoghi all’interno dell’elemento specificato, essi sono ordinati fra loro in base al valore contenuto nel campo indicato dopo la virgola. In caso di ulteriore analogia fra alcuni record, essi sono ordinati fra loro in base al valore dell’eventuale terzo campo, ecc. Si noti che è obbligatorio indicare un nome di un campo dopo la clausola ORDER BY, mentre i successivi elementi sono facoltativi. Per chiarire il concetto, si osservino gli esempi riportati di seguito. Si supponga di applicare la query descritta dalla stringa SELECT Nome, Cognome FROM Anagrafica WHERE AnnoNascita=1981

al database contenente tutti gli abitanti di un piccolo comune. Un possibile risultato è il seguente: Rossi Marco Bianchi Lucia Rossi Alessandro

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB15/index.htm[26/09/2010 5:25:26]


. Verdi Marco Rossi Davide Gialli Claudia

Come si può notare, i dati non sono ordinati in base al contenuto dei campi.Si supponga ora di applicare allo stesso archivio la query: SELECT Nome, Cognome FROM Anagrafica WHERE AnnoNascita=1981 ORDER BY Cognome

In questo caso, il risultato è il seguente: Bianchi Lucia Gialli Claudia Rossi Davide Rossi Marco Rossi Alessandro Verdi Marco

Ora i nominativi sono ordinati per cognome. Si noti però che è assente l’ordinamento per nome nel caso di individui caratterizzati dallo stesso cognome. Per sopperire a ciò è possibile applicare la seguente query: SELECT Nome, Cognome FROM Anagrafica WHERE AnnoNascita=1981 ORDER BY Cognome, Nome

Questa volta, i dati sono presentati nel modo corretto: Bianchi Lucia Gialli Claudia Rossi Alessandro Rossi Davide Rossi Marco Verdi Marco

Ordinamento decrescente. In mancanza di indicazioni contrarie, l’ordinamento avviene in modo crescente in base ai valori assunti dai campi indicati dopo la clausola ORDER BY. Si supponga ora di voler effettuare una query analoga alla precedente ma tale da fare in modo che l’ordinamento rispetto al campo Cognome sia decrescente. In questo caso, al nome del campo deve essere fatta seguire la parola DESC. Ad esempio, la stringa SELECT Nome, Cognome FROM Anagrafica WHERE AnnoNascita=1981 ORDER BY Cognome DESC, Nome

fornisce il seguente risultato: Verdi Marco Rossi Alessandro Rossi Davide Rossi Marco Gialli Claudia Bianchi Lucia

Come si può notare, l’ordinamento è decrescente solo rispetto al campo dopo il cui nome è stata specificata la parola DESC, abbreviazione di descending. Per fare in modo che l’ordinamento sia decrescente anche nei confronti del campo Nome, è necessario quindi scrivere la seguente stringa SQL: SELECT Nome, Cognome FROM Anagrafica WHERE AnnoNascita=1981 ORDER BY Cognome DESC, Nome DESC

Il risultato è costituito dalla sequenza: Verdi Marco Rossi Marco Rossi Davide Rossi Alessandro Gialli Claudia Bianchi Lucia

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB15/index.htm[26/09/2010 5:25:26]


.

Query senza duplicati Si supponga che per scopi statistici si debba produrre un elenco dei nomi di persona utilizzati nell’anno 1981 per iscrivere i nuovi nati all’anagrafe. Ciò è possibile eseguendo sull’archivio la query descritta dalla stringa SELECT Nome FROM Anagrafe WHERE AnnoNascita=1981 ORDER BY Nome

Il risultato è costituito dai seguenti valori: Alessandro Claudia Davide Lucia Marco Marco

Si noti che il nome "Marco" è duplicato. Infatti, come si è visto in precedenza, vi sono due individui omonimi. Nel caso dell’esempio, l’esistenza di un voce duplicata nel risultato rappresenta un fatto indesiderato. Per evitare che ciò avvenga, è possibile far uso della clausola DISTINCT. La sintassi del comando SQL SELECT diventa: SELECT [DISTINCT] <elenco_campi> FROM <nome_tabella> [WHERE <condizione>] [ORDER BY <ordinamento>]

La query da effettuare è quindi descritta dalla stringa: SELECT DISTINCT Nome FROM Anagrafe WHERE AnnoNascita=1981 ORDER BY Nome e il risultato è il seguente: Alessandro Claudia Davide Lucia Marco

Un esempio Il Listato 1 costituisce il codice sorgente di una semplice applicazione in grado di comporre ed eseguire una query SQL sul database descritto negli esempi precedenti. I file sono scaricabili da Internet all’indirizzo ftp://ftp.infomedia.it/pub/DEV./Listati. Il programma permette di selezionare, per mezzo di checkbox, i campi da visualizzare. Con l’ausilio di alcuni option button, inoltre, consente di stabilire i criteri di ricerca e di ordinamento. I risultati sono visualizzati in una listbox. Si noti che l’oggetto di tipo Data è utilizzato solo per l’interfacciamento al database, non per la navigazione; lo stesso dicasi per le 3 label ad esso collegate. Per questo motivo, questi elementi sono stati resi invisibili. Per realizzare questa applicazione è necessario disegnare un form dotato di tutti gli elementi necessari. Si provvede poi a collegare l’oggetto di tipo Data all’archivio e a legare ad esso le etichette testuali. A tal fine occorre inizializzare l’elemento di gestione del database utilizzando come proprietà RecordSource il nome della tabella da cui devono essere estratti i dati. Successivamente, dopo avere composto la query, il programma può provvedere a sostituire il contenuto della proprietà con la stringa in linguaggio SQL. Si noti che, dopo aver eseguito tale operazione, è necessario invocare il metodo Refresh per aggiornare l’oggetto di tipo Data e quindi per accedere al risultato dell’interrogazione. Si osservi altresì che, per verificare l’eventuale assenza di dati soddisfacenti le condizioni imposte, si fa uso della proprietà RecordCount, che indica il numero degli elementi presenti nel recordset (insieme di record) corrente. Rinfreschiamoci la memoria… Il corso dedicato a Visual Basic prosegue ormai da molto tempo e gli argomenti già trattati sono numerosi. Lo scopo di quest’ultima parte della lezione è di invitare il lettore a rivedere i temi discussi negli ultimi 10 numeri, sia per valutare il proprio livello di comprensione, sia per evitare che dei concetti

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB15/index.htm[26/09/2010 5:25:26]


.

importanti siano dimenticati in seguito all’acquisizione di nuove informazioni. Di seguito saranno quindi formulate alcune domande, a cui il lettore è invitato a rispondere. Le soluzioni corrette sono indicate di seguito in corsivo. A cosa serve l’istruzione ReDim? L’istruzione ReDim permette di ridefinire un vettore per aumentare o ridurre la sua dimensione. A quale fine a volte si specifica la clausola Preserve dopo l’istruzione ReDim? L’uso della clausola Preserve permette di aumentare la dimensione di un vettore senza perdere i valori in esso già contenuti. L’indice iniziale di un vettore deve essere sempre 0? No, può essere qualsiasi valore intero. Quali sono i principali vantaggi derivanti dall’uso delle subroutine? Le subroutine (o procedure) permettono di assegnare un nome a delle porzioni di codice usate in più punti di un programma. Esse possono poi essere richiamate semplicemente indicandone l’identificatore. Ciò rende più leggibile il codice dell’applicazione ed evita inutili duplicati al suo interno. A cosa serve la parola chiave ByVal? La parola chiave ByVal permette di passare a una procedura un parametro per valore. Quanti parametri possono essere passati a una procedura? Non esiste un limite ai parametri passabili a una procedura, sebbene non sia opportuno esagerare, onde evitare di produrre del codice scarsamente leggibile. Che cosa differenzia un parametro passato per valore da uno passato per riferimento? Se si richiama una procedura passando come parametro una variabile, se esso è definito per riferimento si rende la procedura in grado di modificare il valore della variabile. Se invece il parametro è definito per valore, la procedura acquisisce il valore della variabile ma non la facoltà di modificarla. Qual è la differenza che intercorre fra una funzione e una procedura? Una funzione può restituire dei valori. Una procedura invece no, a meno di ricorrere a dei parametri passati per riferimento. Può una funzione restituire più di un valore? No, a meno che non si faccia uso di parametri passati per riferimento. Quali rischi comporta un uso errato della ricorsione? Un uso errato della ricorsione, ad esempio quando non è specificata una condizione di uscita, può provocare il superamento della capacità massima dello stack di sistema (stack overflow). Cos’è la procedura Main? La procedura Main, se presente, è la prima procedura eseguita all’avvio di un programma. Essa deve risiedere in un modulo (file di estensione BAS). Qual è la differenza principale fra i file sequenziali e i file ad accesso casuale? I file ad accesso casuale permettono la ricerca delle informazioni senza comportare la lettura di tutto il proprio contenuto. A cosa serve l’istruzione Open? Per mezzo dell’istruzione Open è possibile fare in modo che il programma assuma il controllo di un file per eseguire su di esso delle operazioni di lettura o scrittura. A cosa serve la funzione Line Input? L’istruzione Line Input ha lo scopo di effettuare la lettura di una riga in un file di testo. Cos’è un record? Un record è un agglomerato di informazioni di tipo non necessariamente omogeneo. Costituisce l’elemento fondamentale di cui sono composti i file ad acceso casuale. Quando si apre un file ad accesso casuale, è opportuno specificare il parametro Len? E’ obbligatorio, al fine di consentire al sistema la distinzione dei record all’interno del file. Qual è l’istruzione da utilizzare per leggere un record in un file ad accesso casuale? La lettura di un record in un file ad accesso casuale avviene per mezzo dell’istruzione Get. Qual è l’istruzione che permette di scrivere un record in un file ad accesso casuale? La scrittura di un record in un file ad accesso casuale avviene per mezzo dell’istruzione Put. Che vantaggi offre l’uso di un database in luogo di un file ad accesso casuale? L’uso di un database permette di gestire grandi quantità di dati in modo semplice, grazie all’uso di un "motore" in grado di eseguire autonomamente la maggior parte delle operazioni di ricerca e selezione. Quali formati di database possono essere gestiti da Visual Basic? Visual Basic è in grado di gestire pressoché tutti i formati di database per i quali sia previsto un driver ODBC. A cosa serve il metodo MoveFirst dell’oggetto Recordset?

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB15/index.htm[26/09/2010 5:25:26]


.

Il metodo MoveFirst permette di accedere al primo record presente in archivio. Quando la proprietà EOF dell’oggetto Recordset assume il valore logico True? La proprietà EOF (End Of File) assume il valore True quando il programma giunge all’ultimo recrod presente in archivio. Qual è la proprietà dell’oggetto Recordset che indica che la ricerca effettuata non è andata a buon fine? La proprietà che assume il valore logico True se un’operazione di ricerca non va a buon fine è denominata NoMatch. Che vantaggi offre l’uso delle query? Le query permettono di fare in modo che il programma abbia una visione personalizzata dell’archivio, ovvero che acceda solo delle informazioni utili. Ciò semplifica il compito del programmatore, che non deve occuparsi dei filtrare i dati non necessari. Qual è il linguaggio di definizione delle query supportato da Visual Basic? In Visual Basic le query sono descritte per mezzo del linguaggio SQL. A cosa serve la clausola WHERE in una query SQL? La clausola WHERE permette di specificare la condizione che deve essere soddisfatta dai record che devono essere estratti dall’archivio. Qual è la clausola da utilizzare per fare in modo che i dati siano ordinati in base al valore assunto da un campo? Per fare in modo che i dati siano ordinati in base al valore assunto da un campo è necessario far uso della clausola ORDER BY. Com’è possibile far sì che l’ordinamento in funzione del valore assunto da un campo avvenga in modo decrescente? L’ordinamento avviene in modo decrescente se nella clausola ORDER BY accanto al nome del campo appare la parola DESC. Com’è possibile fare in modo che l’esecuzione di una query su un archivio non produca record duplicati? Per evitare la generazione di record duplicati, è sufficiente far seguire la parola SELECT dalla clausola DISTINCT. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Note Biografiche Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all’indirizzo mcrespi@infomedia.it. VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT e' la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri a risolvere i propri. Sarà

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB15/index.htm[26/09/2010 5:25:26]


Figura 1 Il form dell

Figura 1 Il form dell’applicazione di esempio

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB15/figura1.htm[26/09/2010 5:25:33]


Figura 2 L

Figura 2 L’applicazione di esempio in esecuzione

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB15/figura2.htm[26/09/2010 5:25:42]


LISTATO 1 Il listato del programma di esempio

LISTATO 1 Il listato del programma di esempio Rem Esempio query SQL Private Sub Form_Load() dbArchivio.DatabaseName = "C:\Dev\Archivio.mdb" dbArchivio.Connect = "Access" End Sub Private Sub btnCerca_Click() Dim StringaSQL As String Dim Campi As String Dim CampoRicerca As String Dim CampoOrdinamento As String Dim StringaDati As String

Rem Composizione elenco campi da estrarre Campi = "" If ckCognome.Value = 1 Then Campi = "Cognome" End If If ckNome.Value = 1 Then If Campi <> "" Then Campi = Campi & ", Nome" Else Campi = "Nome" End If End If If CkAnno.Value = 1 Then If Campi <> "" Then Campi = Campi & ", AnnoNascita" Else Campi = "AnnoNascita" End If End If

Rem Controllo del campo su cui effettuare la ricerca

If obCercaNome.Value Then CampoRicerca = "Nome" ElseIf obCercaCognome.Value Then CampoRicerca = "Cognome" Else CampoRicerca = "AnnoNascita" End If

Rem Controllo del campo su cui effettuare l'ordinamento

If obOrdinaNome.Value Then CampoOrdinamento = "Nome" ElseIf obOrdinaCognome.Value Then CampoOrdinamento = "Cognome" Else CampoOrdinamento = "AnnoNascita" End If

Rem Composizione stringa SQL

StringaSQL = "SELECT " + Campi + " FROM Anagrafica"

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB15/listato1.htm[26/09/2010 5:25:48]


LISTATO 1 Il listato del programma di esempio

StringaSQL = StringaSQL + " WHERE " + CampoRicerca StringaSQL = StringaSQL + " = '" + txtDaCercare.Text + "'" StringaSQL = StringaSQL + " ORDER BY " + CampoOrdinamento Rem La stringa è visualizzata nella label lblStringaSQL.Caption = StringaSQL

Rem Esecuzione della query e collegamento al controllo di tipo Data delle 3 etichette Rem lblNome, lblCognome, lblAnnoNascita

dbArchivio.RecordSource = StringaSQL dbArchivio.Refresh

Rem Cancellazione listbox

lstRisultato.Clear

Rem Inserimento dei dati Rem nella listbox

If dbArchivio.Recordset.RecordCount > 0 Then dbArchivio.Recordset.MoveFirst Do While Not dbArchivio.Recordset.EOF StringaDati = lblNome.Caption + " " StringaDati = StringaDati + lblCognome.Caption + " " StringaDati = StringaDati + lblAnnoNascita.Caption + " " lstRisultato.AddItem StringaDati dbArchivio.Recordset.MoveNext Loop Else MsgBox "Nessun elemento trovato" End If End Sub

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB15/listato1.htm[26/09/2010 5:25:48]


.

Programmo Subito n. 16 - 2 Livello - Corso di Visual Basic Il corso dedicato a Visual Basic darà spazio alla gestione della stampante. Sarà illustrato come sia possibile, agendo su alcune semplici proprietà, produrre stampe anche di alto livello

Corso di Visual Basic La gestione della stampante (Parte 16) di Maurizio Crespi Ogni sistema, di qualunque tipo o dimensione, se usato per uso professionale, è corredato da una stampante. Questa periferica, infatti, è ormai diventata una componente imprescindibile di ogni ufficio. Per questo motivo, tutti i programmatori, almeno una volta nella vita, si trovano a dover scrivere del software in grado di gestirla. In particolare, coloro che sviluppano applicazioni gestionali non possono in genere esimersi dal prevedere la rappresentazione su carta delle informazioni elaborate o archiviate. Visual Basic nel tempo si è conquistato una posizione da leader nel campo degli strumenti di sviluppo per applicazioni gestionali. Ciò è dovuto anche alla semplicità e alla flessibilità con cui permette di produrre dei tabulati. L’oggetto Printer In Visual Basic la stampante è rappresentata da un oggetto, denominato Printer. Tutte le operazioni devono pertanto essere eseguite su di esso. Lo scopo della lezione è di consentire al lettore di prendere confidenza con le proprietà e i metodi fondamentali che l’oggetto prevede. Il metodo Print Le stampanti sono nate con lo scopo di permettere la trasposizione su carta dei testi prodotti dal calcolatore. L’operazione elementare per questo tipo di periferiche è quindi rappresentata dalla scrittura di testo. L’oggetto Printer a tal fine mette a disposizione il metodo denominato Print. Il suo utilizzo ricorda quello della parola chiave omonima del linguaggio Basic. Per scrivere una frase è quindi sufficiente invocare il metodo passandogli la stringa da stampare. Ad esempio, la riga Printer.Print "Io leggo Dev"

provoca la scrittura della frase "Io leggo Dev" sulla stampante. Analogamente, le righe Printer.Print "Io leggo Dev" Printer.Print "perché mi insegna a programmare"

provocano la scrittura delle frasi "Io leggo Dev" e "perché mi insegna a programmare". Esse sono poste su due righe differenti. Infatti, analogamente a ciò che avviene nel linguaggio Basic per il comando Print, alla fine della frase è generata automaticamente una sequenza costituita dai caratteri CR (Carriage Return, ovvero ritorno del carrello di stampa nella posizione di inizio riga) e LF (Line Feed, ovvero avanzamento di una riga). Ciò, tuttavia, a volte può risultare fastidioso, soprattutto quando si desidera comporre delle frasi a partire da informazioni calcolate dal programma in punti diversi. Per evitare che sia richiesto alla stampante di andare a capo, è necessario far seguire l’invocazione del metodo Print dal punto e virgola. Le righe Printer.Print "Io leggo Dev"; Printer.Print "perché mi insegna a programmare"

provocano pertanto la scrittura della frase Io leggo Devperché mi insegna a programmare

Si noti che in questo caso non sono stati inseriti automaticamente degli spazi fra le parole "Dev" e "perché". È infatti cura del programmatore l’introduzione al termine di una stringa degli spazi tali da

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB16/index.htm[26/09/2010 5:27:15]


.

impedire che sia unita alla successiva quando ciò non è desiderato. Quindi, per scrivere la frase correttamente, è necessario aggiungere uno spazio al termine della prima stringa, come nelle righe che seguono: Printer.Print "Io leggo Dev "; Printer.Print "perché mi insegna a programmare"

In alcuni casi, invece, può verificarsi la necessità di inserire delle righe vuote. Per fare ciò, è sufficiente richiamare il metodo Print senza parametri. Ad esempio, la riga Printer.Print

fa sì che la testina della stampante si posizioni sulla riga successiva a quella corrente. L’incolonnamento dei dati Spesso, quando si stampano dei dati, si rivela necessario il loro incolonnamento. È il caso, ad esempio, dei documenti per uso fiscale. In questi casi, l’uso delle tabulazioni può rivelarsi molto utile. Esse permettono di suddividere il foglio in colonne, ognuna larga 14 caratteri. Visual Basic permette di gestire le tabulazioni per mezzo dell’opzione Tab del comando Print. Ad esempio, le righe Printer.Print Tab(2); Printer.Print "Dev"

provocano la stampa della stringa "Dev" nella seconda colonna del foglio. Si noti che il parametro numerico descrive sempre una posizione assoluta. Quindi, il numero della colonna in cui la stampa avviene è indipendente dalla posizione assunta dalla testina di stampa prima dell’esecuzione dell’istruzione. Per mezzo dell’opzione Tab non è possibile definire uno spostamento relativo, bensì solo uno assoluto. L’unica eccezione è costituita dal caso in cui il parametro numerico è omesso. La scrittura avviene allora nella colonna successiva a quella corrente o, se la testina si trova alla fine del foglio, nella riga seguente. Pertanto, le righe Printer.Print Tab; Printer.Print "Dev"

fanno sì che nella colonna successiva a quella corrente sia scritta la parola "Dev". Si noti che le colonne iniziano ogni 14 caratteri. La loro lunghezza risulta allora dipendente dal tipo di carattere utilizzato e non dalle dimensioni del foglio. L’inserimento di spazi Spesso, soprattutto quando si devono indicare degli importi in valuta, è opportuno allineare i testi a destra. L’incolonnamento per mezzo delle tabulazioni può in questi casi non rivelarsi una scelta corretta, dal momento che permette di allineare i testi a sinistra ma non agevola un granché l’allineamento a destra. Può allora rivelarsi utile l’uso dell’opzione Spc del metodo Print, che permette di stampare una sequenza di spazi in quantità pari al valore indicato come parametro. Calcolando opportunamente tale dato, è quindi possibile ottenere il corretto allineamento a destra del testo. Si osservi la procedura AllineaDestra di cui è riportato di seguito il codice sorgente: Private Sub AllineaDestra(ByVal Stringa As String, ByVal LarghCol As Integer) Dim Lungh As Integer Dim Spazi As Integer Stringa = Trim(Stringa) Lungh = Len(Stringa) Spazi = LarghCol - Lungh Printer.Print Spc(Spazi); Printer.Print Stringa; End Sub

Essa provvede a stampare la stringa fornitale come parametro dopo averla fatta seguire da spazi la cui quantità è espressa dalla variabile Spazi. Il suo valore è calcolato come differenza fra il numero della colonna in cui deve avvenire l’allineamento, fornito come parametro (LarghCol) e la lunghezza della stringa da stampare. Si noti che tale procedura funziona correttamente solo se il carattere utilizzato è di tipo a spaziatura non proporzionale. In caso contrario, infatti, le larghezze dei caratteri, compresi gli spazi, risultano diverse fra loro e rendono molto più complesso l’allineamento. Al fine di ridurre il rischio di errore derivante da un cattivo allineamento delle informazioni e di rendere più semplice e veloce lo sviluppo delle applicazioni, è pertanto consigliabile l’uso di un carattere a larghezza non proporzionale (ad esempio il "Courier New") nei programmi che prevedono la stampa di tabelle o altri dati su modulistica di tipo fiscale.

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB16/index.htm[26/09/2010 5:27:15]


.

L’impostazione del carattere da utilizzare Per selezionare un carattere diverso da quello predefinito, occorre intervenire sulla proprietà FontName dell’oggetto Printer. Ad esempio, la riga Printer.FontName = "Courier New"

fa sì che la stampa sia eseguita con il carattere "Courier New". È inoltre possibile impostare la dimensione del font da utilizzare agendo sul valore della proprietà FontSize. L’insieme dei valori che essa può assumere è rappresentato dalle misure in punti che sono accettate dal sistema per il carattere selezionato. Per i font di tipo raster, i valori possibili sono pochi, mentre per i caratteri true type, che costituiscono la quasi totalità della dotazione di Windows, le dimensioni possono variare in un intervallo estremamente vasto. Pertanto, per impostare quello che i tipografi chiamano corpo del carattere, ovvero la sua dimensione, al valore corrispondente a 10 punti, occorre scrivere Printer.FontSize = 10

Anche lo stile del carattere può essere variato. Ciò avviene agendo su alcune proprietà in grado di assumere dei valori booleani. Ad esempio, la riga Printer.FontBold = True

fa sì che il testo sia scritto in grassetto. La riga Printer.FontItalic = True

seleziona invece lo stile corsivo. La sottolineatura è invece legata alla proprietà FontUnderline. Pertanto, può essere attivata mediante la riga Printer.FontUnderline = True

Un’altra proprietà, in genere poco usata, è quella che permette di generare delle stampe in cui il carattere risulta barrato. Essa è denominata FontStrikethru. Le proprietà sopra elencate sono combinabili fra loro. Si osservi il seguente codice: Printer.FontName = "Arial" Printer.FontSize = 20 Printer.FontBold = True Printer.FontItalic = True Printer.FontStrikethru = False Printer.Print = "Io leggo Dev"

provocano la stampa della frase "Io leggo Dev" in Arial grassetto corsivo di corpo 20. L’utilizzo di più tipi di caratteri in un documento Le impostazioni relative al carattere sono attive per tutti i testi stampati dopo l’assegnazione dei valori alle proprietà, fino a quando esse non subiscono variazioni. In altre parole, le impostazioni riguardanti il font non interessano l’intero documento, a meno che non siano state definite prima della sua stampa. Inoltre, possono essere variate a piacere al suo interno. È quindi possibile usare un numero teoricamente infinito di caratteri diversi in un’unica stampa. Si osservi l’esempio che segue: Printer.FontName = "Arial" Printer.FontSize = 20 Printer.FontBold = True Printer.FontItalic = False Printer.FontStrikethru = False Printer.Print = "Io leggo Dev" Printer.FontSize = 15 Printer.Print = "perché mi insegna" Printer.FontSize = 10 Printer.FontItalic = True Printer.Print = "a programmare!"

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB16/index.htm[26/09/2010 5:27:15]


.

Il testo prodotto è composto da 3 righe aventi dimensioni diverse. L’ultima, inoltre, si differenza per lo stile, essendo scritta in corsivo. Il passaggio a una nuova pagina Molto spesso, le stampe che un programma deve produrre superano la capienza di una pagina. In questi casi, occorre inserire uno o più salti di pagina. Ciò è possibile invocando il metodo NewPage, senza argomenti, come illustrato di seguito: Printer.NewPage L’utilizzo di tale metodo provoca inoltre l’incremento di un’unità del valore della proprietà Page che, come è facile intuire, contiene il numero della pagina corrente. Si osservi la seguente procedura Private Sub PaginaSucc Printer.NewPage Printer.Print "Pagina "; Printer.Print Printer.Page End Sub

Essa ha lo scopo di provocare l’avanzamento alla pagina successiva e di inserire nella parte superiore del nuovo foglio il numero di pagina. L’avvio della stampa Coloro che leggendo questo articolo hanno già provato a scrivere del codice volto a produrre una stampa, potrebbero aver subìto una delusione. Infatti, con molta probabilità, la stampante non ha prodotto alcun risultato. Ciò è dovuto al fatto che i documenti sono prima composti in memoria e solo in seguito inviati alla stampante. Ciò permette la massima flessibilità, nonché la possibilità di annullare una stampa già iniziata. L’invio di un documento alla stampante avviene quindi solo dopo la sua completa definizione, ovvero quando si provvede a dichiararne il completamento per mezzo del metodo EndDoc, da richiamare senza l’ausilio di parametri, come indicato di seguito: Printer.EndDoc

L’annullamento di una stampa Come si è già accennato, è possibile annullare una stampa in corso di definizione. Per fare ciò, basta ricorrere al metodo KillDoc. Ad esempio, la riga Printer.KillDoc provvede alla cancellazione della stampa in corso.

Un semplice esempio… La lezione termina con un piccolo esempio. Si tratta di un semplice programma in grado di stampare una tavola pitagorica. Il suo codice, riportato nel listato 1, è tutto contenuto nella procedura Main, in quanto non necessita di un’interfaccia grafica. Esso si compone di due cicli nidificati. Uno è utilizzato per gestire le righe, mentre l’altro mantiene traccia delle colonne. Il prodotto dei valori assunti dalle variabili di controllo dei cicli costituisce il dato da visualizzare nella tabella. Si noti che è calcolata la lunghezza del valore da scrivere, per consentire l’anteposizione di un numero di spazi tale da ottenere l’allineamento a destra dei dati. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all’indirizzo mcrespi@infomedia.it. VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT è la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB16/index.htm[26/09/2010 5:27:15]


Scrivere qui l’occhiello dell’articolo (di 150 caratteri per Dev

iniziata. L’invio di un documento alla stampante avviene quindi solo dopo la sua completa definizione, ovvero quando si provvede a dichiararne il completamento per mezzo del metodo EndDoc, da richiamare senza l’ausilio di parametri, come indicato di seguito: Printer.EndDoc

L’annullamento di una stampa Come si è già accennato, è possibile annullare una stampa in corso di definizione. Per fare ciò, basta ricorrere al metodo KillDoc. Ad esempio, la riga Printer.KillDoc provvede alla cancellazione della stampa in corso.

Un semplice esempio… La lezione termina con un piccolo esempio. Si tratta di un semplice programma in grado di stampare una tavola pitagorica. Il suo codice, riportato nel listato 1, è tutto contenuto nella procedura Main, in quanto non necessita di un’interfaccia grafica. Esso si compone di due cicli nidificati. Uno è utilizzato per gestire le righe, mentre l’altro mantiene traccia delle colonne. Il prodotto dei valori assunti dalle variabili di controllo dei cicli costituisce il dato da visualizzare nella tabella. Si noti che è calcolata la lunghezza del valore da scrivere, per consentire l’anteposizione di un numero di spazi tale da ottenere l’allineamento a destra dei dati. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all’indirizzo mcrespi@infomedia.it. VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT è la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa:

subscribe vb-it Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri a risolvere i propri. Sarà anche un modo per instaurare nuovi rapporti di lavoro, collaborazione ed amicizia!

file:///C:/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB16/articolo.htm[26/09/2010 5:39:04]


Sub Main() Dim i As Integer Dim j As Integer Dim Prodotto As String Dim Lungh As Byte Dim NumSpazi As Byte Printer.FontName = "Courier New" Printer.FontSize = 10 For i = 1 To 10 For j = 1 To 10 Prodotto = Str$(i * j) Lungh = Len(Prodotto) NumSpazi = 8 - Lungh Printer.Print Spc(NumSpazi); Printer.Print Prodotto; Next j Rem va a capo Printer.Print Next i Printer.EndDoc End Sub


. Riquadro1

Riquadro2

Programmo Subito n. 17 - Giugno 1999 - 2 Livello - Corso di Visual Basic Il corso dedicato a Visual Basic da nuovamente spazio alla gestione della stampante. Questa volta saranno descritti i metodi che permettono di creare dei tabulati di alta qualità

Corso di Visual Basic La produzione di stampe di elevata qualità (parte XVII) di Maurizio Crespi Nel corso degli anni, gli strumenti che permettono di stampare le informazioni su carta hanno subìto una notevole evoluzione. Dalle prime stampanti a margherita si è passati a quelle ad aghi, in grado di produrre anche della grafica e di operare con diversi tipi di carattere, fino poi ad arrivare alle moderne stampanti a tecnologia laser o a getto di inchiostro, che permettono di ottenere dei risultati di qualità un tempo di esclusiva competenza dei migliori tipografi. L’evolversi delle periferiche ha portato ad un aumento delle esigenze dei programmatori. Dalla semplice rappresentazione di testi si è passati a un uso sempre più massiccio delle grafica, anche per le applicazioni di tutti i giorni. Per questo motivo, lo sviluppatore moderno necessita di uno strumento che gli permetta di gestire le stampanti anche per effettuare le operazioni più complesse. Ancora una volta Visual Basic non delude le aspettative, in quanto mette a disposizione una nutrita serie di metodi tali da rendere l’oggetto Printer, di cui si è già ampiamente parlato nella scorsa lezione, in grado di accontentare anche l’utenza più esigente senza richiedere uno sforzo elevato al programmatore. La proprietà ScaleMode Per effettuare stampe di alta qualità, occorre dapprima essere in grado di posizionare i testi con estrema precisione in qualsiasi punto del foglio. Il concetto di "colonna", visto nella precedente lezione a proposito dell’opzione Tab del metodo Print, non consente un controllo preciso della posizione in cui avviene la stampa, in quanto risulta legata alla dimensione del carattere. Per un posizionamento preciso all’interno del foglio è pertanto necessario disporre di uno strumento che permetta di esprimere delle coordinate in unità di misura semplici da usare e indipendenti dal carattere selezionato, quali sono ad esempio i millimetri. È ciò che la proprietà ScaleMode permette di fare. I valori più utilizzati per questa proprietà sono elencati nel riquadro 1. Per poter definire le coordinate degli elementi da posizionare sul foglio in centimetri, è quindi sufficiente inserire nel codice la riga Printer.ScaleMode = 7

Nella trattazione che segue si supporrà di aver selezionato come unità di misura i centimetri. La verifica delle dimensioni del foglio Per ottenere le dimensioni dell’area di stampa espresse nella scala impostata, è possibile ricorrere alle proprietà ScaleWidth e ScaleHeight. La prima restituisce la larghezza del foglio, mentre la seconda, ovviamente, l’altezza. Esse si basano sulle impostazioni inserite nella finestra di configurazione della stampante nel Pannello di Controllo di Windows.Le righe che seguono stampano un messaggio indicante le dimensioni del foglio in uso. Printer.ScaleMode = 7 Altezza=Printer.ScaleHeight Larghezza=Printer.ScaleWidth Printer.Print "Il foglio è largo cm"; Printer.Print Larghezza; Printer.Print "e alto cm"; Printer.Print Altezza Printer.EndDoc

Le proprietà CurrentX e CurrentY Dopo aver definito una scala, è possibile stabilire la posizione in cui deve essere visualizzata la successiva riga di testo sul foglio. A tal fine, si fa uso delle proprietà CurrentX e CurrentY, che permettono di

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB17/index.htm[26/09/2010 5:31:33]


.

intervenire rispettivamente sulla coordinata orizzontale e su quella verticale. Ad esempio, si supponga di voler scrivere sul foglio a 4 centimetri dal bordo superiore e a 2,5 centimetri da quello laterale sinistro, la frase "Io leggo Dev". Il codice necessario per fare ciò è il seguente Printer.ScaleMode = 7 Printer.CurrentX = 2.5 Printer.CurrentY = 4 Printer.Print "Io leggo Dev" Printer.EndDoc

Le proprietà CurrentX e CurrentY si incrementano automaticamente. I loro valori riflettono pertanto sempre la posizione che è occupata dalla testina di stampa.Per mezzo delle suddette proprietà è anche possibile definire degli spostamenti relativi. Ad esempio, le righe seguenti spostano la testina di stampa a destra di 3 centimetri e in basso di 2 millimetri rispetto alla posizione corrente. Printer.CurrentX = Printer.CurrentX + 3 Printer.CurrentY = Printer.CurrentY + .2

L’allineamento di un testo a destra Si supponga di voler scrivere la frase "Io leggo Dev" a 2 centimetri dal bordo destro del foglio. Per fare ciò occorre calcolare la posizione iniziale in cui deve essere effettuata la scrittura. Essa è pari alla differenza fra la larghezza del foglio, a cui sono sottratti i 2 centimetri di margine, meno la lunghezza del testo. È quindi necessario disporre di uno strumento in grado di calcolare l’ingombro di una frase in base al carattere e allo stile selezionati ed esprimerlo nell’unità di misura in uso. Il metodo TextWidth ha questo scopo. La sua sintassi è: <lunghezza> = Printer.TextWidth (<stringa>)

Per scrivere la frase nella posizione desiderata occorre quindi digitare il seguente codice Testo = "Io leggo Dev" LarghFoglio = Printer.ScaleWidth LarghTesto = Printer.TextWidth(Testo) Printer.CurrentX = LarghFoglio – LarghTesto - 2 Printer.Print Testo

La centratura di un testo Analogamente, è possibile centrare un testo nella pagina. A tal fine si fa ancora uso del metodo TextWidth, nonché delle proprietà ScaleWidth e CurrentX. Questa volta è necessario calcolare lo spazio che rimane libero nella riga, ovvero la differenza fra la larghezza del foglio e quella del testo da scrivere. Il valore ottenuto deve essere diviso per 2. È ciò che fa la procedura CentraTesto. Private Sub CentraTesto(ByVal Testo As String) LarghFoglio = Printer.ScaleWidth LarghTesto = Printer.TextWidth(Testo) Printer.CurrentX = (LarghFoglio – LarghTesto) / 2 Printer.Print Testo End Sub

La scrittura di note a fine pagina In modo perfettamente analogo è possibile stabile l’allineamento di un testo rispetto ai margini superiore e inferiore del foglio. In questo caso, è necessario tenere conto dell’altezza della stringa da stampare. Essa è calcolata dal metodo TextHeight, la cui sintassi è la seguente <altezza> = Printer.TextHeight (<stringa>)

Si supponga di voler scrivere una procedura in grado di visualizzare delle note di fondo pagina in un carattere di corpo 8 a 2 centimetri dal margine inferiore del foglio. Il codice che la descrive è il seguente Private Sub NoteFondo(ByVal Testo As String) Printer.FontSize = 8 AltFoglio = Printer.ScaleHeight AltTesto = Printer.TextHeight(Testo) Printer.CurrentY = AltFoglio – AltTesto – 2 Printer.Print Testo End Sub

La stampa in orizzontale o verticale Ormai tutte le stampanti moderne permettono di impostare l’orientamento della stampa, ovvero di scegliere

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB17/index.htm[26/09/2010 5:31:33]


.

se utilizzare il foglio in modalità portrait (in verticale) o landscape (in orizzontale). Visual Basic offre il supporto per sfruttare questa caratteristica per mezzo della proprietà Orientation dell’oggetto Printer. I valori che essa può assumere sono due: il primo corrisponde alla costante vbPRORPortrait, che ha valore 1 e imposta la stampa in verticale, mentre il secondo, corrispondente alla costante vbPRORLandscape, permette di attivare la stampa in orizzontale. Il tracciamento di linee Sovente, al fine di delimitare delle tabelle o di dare un look più professionale ai propri documenti, si tracciano delle linee sul foglio. Visual Basic offre questa possibilità per mezzo del metodo Line, la cui sintassi è la seguente: Printer.Line <coord_inizio> - <coord_fine>

dove le coordinate sono espresse da coppie di tipo (x,y), in cui x rappresenta la posizione orizzontale espressa nella scala in uso (indicata dalla proprietà ScaleMode) e y si riferisce alla posizione verticale. Pertanto, considerando sempre il valore della proprietà ScaleMode pari a 7, la riga Printer.Line (2,3) – (19,3)

provoca il tracciamento di una linea a 3 centimetri dal bordo superiore del documento che, in un comune foglio in formato A4 largo 21 centimetri, occupa l’intera larghezza dell’area stampabile mantenendo un margine di 2 centimetri dai bordi. La prima delle coppie indicanti le coordinate può essere omessa. In questo caso è assunta come punto di partenza la posizione corrente della testina di stampa, ovvero la coppia (Printer.CurrentX, Printer.CurrentY) Ad esempio, la riga Printer.Line – (19,3)

provoca il tracciamento di una linea a partire dalla posizione corrente del cursore fino alla posizione distante 19 unità (centimetri, se la proprietà ScaleMode è impostata al valore 7) dal bordo sinistro del foglio e 3 unità da quello superiore. Lo spessore della linea dipende dal valore assegnato alla proprietà DrawWidth. Essa può assumere un valore interno fra 1 e 32767, che esprime il numero di pixel (punti) corrispondente allo spessore desiderato. Ad esempio, le righe

Printer.DrawWidth = 4 Printer.Line (2,3) – (19,3)

fanno sì che sia disegnata una linea di spessore pari a 4 pixel. Un’altra proprietà, denominata DrawStyle, descrive il tipo di tratto della linea. I valori che essa può assumere sono elencati nel riquadro 2. Quelli compresi fra 1 e 4 hanno effetto solo se la proprietà DrawWidth è impostata a 1. Altrimenti, producono una linea continua, esattamente come quella determinata dall’uso dell’impostazione predefinita, ovvero quella corrispondente alla costante vbSolid, che ha valore nullo. Si osservi il seguente codice:

Printer.ScaleMode = 7

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB17/index.htm[26/09/2010 5:31:33]


.

Printer.DrawWidth = 1 Printer.Drawstyle = 1 Printer.Line (2,3) – (19,3)

Esso provoca il tracciamento di una linea orizzontale tratteggiata a partire dalla posizione posta a 2 centimetri dal bordo sinistro del foglio fino alla posizione distante da esso 19 centimetri.

La stampa di immagini Tutte le stampanti presenti sul mercato sono ormai in grado di stampare anche delle immagini, spesso con una risoluzione grafica elevata. Naturalmente, Visual Basic mette a disposizione dei programmatori uno strumento che permette di sfruttare questa capacità. Si tratta del metodo PaintPicture, la cui sintassi è la seguente:

Printer.PaintPicture <immagine>, <x1>, <y1>, [<larghezza>], [<altezza>],

dove <immagine> rappresenta la sorgente dei dati da visualizzare, ovvero è la proprietà Picture di una PictureBox (oggetto atto a contenere immagini). I valori x1 e y1 rappresentano invece le coordinate del punto in cui deve essere posizionato l’angolo superiore sinistro dell’immagine. Ad esempio, si supponga di disporre di una PictureBox, denominata pbImg, in cui è contenuta un’immagine. Per riportare quest’ultima su carta a partire dal punto di coordinate (2,3) è necessario scrivere la riga

Printer.PaintPicture pbImg.Picture, 2, 3

L’immagine è così disegnata in modo che la sua dimensione non sia alterata. Molto spesso, tuttavia, si desidera effettuare un ridimensionamento in fase di stampa. Ciò ha in genere il fine di sfruttare l’intera area disponibile sul foglio, indipendentemente dalle dimensioni di quest’ultimo. Ad esempio, si potrebbe voler stampare l’immagine in modo da occupare tutto il foglio mantenendo un margine di 2 centimetri dai bordi. Ciò è possibile digitando il seguente codice: Printer.ScaleMode = 7 Larghezza = Printer.ScaleWidth - 4 Altezza = Printer.ScaleHeight – 4 Printer.PaintPicture pbImg.Picture, 2, 2, Larghezza, Altezza

Si noti che sono stati utilizzati due ulteriori parametri che descrivono, rispettivamente, la larghezza e

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB17/index.htm[26/09/2010 5:31:33]


.

l’altezza dell’immagine da stampare. Si osservi altresì che ad essi sono stati assegnati dei valori pari alle dimensioni del foglio diminuite di 4 centimetri, al fine di generare i margini. La scelta fra la stampa a colori o in bianco e nero Le stampanti a colori, dato il continuo ridursi dei prezzi, si stanno sempre più diffondendo. La stampa a colori comporta tuttavia un costo per pagina più elevato rispetto a quella monocromatica a toni di grigio. Per questo motivo, spesso si rivela utile fare in modo che le applicazioni siano in grado di operare una scelta fra le due modalità di stampa. Ciò è possibile per mezzo della proprietà ColorMode, che può assumere i valori 1 (corrispondente alla costante predefinita vbPRCMMonochrome) e 2. L’assegnamento di quest’ultimo valore, a cui si può far riferimento anche attraverso la costante vbPRCMColor, fa sì che la stampa avvenga a colori. In caso contrario è monocromatica. Tale proprietà è ignorata nel caso in cui la stampante in uso sia in grado di produrre solo dei tabulati monocromatici.

Conclusioni La capacità di produrre un risultato di qualità non solo sul video ma anche sulla stampante è sempre più richiesta dall’utenza moderna, che sembra accettare sempre di meno i tabulati grezzi e spesso poco leggibili che un tempo costituivano lo standard per le applicazioni gestionali. Oggi le esigenze sono cambiate e con esse le periferiche in grado di stampare le immagini. Oggi un programmatore deve essere in grado di creare delle applicazioni che visualizzino nel migliore dei modi i risultati delle proprie elaborazioni, ricorrendo a quanto di meglio la tecnologia mette a disposizione. Un moderno strumento di sviluppo deve quindi tenere conto di queste esigenze. Visual Basic fin dalla nascita si è affermato come uno dei prodotti più innovativi. Anche per quanto riguarda la gestione delle stampe è all’altezza della propria fama, rivelandosi in grado di soddisfare le richieste dell’utenza più esigente, pur mantenendo la consueta semplicità d’uso che rappresenta il suo fiore all’occhiello. Bibliografia "Visual Basic 5", McGrawHill, ISBN 88-386-0436-3 Maurizio Crespi si occupa di grafica, multimedialità, amministrazione di reti locali e geografiche, nonché della progettazione e dello sviluppo di applicazioni in C++, Visual Basic, Delphi e Director. Può essere contattato tramite Internet all’indirizzo mcrespi@infomedia.it.

VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT e' la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it Una volta iscritto, esponi i tuoi problemi a

vb-it@infomedia.it e aiuta gli altri a risolvere i propri. Sarà

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/VB17/index.htm[26/09/2010 5:31:33]


Riquadro 1 I principali valori assegnabili alla proprietà ScaleMode

Riquadro 1 I principali valori assegnabili alla proprietà ScaleMode I principali valori assegnabili alla proprietà ScaleMode Costante Valore Descrizione predefinita numerico sintetica VbPoints 2 Settantaduesimi di pollice VbPixels 3 Pixel (punti sullo schermo). VbInches 5 Pollici. VbMillimeters 6 Millimetri. VbCentimeters 7 Centimetri.

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB17/riquadro1.htm[26/09/2010 5:31:40]


Riquadro 2 I principali valori assegnabili alla proprietĂ DrawStyle

Riquadro 2 I principali valori assegnabili alla proprietĂ DrawStyle Costante Valore Descrizione predefinita numerico sintetica

vbSolid 0 Linea continua (valore predefinito) vbDash 1 Tratteggio. vbDot 2 Sequenza di punti. vbDashDot 3 Sequenza alternata di linee e punti. vbDashDotDot 4 Sequenze linea-punto-punto. vbInvisible 5 Tratto trasparente. vbInsideSolid 6 Tratto continuo interno.

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/VB17/riquadro2.htm[26/09/2010 5:31:48]


. Figura1

Figura2 Figura3

Corso di Visual Basic Questo articolo spiega gli strumenti che il Visual Basic propone per visualizzare delle immagini grafiche. Nel prossimo numero approfondiremo questa prima parte, per spiegare invece come crearne di nuove.

Corso Visual Basic La visualizzazione di immagini grafiche Parte 18 di Andrea T.M. Frosini Il Visual Basic è un ambiente di sviluppo che offre almeno una soluzione ad ogni tipico problema della programmazione quotidiana. Perciò se avete ricevuto una commessa per lo sviluppo di un semplice programma orientato alla gestione di magazzino, potete accettare perché siete in grado di interagire con una base dati e di eseguire delle stampe di qualità. Quanto vi manca è forse quel "qual cosa in più" rispetto a ciò che i vostri concorrenti sono disposti a promettere. Per esempio la visualizzazione della foto che riguarda il generico articolo gestito dal vostro programma, oppure la visualizzazione di un catalogo elettronico.Ciò che vi occorre è quindi uno strumento adatto per visualizzare immagini. A tale scopo, e’ possibile utilizzare: un Form un controllo chiamato Picture un secondo controllo (simile al precedente) chiamato Image. Vediamo ora come vare. Immagini contenute in un Form Per visualizzare un’immagine in un Form create un nuovo progetto partendo da zero. Posizionatevi quindi sulla finestra principale del progetto (normalmente chiamata Form1), e cercate nella relativa palette delle proprietà la voce Picture. Accanto ad essa trovate un pulsante: premetelo, e vi si aprirà una finestra che vi permette di scegliere il file da visualizzare. Esso deve ovviamente essere di tipo grafico, ossia deve avere un’estensione appartenente al seguente elenco: BMP, DIB, GIF, JPG, WMF, EMF, ICO, CUR.

Fra gli esempi allegati a questo articolo troverete anche alcune immagini in formato Bitmap, che potete usare per eseguire i vostri esperimenti. Perciò selezionatene una a caso, e confermate la finestra di scelta file su cui vi trovate. Potete inserire un’immagine anche importandola dalla ClipBoard di Windows, a patto di avercela precedentemente inserita con un editor di disegni. Se così non è allora lanciate, per esempio, il programma Paint e scarabocchiate qualche cosa al suo interno. Selezionato tale immagine ed inviatela in ClipBoard. Poi tornate in VB, e premete il tasto destro del mouse sul Form. Si apre un menù di contesto: scegliete la voce Paste (o Incolla) per copiare in automatico l’immagine dalla ClipBoard… al Form. La cancellazione di un’immagine dal Form è un’operazione altrettanto semplice: ritornate sulla palette delle proprietà del Form e riposizionatevi sulla voce Picture. Premete poi il tasto "Canc" assicurandovi che la posizione del cursore sia sul primo carattere della stringa che compare in Picture. Bene, adesso che sapete come inserire e cancellare un’immagine a design time (cioè in fase di creazione), preoccupiamoci di come fare le stesse cose a run time (durante l’esecuzione del programma). Inserire immagini a Run time Per visualizzare un’immagine a run time, dobbiamo usare un funzione che fa parte della libreria standard di Visual Basic. Il suo nome è piuttosto facile da ricordare, poiché si chiama LoadPicture. Il suo uso è altrettanto immediato, perché basta eseguire un codice come quello che segue. Form1.Picture = LoadPicture("ciliegia.bmp")

Per cancellare l’immagine dal Form è sufficiente richiamare la LoadPicture con una stringa vuota: Form1.Picture = LoadPicture("")

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb18/index.htm[26/09/2010 5:32:52]


.

Oppure eseguire un assegnamento a Nothing: Form1.Picture = Nothing Un’altra funzione di fondamentale importanza è la SavePicture, tipicamente utile per salvare un’immagine su disco. Il suo uso, almeno nella forma, è del tutto simile a quello approntato per la LoadPicture. Ma attenzione a non perdere i vostri dati: la SavePicture è distruttiva nei confronti del file su cui la farete operare, perciò per evitare spiacevoli sovrascritture è bene accertarsi che l'utente sia d'accordo. Un esempio di codice utile per chiedere conferme è il seguente: Dim bSi As Boolean bSi = True If Dir("pippo.bmp") <> "" Then bSi = MsgBox(_ "Sei sicuro?", _ vbYesNo) End If If bSi = True Then SavePicture _ Form1.Picture, _ "pippo.bmp" End If Ricordo che la funzione Dir usata, serve proprio per verificare l'esistenza di un file su disco. Prima di richiamare la SavePicture dovete inoltre essere certi che all’interno del Form vi sia un’immagine da salvare, e questo lo ottenete con il seguente codice: If Form1.Picture <> 0 Then ... End If Se non farete così, otterrete dal VB un noioso e poco professionale messaggio di errore. Per leggere un’immagine da ClipBoard, dovete usare il metodo GetData dell’oggetto Clipboard usando il seguente codice: Form1.Picture = Clipboard.GetData(vbCFBitmap) Come avete visto la GetData è molto semplice da usare, perché è sufficiente passare come suo parametro il formato con il quale vogliamo importare l’immagine. I formati disponibili sono pochi, ma sufficienti per coprire la maggior parte delle esigenze: vbCFBitmap, vbCFMetafile e vbCFDIB.

Ovviamente potrebbe non esserci nulla di interessante in ClipBoard, o per lo meno nulla che assomigli ad un formato grafico (potrebbe ad esempio esserci del semplice testo proveniente da un editor). Perciò prima di richiamare la GetData, potete usare il metodo GetFormat per scoprire se ci sono immagini di pronto utilizzo. Per esempio con il seguente costrutto If, è possibile verificare se in ClipBoard esiste un immagine di tipo Bitmap:

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb18/index.htm[26/09/2010 5:32:52]


. If Clipboard. GetFormat( vbCFBitmap) Then Form1.Picture = Clipboard.GetData( vbCFBitmap) End If

Per salvare un’immagine anche in ClipBoard dovete usare il metodo SetData dell’oggetto Clipoard. Ecco come fare: Clipboard.SetData Form1.Picture, vbCFBitmap

Tutto ciò che sino ad ora avete appreso in via del tutto teorica, lo potete sperimentare dal vivo usando FORM.VBP (reperibile sul sito ftp di Infomedia), che ho preparato utilizzando la versione 6 del Visual Basic.Ma adesso è tempo di occuparci di nuove cose, ossia del controllo Image che ci permette di perimetrare un’immagine… Il controllo Image A volte visualizzare un’immagine in un Form è sconveniente, perché non si può controllare né la sua posizione video, né la sua dimensione. Se queste esigenze sono (o saranno) anche le vostre, allora potete usare il controllo Image, appositamente progettato per visualizzare immagini.Image è presente nella palette dei controlli tramite l’icona visibile in Figura 1.Il suo uso è piuttosto semplice: selezionatelo dalla palette, ed inseritelo all’interno di un Form così come fate di solito per ogni altro classico componente Visual Basic.Dopodiché, con esso potrete fare le stesse cose previste per i Form, riciclando quindi lo stesso codice VB. Ovviamente là dove compariva la scritta Form1, ora deve apparire la scritta Image1. È la stessa cosa che ho fatto io per l’esempio IMAGE.VBP (reperibile presso il sito ftp di Infomedia) che è un’opportuna copia del precedente progetto FORM.VBP.La proprietà fondamentale di Image si chiama Stretch. Se essa è impostata al valore True, allora il controllo Image stirerà in lungo e in largo l’immagine, sino a quando essa non coprirà l’intera superficie video perimetrata dal controllo stesso. Perciò la prima immediata conseguenza visuale dell’operazione di Strech, è la trasformazione dei cerchi in ellissi e dei quadrati in rettangoli. Se invece tale proprietà è impostata al valore False, allora l’immagine si estenderà oltre il perimetro del controllo Image, a partire però dal suo angolo superiore sinistro. Il controllo Picture Un’apparente ridondanza del controllo Image è il controllo Picture. Sembrano simili, ma non lo sono affatto.Picture è un controllo abbastanza duttile nelle sue funzionalità, perché dotato di alcuni strumenti necessari per agire sull’immagine in esso visualizzata. Attenzione però: il controllo Picture non è un elaboratore di immagini come ad esempio lo è Paint Shop Pro, ma un semplice editor grafico non interativo che permette di tracciare figure geometriche fondamentali. Quindi segmenti, rettangoli ed archi di curva.La sua icona è visibile in Figura 2, mentre il suo utilizzo lo dettaglierò nel prossimo numero di questo corso di programmazione Visual Basic.Dunque arrivederci al prossima puntata, e nel frattempo (a mo’ di esercizio), provate ad usare da soli il controllo Picture "aiutandovi" con il manuale in linea del VB. Potrete così confrontare i vostri risultati, con le informazioni che leggerete sul prossimo numero di DEV. Andrea T.M. Frosini lavora presso il laboratorio di Ricerca e Sviluppo della Top Software S.A di S.Marino, per la quale (negli scorsi dieci anni trascorsi all'interno del team del progetto Passepartout http://www.topsoft.com) si è occupato di programmazione di sistema, di porting, dello sviluppo di componenti per librerie di base, di interpreti, di compilatori p-code e di tool di sviluppo multipiattaforma usando il linguaggio C/C++. Da diversi anni collabora stabilmente con la redazione di DEV. Può essere contattato tramite l’account afrosini@infomedia.it.

VB-IT: per tutti gli sviluppatori VB o aspiranti tali VB-IT è la mailing list italiana interamente dedicata a Visual Basic, VBA (Visual Basic for Application) e VBScript. Se sei uno sviluppatore esperto oppure ti interessa il mondo Visual Basic anche solo per diletto, troverai VB-IT utilissima! Consigli, suggerimenti, trucchi, soluzioni a problemi comuni e molto altro. Per iscriversi, gratuitamente, a VB-IT è sufficiente inviare un messaggio a majordomo@infomedia.it e nel body inserire la stringa: subscribe vb-it Una volta iscritto, esponi i tuoi problemi a vb-it@infomedia.it e aiuta gli altri a risolvere i propri. Sarà anche un modo per instaurare nuovi rapporti di lavoro, collaborazione ed amicizia!

file:///C|/Documents and Settings/alberto/Desktop/access/corsovb/Vb18/index.htm[26/09/2010 5:32:52]


Figura 1 L

Figura 1 L’icona del controllo Image.

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb18/figura1.htm[26/09/2010 5:32:58]


Figura 2 L

Figura 2 L’icona del controllo Picture: attenzione a non confonderla con la precedente‌

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb18/figura2.htm[26/09/2010 5:33:07]


Figura 3 Il programma FORM

Figura 3 Il programma FORM.VBP in azione.

file:///C|/Documents%20and%20Settings/alberto/Desktop/access/corsovb/Vb18/figura3.htm[26/09/2010 5:33:14]



Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.