ComboBox

Ultima modifica: 28-05-2016

Possiamo disporre di diversi tipi di ComboBox:


Le ComboBox disegnate sul foglio

Per la ComboBox presa dai Moduli

Una volta disegnata sul foglio

scegliere formato controllo facendo clic destro sulla ComboBox

nella finestra che si apre scegliere la scheda controllo

in intervallo di input scrivere o selezionare l'intervallo da cui prelevare i dati da mettere nella lista

in collegamento cella scrivere o selezionare la cella dove depositare il dato scelto

Questo controllo, quando viene usato, non restituisce il nome selezionato bensì il numero di indice che il nome selezionato occupa nella lista: se si sceglie il primo elemento restituisce nella cella collegata il numero 1, se si sceglie il terzo elemento restituisce il numero 3 e così via.

Per visualizzare correttamente il valore scelto nella ComboBox occorre usare la funzione =INDICE()

Se nella finestra Formato controllo abbiamo specificato che in H2:H17 abbiamo l'elenco dei nomi da inserire nella ComboBox e abbiamo designato che la C1 è cella collegata, la formula per visualizzare il nome selezionato nella giusta cella che nel nostro caso è la C4 sarà: =INDICE(H2:H17;C1). Altri eventuali riferimenti verranno cercati col classico CERCA.VERT.

Questo sarà lo schema da usare nelle celle della mascherà che dovrà accogliere i dati:

cella C1: =INDICE(H2:H17;C1)

cella C3: =SE(C1="";"";CERCA.VERT(C1;H2:L17;2;FALSO))

cella C5: =SE(C1="";"";CERCA.VERT(C1;H2:L17;3;FALSO))

cella C7: =SE(C1="";"";CERCA.VERT(C1;H2:L17;4;FALSO))

cella C9: =SE(C1="";"";CERCA.VERT(C1;H2:L17;5;FALSO))

cella C11: =SE(C1="";"";CERCA.VERT(C1;H2:L17;5;FALSO))

Qui possiamo vedere un piccolo esempio esempiodi utilizzo di questa ComboBox.

 

Per la ComboBox presa da Strumenti di controllo

Una volta disegnato il controllo sul foglio

scegliere dalla barra Strumenti di controllo il pulsante Proprietà (l'icona con la manina)

si apre la finestra proprietà

in questa finestra eseguire queste operazioni

in ListFillRange scrivere l'intervallo da cui prendere i dati da mettere nella lista: nell'esempio che stiamo portando avanti scriviamo H2:H17. Se l'intervallo di origine si trova in un altro foglio dobbiamo scrivere anche il nome di quel foglio. Es: Foglio2!A1:A15

in LinkedCell scrivere la cella dove deve essere scritto il dato selezionato Es: C1

Questo controllo, contrariamente a quello preso dai Moduli, quando viene utilizzato, restituisce, nella cella indicata in LinkedCell, il nome del dato scelto, perciò in LinkedCell possiamo indicare direttamente la cella che deve visualizzare il dato escludendo così l'uso della funzione =INDICE(H2:H17;C1) usata con l'altro controllo.

Finita questa operazione, per usare la ComboBox, bisogna disabilitare la Modalità progettazione (l'icona con squadra e riga) presente sulla barra degli strumenti.

Nella cella C4 non è più necessario mettere la funzione INDICE in quanto il dato prelevato dalla ComboBox viene scritto direttamente nella cella. Per il resto delle celle rimangono valide le formule appena viste:

cella C3: =SE(C1="";"";CERCA.VERT(C1;H2:L17;2;FALSO))

cella C5: =SE(C1="";"";CERCA.VERT(C1;H2:L17;3;FALSO))

cella C7: =SE(C1="";"";CERCA.VERT(C1;H2:L17;4;FALSO))

cella C9: =SE(C1="";"";CERCA.VERT(C1;H2:L17;5;FALSO))

cella C11: =SE(C1="";"";CERCA.VERT(C1;H2:L17;5;FALSO))

Per maggior chiarezza anche per questa ComboBox ho preparato un modellino esempio simile al precedente.

 

Per questo controllo è possibile aiutarsi col VBA

Se l'uso che si può fare di questa ComboBox con le semplici impostazioni non ci soddisfano possiamo facilmente far uso di istruzioni VBA evitando di impostare le proprietà ListFillRange, LinkedCell o entrambe.

I passi da seguire per usare la ComboBox da VBA sono due:

 

Primo esempio: usare la ComboBox per gestire una maschera gia preimpostata

L'aspetto del foglio non cambia rispetto a quelli già visti precedentemente.

Inizializzazione della ComboBox

Usando l'evento Workbook_Open nel modulo relativo a ThisWorkbook

Private Sub Workbook_Open()
Dim NumR, NumC, R
Dim Intervallo As Range
With Worksheets("Foglio4").Range("H1")
      NumR = .CurrentRegion.Rows.Count
      NumC = .CurrentRegion.Columns.Count
      Set Intervallo = .CurrentRegion.Offset(1, 0).Resize(NumR - 1, NumC)
End With
With Worksheets("Foglio4").ComboBox1
      .Clear
      For R = 1 To Intervallo.Rows.Count
            .AddItem (Intervallo(R, 1))
      Next
End With
End Sub

E' buona norma, anche se a volte può sembrare inutile, cancellare il contenuto della ComboBox prima di provvedere al suo popolamento per evitare che azioni o eventi imprevisti continui ad incrementarne e duplicare gli elementi.

Uso della ComboBox

Usando l'evento Change della ComboBox

Private Sub ComboBox1_Change()
If ComboBox1.ListIndex = -1 Then Exit Sub
Range("C1") = ComboBox1.List
End Sub

Il codice da usare per scrivere il dato scelto dalla ComboBox nella cella C4 si riduce al minimo e lo poniamo nell'evento Change della ComboBox1 grazie alle formule che abbiamo lasciato nel foglio di calcolo. Infatti per risparmiare codice da scrivere nel Private Sub ComboBox1_Change(), nelle celle sottostanti la C4 (la C6, C8, C10, C12) possiamo usare le formule che abbiamo usato precedentemente.

cella C6: =SE(C4="";"";CERCA.VERT(C4;H2:L17;2;FALSO))

cella C8: =SE(C4="";"";CERCA.VERT(C4;H2:L17;3;FALSO))

cella C10: =SE(C4="";"";CERCA.VERT(C4;H2:L17;4;FALSO))

cella C12: =SE(C4="";"";CERCA.VERT(C4;H2:L17;5;FALSO))

cella C12: =SE(C4="";"";CERCA.VERT(C4;H2:L17;5;FALSO))

Una volta aperta la cartella e selezionato il foglio4 è possibile usare la ComboBox che grazie al codice appena visto è già pronta.

Ma questa è una variante quasi inutile alla impostazione fatta con la finestra proprietà del controllo stesso se dobbiamo usare la maschera che ho precedentemente illustrata nella parte superiore dell'esempio. Infatti ci risparmia solo di eseguire le impostazioni da fare nella finestra Proprietà relativa alla ComboBox.

 

Secondo esempio: uso della ComboBox per gestire una tabella dinamica

Ben più utile ed interessante è l'uso del VBA se, invece di indirizzare l'output della ComboBox in una maschera, vogliamo creare un elenco.

In questo caso si potrebbe usare questo codice scritto sempre nell'evento Change della ComboBox1.

Anche in questo caso usiamo i due eventi appena visitati.

Inizializzazione della ComboBox

Usando l'evento Workbook_Open nel modulo relativo a ThisWorkbook

Private Sub Workbook_Open()
Dim NumR, NumC, R
Dim Intervallo As Range
With Worksheets("Foglio3").Range("H1")
NumR = .CurrentRegion.Rows.Count
NumC = .CurrentRegion.Columns.Count
Set Intervallo = .CurrentRegion.Offset(1, 0).Resize(NumR - 1, NumC)
End With
With Worksheets("Foglio3").ComboBox2
.Clear
For R = 1 To Intervallo.Rows.Count
.AddItem (Intervallo(R, 1))
Next
End With
End Sub

Per la ComboBox continuiamo ad usare l'evento Change della ComboBox

Private Sub ComboBox2_Change()
Dim R, R1, C, NumR, NumC
Dim Intervallo As Range
If ComboBox2.ListIndex = -1 Then Exit Sub
'=============================
R = 18
While Cells(R, 1) <> ""
    R = R + 1
Wend
Cells(R, 1) = ComboBox2.Text
'=============================
With Range("H1").CurrentRegion
    NumR = .Rows.Count
    NumC = .Columns.Count
    Set Intervallo = .Offset(1, 0).Resize(NumR - 1, NumC)
End With
'=============================
For R1 = 1 To Intervallo.Rows.Count
    If Intervallo(R1, 1) = Cells(R, 1) Then
        For C = 2 To Intervallo.Columns.Count
            Cells(R, C) = Intervallo(R1, C)
        Next
        Exit For
    End If
Next
End Sub

In questo caso il codice può sembrare leggermente più complesso di quello precedente, ma se lo analizziamo vedremo che non lo è affatto.

Dopo le solite dichiarazioni delle variabili ed aver controllato se è stata eseguita una scelta nella ComboBox, vengono eseguite queste operazioni:

 


La ComboBox che viene usata in una Userform

Concludiamo col terzo caso: la ComboBox usata su una UserForm.

In questo caso occorre necessariamente recarsi in ambiente VBA con uno dei tanti mezzi di cui disponiamo: Alt + F11, dal menù Strumenti => Macro => Visual Basic Editor, oppure scegliendo l'icona "Visual Basic Editor" dalla Barra degli strumenti Visual Basic se è aperta.

In questo ambiente vediamo alcune finestre:

Nella finestra Progetto - VBA Project facciamo clic destro col mouse e, dal menù contestuale scegliamo  "inserisci => UserForm" per inserire un nuovo modulo col suo nome di default UserForm1

Assieme alla UserForm dovremmo vedere anche la finestra Casella degli strumenti. Se questa non è visualizzata clicchiamo sul pulsante Casella degli strumenti.

Per il nostro progettino cerchiamo di costruire una userform simile a questa dove abbiamo usato:

Da questa Casella degli strumenti scegliamo i Controlli che vogliamoe li disegnamo nella UserForm.

Per attivare la funzionalità di questa UserForm scriviamo tutto il codice nel modulo relativo alla UserForm usando gli appropriati Eventi di alcuni oggetti in essa contenuti:

Siccome molti di questi eventi non sono scatenati solo dalle azioni dell'utente ma anche dal mutare delle condizioni sia dellaComboBox1 e della TextBox1 durante l'esecuzione delle varie routines, occorre prestare particolare attenzione nel bloccare le azioni che da questi eventi vengono eseguite se veniamo a trovarci in particolari situazioni.

Con questo sistema molti degli eventi interferiscono con altri e vedremo nel codice che sto per presentare.

L'evento Initialize della UserForm

E' utile dichiarare la variabile Intervallo che memorizzerà l'intervallo di origine dei dati che useremo in questo esempio perchè a questo intervallo faremo riferimento in più di una routine.

La visibilità di questa variabile dovrà essere a livello del modulo relativo alla UserForm, perciò va dichiarata tra le prime righe del modulo, fuori di qualsiari routine:

Dim Intervallo As Range

Di seguito vediamo come sono organizzate le routines

Private Sub UserForm_Initialize()
Dim NumR, NumC, R
With Worksheets("Foglio3").Range("H1")
    NumR = .CurrentRegion.Rows.Count
    NumC = .CurrentRegion.Columns.Count
    Set Intervallo = .CurrentRegion.Offset(1, 0).Resize(NumR - 1, NumC)
End With
'=============================
With ComboBox1
    .Clear
    For R = 1 To Intervallo.Rows.Count
        .AddItem (Intervallo(R, 1))
    Next
End With
End Sub

Con questa compiamo due azioni:

 

L'evento Change della ComboBox1

Private Sub ComboBox1_Change()
If ComboBox1.ListIndex = -1 Then
    TextBox1 = ""
    Exit Sub
End If
'=============================
TextBox1 = ComboBox1.Text
End Sub

La comboBox può avere due stati:

 

L'evento Change della TextBox1

Private Sub TextBox1_Change()
Dim R, R1, C
Dim CTRL As Control
If ComboBox1.ListIndex = -1 Then
    For Each CTRL In Controls
        If (TypeName(CTRL) = ("TextBox")) Then
           CTRL = ""
           C = C + 1
       End If
    Next
    Exit Sub
End If
'=============================
R = 18
While Cells(R, 1) <> ""
    R = R + 1
Wend
For R1 = 1 To Intervallo.Rows.Count
    If Intervallo(R1, 1) = TextBox1 Then
        For C = 2 To Intervallo.Columns.Count
            Controls("textbox" & C) = Intervallo(R1, C)
        Next
        Exit For
    End If
Next
End Sub

Anche in questo caso valutiamo la condizione della ComboBox

 

L'evento Click del CommandButton1

Private Sub CommandButton1_Click()
Dim R, R1, C
Dim CTRL As Control
If ComboBox1.ListIndex = -1 Then Exit Sub
'=============================
R = 1
    While Cells(R, 1) <> ""
    R = R + 1
Wend
'=============================
'Cells(R, 1) = ComboBox1.Text
'For R1 = 1 To Intervallo.Rows.Count
'    If Intervallo(R1, 1) = Cells(R, 1) Then
'         For C = 2 To Intervallo.Columns.Count
'             Cells(R, C) = Intervallo(R1, C)
'         Next
'         Exit For
'     End If
'Next

'=============================
C = 1
For Each CTRL In Controls
    If (TypeName(CTRL) = ("TextBox")) Then
        Cells(R, C) = CTRL.Text
        C = C + 1
    End If
Next
ComboBox1.ListIndex = -1
End Sub

Potete notare che nella routine c'è una parte di codice commentata. Non è una distrazione ma vuol mostrare una alternativa al codice che segue immediatamente sotto.

Altro controllo sullo stato della ListIndex della ComboBox

 

L'evento Click del CommandButton2: la fase conclusiva

Private Sub CommandButton2_Click()
Dim Risp
If ComboBox1.ListIndex = -1 Then
Unload UserForm1
Exit Sub
End If
Risp = MsgBox("sicuro di voler uscire", vbExclamation + vbYesNo, "Attenzione")
If Risp = vbYes Then Unload UserForm1
End Sub

Ancora un controllo sullo stato della ListIndex della ComboBox

la ListIndex è pari a -1, si chiude la UserForm ed il lavoro finisce

la ListIndex è pari al valore del dato scelto: in questo caso si sta tentando di chiudere la UserForm senza scaricare gli ultimi dati selezionati. In questo caso si pone una domanda all'utente se veramente vuole interrompere il lavoro. In caso affermativo si termina il lavoro, in caso contrario si lascia la UserForm aperta per continuare il lavoro.

Questo potrebbe essere un eventuale aspetto del foglio di lavoro esempio

 

Allego il file che ho usato per questa esercitazione: combobox.zip