ListBox (vale anche per le ComboBox): eliminare dati dalla lista, e stampare la lista. - dal 04/09/04 pagina vista: volte

Ovvero: un esame completo di come caricare dati, eliminarne una parte, e infine stampare il contenuto di una ListBox.

Ci occupiamo ancora di ListBox (i concetti espressi valgono anche per le ComboBox) ActiveX, cioè presi da "Strumenti di controllo" e non da Moduli. Sembra che ci siano ancora incomprensioni sul come "lavorare" con questi "Oggetti" ActiveX. I termini italiani per riconoscere questi due oggetti sono "Casella":

  • "Casella di riepilogo" - per la ListBox

  • "Casella combinata" o anche detta "Casella a discesa"  - per la ComboBox

Sappiamo che per inserire (o se preferite: "caricare") dati in uno di questi due "oggetti" dobbiamo sfruttare le proprietà RowSource, se le "caselle" sono poste su una UserForm, o ListFillRange se invece sono inserite su un foglio di lavoro. Dovremo fornire l'area che contiene i dati da visualizzare (in genere le celle di una colonna di un foglio di lavoro), fornendo i riferimenti dell'area, seguendo questa sintassi:

  • ListBox1.RowSource = "A1:A100"  oppure:

  • ListBox1.RowSource = "Foglio3!A1:A100" se l'area dati risiede su un foglio diverso da quello su cui apriremo l'Userform.    oppure:

  • ListBox1.RowSource = "pippo"   se avremo assegnato un nome all'area dati. In questo caso se "pippo" è riferito ad un'area su un'altro foglio, non occorre definire il foglio essendo già implicito nel percorso che mira a "pippo".

Le stesse istruzioni varieranno la proprietà se, come detto, si troveranno su un foglio di lavoro, in questo caso dovremo usare la proprietà ListFillRange al posto di RowSource, così : ListBox1.ListFillRange = "A1:A100" . Chiaro fino ad ora?

Un'altro modo per "caricare" i dati nelle caselle, è quello di usare il Metodo AddItem, che letteralmente vuol dire: "aggiungi un elemento" e visto che stiamo riferendoci ai dati da caricare, si può intendere come: "aggiungi un dato". Alla stessa stregua, se vorremo togliere, eliminare un dato, useremo il Metodo RemoveItem ("rimuovi un elemento").

Ma per ora esaminiamo solo AddItem. Intanto vediamo come usare la sintassi necessaria a sfruttare il metodo, che è molto semplice: dobbiamo dire su quale oggetto vogliamo aggiungere un elemento, e quale è l'elemento da aggiungere, così:

  • ListBox1.AddItem "Roma" - infatti ListBox1 è l'oggetto, e la parola Roma fra doppi apici è l'elemento da aggiungere. Volendo aggiungere più di in elemento (o dato, per intenderci), dovremo ripetere la stessa istruzione per quanti dati vorremo caricare, esempio:

   e questo sarà il risultato:
ListBox1.AddItem  "Roma"
ListBox1.AddItem  "Milano"
ListBox1.AddItem  "Palermo"
ListBox1.AddItem  "Napoli"
ecc.ecc                                  

In questo esempio abbiamo scritto noi direttamente nel codice, i nomi (dati) da caricare, usando il Metodo AddItem, ma quando dovremo prelevare dei dati da un elenco o tabella posto su un foglio, dovremo usare un'altro sistema, un ciclo For Next oppure For Each Next che si incarichi di reperire i dati da far aggiungere, se vorremo sfruttare il metodo AddItem.

Se conosciamo già l'ampiezza ( lunghezza ) dell'elenco da caricare, potremo usare un istruzione come questa:

  • Dim CL As Object
    For Each CL In Sheets(1).[A1:A100]
    ListBox1.AddItem CL.Value
    Next

Se invece non sapremo a priori quanto è lungo l'elenco da caricare, potremo usare la funzione End per reperire l'ultima cella occupata nell'area dati, assegnando ad una variabile "elenco" la zona compresa da tutte le celle occupate nella colonna A (in questo esempio, partendo dalla A1), e poi proseguire con il ciclo che cercherà ora nella zona "elenco", così:

  • Dim CL As Object
    Set elenco = Sheets(1).Range([A1], [A1].End(xlDown))
    For Each CL In elenco
    ListBox1.AddItem CL.Value
    Next

In entrambi i casi comunque ciò che volevamo vedere è questa riga di istruzione : ListBox1.AddItem CL.Value che serve appunto ad aggiungere (AddItem) nella ListBox1 il valore che sarà nella cella (CL) letta ad ogni ciclo.

Quando e come useremo queste istruzioni? Possiamo scegliere due soluzioni:

  • usare un CommandButton nel quale evento Click inserire le istruzioni, e saremo noi a decidere quando e se "caricare" i dati nella ListBox.

  • usare l'evento Activate della UserForm in modo che all'apertura della stessa si carichi automaticamente la lista.

Passiamo ora a esaminare alcune proprietà delle "Caselle" che dovremo conoscere. Quando si "traffica" con loro, non possiamo non conoscerle. Cominciamo col dire che una "casella" ha un suo sistema per identificare i dati che contiene, infatti ogni casella possiede un "indice riga" relativo al suo contenuto: è un indice numerico che partendo dal numero zero ( 0 ), si incrementa di una unità per ogni valore ( o dato ) che contiene. ( Non voglio in quest'articolo parlare anche delle colonne; è infatti possibile ottenere ListBox a più colonne, anche loro identificate da un numero indice. ) Queste proprietà sono gestibili in programmazione, e ci aiutano a lavorare con i contenuti delle caselle ( ListBox o ComboBox che siano ), vediamole da vicino; intanto, come trovare queste proprietà, consultando la guida in linea: dall'editor di visual basic, digitare List Box in "indice", indi selezionare in "argomenti trovati (finestra 3)" la voce "Controllo ListBox (Casella di riepilogo)" : nella zona granda a destra compare la spiegazione della voce trovata: in quuesta zona, scritto un blu, troviamo anche la parola "Proprietà"; se clicchiamo su di essa, si apre la finestra che mostrerà tutte le proprietà correlate; con un doppio click sulla proprieta, si aprirà nella pagina sottostante le spiegazioni relative alla proprietà selezionata. Navigando in questo modo, potremo reperire tutte le informazioni che ci servono per capire cose che non sappiamo. Così faccio io, e così potrete fare anche voi, e vedrete che avrete meno necessità di chiedere aiuto.

Facciamo comunque un proseguo a beneficio di quei pochissimi che non riusciranno comunque a capire neppure leggendo sulla guida.  Vediamo queste proprietà:

  • List - Restituisce o imposta le voci dell'elenco di un controllo ListBox o ComboBox.- La proprietà List viene utilizzata con le proprietà ListCount e ListIndex. Si utilizza List per l'accesso a elementi dell'elenco. A ogni elemento dell'elenco viene assegnato un numero di riga e un numero di colonna. Possiamo ad esempio assegnare ad una variabile X , un valore contenuto nella casella, usando List e fra parentesi il numero di riga e di colonna con cui in valore è identificato nella ListBox, quindi  :   X = ListBox1.List(2, 0) e con X avremmo nell'esempio dei nomi delle città visto sopra, che X è uguale a "Palermo". (ricordo che la numerazione dell'indice parte da zero, quindi Palermo si trova : indice 0 =Roma, indice 1 =Milano,  indice 2 =Palermo, ecc.)

  • ListCount - Restituisce il numero di voci di un elenco del controllo. Quindi si usa per sapere il numero di quanti elementi sono presenti nella "Casella". Utile per determinare il limite superiore (o numero finale) nei cicli di "spazzolamento" basati sui numeri indice. ListCount è sempre maggiore di un'unità rispetto al valore massimo della proprietà ListIndex, in quanto i numeri di indice iniziano da 0, mentre il conteggio degli elementi inizia da 1. Se non è selezionato alcun elemento, ListCount è uguale a 0 e ListIndex è –1. La sintassi è semplice, si identifica l'oggetto di cui si devono contare gli elementi, e si assegna il valore ad una variabile; esempio : W = ListBox1.ListCount  , e W sarà uguale al numero esatto di elementi "caricati" nella ListBox, che nell'esempio delle città, sarà 4.

  • ListIndex - La proprietà ListIndex contiene un indice della riga selezionata in un elenco. I valori di ListIndex sono compresi tra –1 e un numero minore di un'unità rispetto al numero totale di righe di un elenco (ovvero ListCount – 1). Quando non è selezionata alcuna riga, ListIndex restituisce –1. Quando l'utente seleziona una riga in un controllo ListBox o ComboBox, viene impostato automaticamente il valore di ListIndex. Il valore di ListIndex della prima riga di un elenco è 0, il valore della seconda riga è 1 e così via. Per quanto riguarda la sintassi relativa a questa proprietà, vedremo negli esempi che seguono come impostarla.

  • Text - Questa proprietà restituisce il valore selezionato nella ListBox. Utile quando si voglia restituire il valore ad una variabile, ad una cella del foglio di lavoro, ad una textbox, ecc. La sintassi è semplicissima: TextBox1 = ListBox1.Text , oppure : Selez = ListBox1.Text , o ancora : Sheets(1).[C10] = ListBox1.Text.

Esistono altre proprietà interessanti per la gestione dei dati contenuti in una ListBox, ma non ne parleremo in questo articolo in quanto non pertinenti all'esercizio che vedremo ora.

Il problema, vogliamo : 

  1. selezionare un valore in un elenco di una ListBox, ed eliminare tutti i valori dal valore selezionato al valore inizio elenco,

  2. poi selezionare un altro valore, ed eliminare tutti i valori da questo fino alla fine dell'elenco.

  3. Stampare i valori rimasti nella ListBox.

In pratica eliminiamo la testa, la coda e usiamo il cuore; sembra di fare la grappa, no? I lettori attenti avranno già letto l'articolo "Alimentatore valori celle", in questa sezione, dove sono spiegati i passaggi per eliminare valori da ListBox, ma in quell'esempio si toglie un solo valore per volta, qui useremo comunque un CommandButton al quale facciamo cambiare la Caption: se la Caption sarà uguale ad un certo testo, si eseguiranno delle istruzioni, che si occuperanno anche di modificare la Caption e quindi creare la seconda condizione, con altre istruzioni. Ultima cosa da considerare: per poter stampare il contenuto di una ListBox, consiglio di seguire questa procedura: passare il contenuto della ListBox in una zona di un foglio di lavoro, e poi di creare una macro per la stampa dei dati trasferiti su questo foglio.

Si può usare lo stesso pulsante usato per le eliminazioni dei valori, con le istruzioni per passare i valori residui dalla ListBox al foglio, e con una domanda "se vogliamo la stampa" e quindi se risponderemo si, predisporre le istruzioni per la stampa dell'area dati del foglio di destinazione. Oppure separare le due procedure affidandosi ad un secondo pulsante che si occuperà di passare i valori dalla ListBox al foglio, e quindi di mandare in stampa l'area del foglio. Comunque vediamo le due soluzioni. Vediamo intanto li istruzioni per caricare la ListBox sfruttando l'evento Activate della IserGorm:

Private Sub UserForm_Activate()
Dim CL As Object
For Each CL In Sheets(1).[A1:A100]
'definiamo la zona che contiene i dati su un foglio
ListBox1.AddItem CL.Value 
'e per ogni cella aggiungiamo il suo valore alla ListBox
Next
End Sub

e questa sarà la situazione che vedremo attivando l'userform: la listbox con la lista dei dati provenienti dal range previsto (ovviamente i nomi sono di fantasia)

Passiamo ora a esaminare le istruzioni collegate al pulsante "Togli inizio":

Private Sub CommandButton1_Click()
If ListBox1.Text = "" Then Exit Sub
'inseriamo un semplice controllo che ci fa uscire dalla routine 'se non avremo selezionato nessun valore
'sotto: basiamo l'esecuzione delle istruzioni sul testo della Caption. Ad apertura Form, il pulsante si 'presenta con "Togli inizio" come valore assegnato alla proprietà Caption del CommandButton, e 'quindi l'istruzione verifica appunto se la Caption è uguale a "Togli inizio", poichè la condizione 'risulta vera, verranno eseguite le istruzioni sottostanti.
If CommandButton5.Caption = "Togli inizio" Then
Dim Y As Integer
n = ListBox1.ListCount - 1 
'con la variabile "n" otteniamo il numero delle voci presenti
If n >= 1 Then
'poi verifichiamo che "n" sia uguale o maggiore di 1. vogliamo rendere l'esecuzione 'delle istruzioni solo se avremo almeno un dato nella listbox.
Y = ListBox1.ListIndex
'con la variabile Y prendiamo il numero indice del dato che avremo 'selezionato, quindi iniziamo un ciclo che partirà da questo indice Y e scalerà verso l'inizio di un 'valore ogni ciclo (Step -1)
For X = Y To 0 Step -1 'la variabile X è il contatore che rappresenta il numero indice letto ad 'ogni ciclo
ListBox1.RemoveItem X
'e finalmente togliamo il dato il cui numero indice è rappresentato da X
Next  
'si prosegue fino alla fine del ciclo ripetendo mano a mano il RemoveItem
End If
' e si termina la  condizione Se n  >= 1
CommandButton5.Caption = "Togli fine"
'quindi si rinomina la Caption del commandButton in  '"Togli Fine" in maniera che alla successiva pressione sul pulsante, si verifichi la condizione Else, cioè la caption NON sarà uguale a "Togli inizio"

Else
'questa condizione DEVE prevedere che avremo selezionato un'altro valore nella ListBox, in 'quanto le istruzioni che seguono eliminano i dati dalla fine elenco fino a questo secondo valore 'selezionato. Rinominiamo la Caption predisponendola alla prima condizione. Le istruzioni sono 'simili a queste sopra.
CommandButton5.Caption = "Togli inizio"
n = ListBox1.ListCount - 1
If n >= 1 Then
Y = ListBox1.ListIndex
For W = n To Y Step -1
ListBox1.RemoveItem W
Next
End If
End If
End Sub

Quindi, ricapitolando, avremo bisogno di selezionare un dato (foto1), premere il pulsante, poi riselezioniamo il secondo valore (Foto 2), e premeremo di nuovo il pulsante. vediamo i passaggi, (notare la caption del pusante che cambia il testo dopo ogni pressione):

Foto 1

 sono spariti i valori sopra e quello selezionato

Foto 2

sono spariti i dati sotto e quello selezionato

Bene, ora che abbiamo eliminato i dati che non volevamo mandare in stampa, esaminiamo le istruzioni collegate al CommandButton "Copia & Stampa". E' opportuno per poter stampare i dati contenuti in una ListBox, trasferire gli stessi dati, copiandoli, in una zona di un foglio all'uopo destinato, e mandare il foglio in stampa. Inseriremo un'istruzione per la pulizia delle celle in modo da cancellare dati precedentemente copiati, e tramite un ciclo che legga i numeri indice relativi ai dati, li possa identificare e copiare, scalando una riga per ogni dato. Supponiamo quindi che il foglio destinato alla stampa sia il foglio 2 e che si scelga in questo foglio la colonna A per copiare i dati. Vediamo le istruzioni:

Private Sub CommandButton2_Click()
Set Fogliostampa = Worksheets("Foglio2")
'impostiamo con la variabile "Fogliostampa" il foglio 2
Fogliostampa.Cells.ClearContents 
 'e puliamo tutte le celle del foglio

n = ListBox1.ListCount - 1
'con "n" prendiamo il numero di quanti dati sono presenti ora nella 'ListBox
Dim X As Long
'la variabile X ora diventa il vettore del numero indice scorso dal ciclo, dal 'numero zero (che corrisponde al primo dato, non scordiamocelo) fino al valore numerico 'rappresentato da "n" ed iniziamo il ciclo
For X = 0 To n
'sotto: rendiamo la cella del foglio 2, colonna A, riga corrispondente al numero rappresentarto da X + 1 (infatti all'inizio X sarebbe zero, e su un foglio la riga zero non esiste) uguale al dato 'rappresentato da List(X), mentre nella ListBox X inizialmente corrisponde al valore "gunny", cioè 'all'indice riga zero. Ovviamente ad ogni Next X si imcrementa di un valore, scalando così di uno 'sia i nomi nella listbox, sia le righe sul Fogliostampa nelle quali celle verrà copiato il nome stesso.
Fogliostampa.Range("A" & X + 1).Value = ListBox1.List(X)
Next
Fogliostampa.PrintOut 
'quindi si stampa il Fogliostampa con i dati copiati

End Sub

Mi sembra ci sia tutto.

 

Buon lavoro.

prelevato sul sito www.ennius.altervista.org