Lavorare con le ListBox o ComboBox a una e a più colonne
- parte seconda -

| <<<Prima parte | Seconda parte | Terza parte>>> | Quarta parte >>> |

Lavorando col VBA di Excel si ha la possibilità di usare i controlli ListBox e ComboBox a più colonne. La tecnica è leggermente differente dall'uso degli equivalenti controlli ad una colonna.

ListBox o ComboBox a più colonne

Ricordo che anche in questi casi

Questi sono i dati che useremo in questi esempi (oramai penso che avremmo acquisito il nuovo metodo di lavorare con gli intervalli senza più fare riferimento alla classica notazione A1):

Cognome Nome Indirizzo CAP Città
Migliavacca Luigi VIA DEL TUSCOLANO 1 42033 Muscoline
Scicchitano Andrea VIA SABIN 34/2 67020 Rifreddo di Saluzzo
Migliavacca Luigi VIA DEL TUSCOLANO 1 42033 Muscoline
Migliavacca Luigi VIA DEL TUSCOLANO 1 42033 Muscoline
Edelvisi Maurizio STRADA MARCHESANE 434 58020 Uppello
Borsotti Mirella STRADA MARCHESANE 434 26010 Malborghetto
Maggi Massimo VIA SABIN, 34/2 32032 Cittadella

 

Come vedremo qui di seguito esistono molti metodi per riempire una ListBox o una ComboBox.

Il discorso è leggermente articolato e spero di riuscire ad esporlo chiaramente.

Per comodità trascrivo l'ordine che ho seguito nell'esposizione di queste note.

  1. Riempimento di ComboBox e ListBox usando i cicli
    • Per un controllo ListBox o ComboBox a più colonne usando le matrici
    • Per un controllo ListBox o ComboBox a più colonne usando i dati di un intervallo
  2. Riempimento di ComboBox e ListBox senza usare i cicli
    • Per un controllo ListBox o ComboBox a più colonne usando una matrice
    • Per un controllo ListBox o ComboBox a più colonne usando i dati di un intervallo
    • Intestazioni di colonna con ColumnHeads e RowSource
  3. Riempi e trasponi i dati che vengono da un intervallo (metodo interessante o poco documentato)
    • i dati che provengono da una matrice
    • i dati che provengono da un intervallo del foglio di Excel
  4. lettura delle scelte effettuate in una ListBox a più colonne

 


Riempimento di ComboBox e ListBox usando i cicli

Questo metodo possiamo applicarlo sia con l'uso di matrici, sia leggendo i dati direttamente da un intervallo del foglio di Excel

La ListBox viene riempita usando degli opportuni cicli ed usando l'ormai famoso Additem.

In VBA si ha la possibilità di usare anche ListBox e ComboBox a più colonne. Ma per usare queste occorrono alcuni accorgimenti.

Dalla guida in linea leggiamo queste notizie riguardanti queste voci.

Ma passiamo subito a degli esempi pratici.

 

Per un controllo ListBox o ComboBox a più colonne usando le matrici

Per usare una matrice a due dimensioni per un controllo ListBox o ComboBox eseguiamo queste operazioni:

Dim Intervallo As Range
Dim Righe, Colonne, R, C
Dim Matrice()
Worksheets("Foglio1").Select
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
ReDim Matrice(1 To Righe, 1 To Colonne)
For R = 1 To Righe
For C = 1 To Colonne
Matrice(R, C) = .Cells(R + 1, C)
Next
Next
End With
With ListBox1
.Clear
.ColumnCount = Colonne
.BoundColumn = 2
For R = 1 To Righe
.AddItem
For C = 1 To Colonne
ListBox1.List(R - 1, C - 1) = Matrice(R, C)
Next
Next
End With

Per un controllo ListBox o ComboBox a più colonne usando i dati di un intervallo

Se invece preleviamo i dati da un intervallo del foglio di Excel possiamo notare che la procedura è simile a quella appena vista:

Dim Righe, Colonne, R, C
Dim Intervallo As Range
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
Set Intervallo = .Offset(1, 0).Resize(Righe, Colonne)
End With
With ListBox1
.Clear
.ColumnCount = Colonne
.BoundColumn = 2
For R = 1 To Righe
.AddItem
For C = 1 To Colonne
.List(R - 1, C - 1) = Intervallo(R, C)
Next
Next
End With

 


Riempimento di ComboBox e ListBox senza usare i cicli

Invece di usare cicli, usando particolari proprietà e/o metodi è possibile riempire i controlli ListBox e ComboBox con una semplice istruzione

Per un controllo ListBox o ComboBox a più colonne usando una matrice

In questo esempio, per caricare il controllo ListBox con i valori di una matrice viene usata la proprietà List(). In questo caso, la proprietà List non include indici tra le sue parentesi.

Dim Intervallo As Range
Dim Righe, Colonne, R, C
Dim Matrice()
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
ReDim Matrice(1 To Righe, 1 To Colonne)
For R = 1 To Righe
For C = 1 To Colonne
Matrice(R, C) = .Cells(R + 1, C)
Next
Next
End With
With ListBox1
.ColumnCount = Colonne
.BoundColumn = 2
.List() = Matrice
End With

Per un controllo ListBox o ComboBox ad una colonna usando i dati provenienti da un intervallo

Usare un intervallo per riempire una ListBox o una ComboBox è simile a quel che abbiamo appena visto.

Ma al posto di usare la proprietà List è necessario usare la proprietà RowSource che specifica l'origine da cui proviene un elenco di un controllo ComboBox o ListBox

Dim Righe, Colonne
Dim Intervallo As Range
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
Set Intervallo = .Offset(1, 0).Resize(Righe, Colonne)
End With
With ListBox1
.ColumnCount = Colonne
.BoundColumn = 2
.RowSource = Intervallo.Address
End With

 

Le intestazioni di colonna con ColumnHeads e RowSource

L'intestazione di colonna funziona solo quando per i controlli ComboBox o ListBox è impostata la proprietà ColumnHeads e viene usata la proprietà RowSource per caricare questi controlli. In questo caso viene usata come intestazione di colonna la riga immediatamente sopra l'intervallo che viene mandato nel controllo.

Ecco il codice di esempio:

Dim Righe, Colonne
Dim Intervallo As Range
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
Set Intervallo = .Offset(1, 0).Resize(Righe, Colonne)
End With
With ListBox1
.ColumnHeads = True
.ColumnCount = Colonne
.BoundColumn = 2
.RowSource = Intervallo.Address
End With

 

 

Riempi e trasponi

E' possibile che qualche volta abbiamo la necessità di trasferire il contenuto di una matrice o di un intervallo ruotando i dati, ossia visualizzare i dati in colonne anzichè in righe come in questo esempio:

Migliavacca Rizzi Liberali Di Maggio ecc.
Luigi Carlo Franca Mario ecc.
VIA P. FIMIANI-LOC.TRIVIO VIA SABIN 34/2 VIA DEL TUSCOLANO 1 TERMINAL CONTENITORI MOLO VII ecc.
35031 84040 67030 48012 ecc.
Varena Noli Calcinatello Verzegnis ecc.
FR TO BO AL ecc.

 

A noi invece servono i dati disposti in quest'altra maniera:

Migliavacca Luigi VIA P. FIMIANI-LOC.TRIVIO 35031 Varena FR
Rizzi Carlo VIA SABIN 34/2 84040 Noli TO
Liberali Franca VIA DEL TUSCOLANO 1 67030 Calcinatello BO
Di Maggio Mario TERMINAL CONTENITORI MOLO VII 48012 Verzegnis AL
Scicchitano Andrea VIA SABIN, 34/2 10060 Peri NA
Maggi Massimo VIA DEL TUSCOLANO 1 20070 Formignana VI
Gerardini Silvano Z.I SAMBUCETO 61040 Villaretto Chisone LC
ecc. ecc. ecc. ecc. ecc. ecc.

 

Può capitare che per memorizzare dei dati in una matrice non possiamo dimensionare opportunamente la matrice con

ReDim Matrice(1 To Righe, 1 To Colonne)

perchè non conosciamo a priori la quantità di record da memorizzare. In questo caso dobbiamo rfidimensionare la matrice man mano che leggiamo i record con

ReDim Preserve Matrice(1 To Colonne, 1 To R)

Questo caso può succedere per esempio quando andiamo a leggere dei record residenti in un file di testo.

Riempi e trasponi con matrice

Vediamo con questo esempio cosa succede durante la lettura del file di testo e mandare i dati così letti in un controllo ListBox o ComboBox.

Dim Percorso, FileTesto, Filenum, Campi
Dim Riga, Matrice()
Dim Righe, Colonne, R, C
' viene determinato il nome del file da leggere comprensivo di percorso completo
Percorso = ThisWorkbook.Path & "\"
FileTesto = Percorso & "archivio.txt"
' quindi si verifica se il file esiste
If Dir(FileTesto) = "" Then
MsgBox "file non trovato"
Exit Sub
End If
' si inizia la lettura del file di testo riga per riga
Righe = 0
Filenum = FreeFile
Open FileTesto For Input As #Filenum
' nella prima riga del file di testo sono memorizzati i nomi dei campi
' da questi si determinano quanti campi deve contenere la matrice
Line Input #Filenum, Riga
Colonne = UBound(Split(Riga, "*")) + 1
' da qui continuo con la lettura del file di testo riga per riga
While Not EOF(Filenum)
Line Input #Filenum, Riga
Campi = Split(Riga, "*")
R = R + 1
' dopo aver suddiviso le singole righe lette dal file di testo
' incremento la matrice e memorizzo i nuovi dati nella matrice
ReDim Preserve Matrice(1 To Colonne, 1 To R)
For C = 0 To UBound(Campi)
Matrice(C + 1, R) = Campi(C)
Next
Wend
Close #Filenum
' finita la lettura del file ho la matrice pronta ma con i dati invertiti
With ListBox1
.Clear
.ColumnCount = Colonne
.BoundColumn = 2
.Column() = Matrice
End With

Il codice esposto qui sopra è abbastanza commentato per cui mi esimo dall'aggiungere ulteriori commenti. Aggiungo solo queste poche note.

Alla fine della lettura del file di testo nella matrice abbiamo i record disposti nelle colonne anzichè nelle righe.

A noi invece serve che i record siano giustamente nelle righe.

La ListBox del VBA riesce ad accogliere tra le sue righe la matrice ruotata di 90° con la istruzione ListBox1.Column() = Matrice anzichè ListBox1.List() = Matrice

Repetita iuvant

  1. Normalmente i dati vengono memorizzati in una matrice a due dimensioni distribuendo i record tra le righe i campi tra le colonne.
  2. Ma in una matrice dinamica da dover ridimensionare con ReDim Preserve i dati vengono ruotati perchè in una matrice dinamica è possibile ridimensionare, senza perdere i dati, solo l'ultima dimensione:
    ReDim Preserve Matrice(1 To Colonne, 1 To R + 1)

Primo caso:

ReDim Matrice(1 To Colonne, 1 To Righe)
For R = 1 To Righe
For C = 1 To Colonne
Matrice(R, C) = Intervallo(R, C)
Next
Next

La matrice ha questo schema:

  Campo 1 Campo 2 Campo 3
Record 1      
Record 2      
Record 3      
Record 4      
Record 5      
Record 6      
Record 7      

secondo caso:

For R = 1 To Righe
ReDim Preserve Matrice(1 To Colonne, 1 To R)
For C = 1 To Colonne
Matrice(C, R) = Intervallo(R, C)
Next
Next

La matrice ha questo schema:

  Record 1 Record 2 Record 3 Record 4 Record 5 Record 6 Record 7
Campo 1              
Campo 2              
Campo 3              

 

 

Riempi e trasponi i dati che vengono da un intervallo

Ma vediamo come comportarci se la stessa situazione la troviamo in un foglio di Excel.

Questo metodo è un po' più complesso, nella sintassi da usare rispetto a quelli fin qui visti.

Dim Righe, Colonne
Dim Intervallo As Range
Worksheets("Foglio4").Select
With Range("A1").CurrentRegion
Righe = .Rows.Count - 1
Colonne = .Columns.Count
Set Intervallo = .Offset(1, 0).Resize(Righe, Colonne)
End With
With ListBox1
.ColumnCount = Colonne
.BoundColumn = 2
.List() = Application.Transpose(Intervallo)
End With

 

Lettura delle scelte effettuate in una ListBox ad più colonne

Per leggere l'elemento selezionato da una ListBox a più colonne possiamo usare uno dei seguenti metodi:

lettura della voce scelta nella ListBox aiutati dalla proprietà Value (di default, quindi non necessario)

Se abbiamo definito una BoundColumn ci verrà restituito il dato presente nella colonna designata

In caso contrario ci viene restituito il dato della prima colonna

TextBox1 = ListBox1

lettura della voce aiutati dalla proprietà List() indicando la riga, normalmente restituito dalla Proprietà ListIndex e la colonna di nostra scelta da cui prelevare il dato

R = ListBox1.ListIndex
TextBox1 = ListBox1.List(R, 3)

 


| <<<Prima parte | Seconda parte | Terza parte>>> | Quarta parte >>> |