maurogsc.eu
mauro gamberini


home ==> Excel: articoli ==> UserForm - Array di controlli

UserForm - Array di controlli

Situazione.
Ci troviamo nella necessità di dover gestire n controlli in una UserForm e vorremmo avere uno o più eventi comuni. Vediamo di fare un esempio. La nostra UserForm contiene 4 CommandButton e facendo click su uno dei pulsanti, vorremmo chiamare una Sub passando il nome del pulsante, in modo da eseguire codice diverso per ogni CommandButton. Dovremmo scrivere codice all'interno di 4 eventi Click, uno per pulsante. In Visual Basic(il tool di programmazione) c'è la possibilità di creare in modo facile e veloce array(matrici) di controlli che condividono gli eventi. Nel Visual Basic di Excel dobbiamo invece ricorrere ad un *trucco*.

Nota.
Il codice dell’esempio è scaricabile a questo link. Il codice ed i files sono forniti *così come sono* e l’autore declina ogni responsabilità su eventuali problemi causati dal codice o dai files se usati impropriamente. Utilizzate gli esempi forniti o files di test per le vostre prove. Codice e file sono stati testati con(e quindi validi per) Excel 2000/Xp(2002)/2003/2007/2010.

Una classe...
ALT+F11 e siamo nell'editor del Visual Basic. Creiamo un modulo di classe(Inserisci-->Modulo di classe) e rinominiamolo clsCommandButton. Mettiamo questo codice:

Option Explicit

'dichiarazione variabili visibili all'esterno
'della classe

'WithEvents  specifica che la variabile
'è una variabile oggetto utilizzata
'per rispondere agli eventi generati '
'da un oggetto ActiveX.
Public WithEvents cmd As MSForms.CommandButton
Public frm As UserForm

'evento Click
Private Sub cmd_Click()
    'chiamata alla routine mEsegui
    'viene passato come parametro
    'il Name del CommandButton
    'sul quale si è fatto Click
    Call mEsegui(cmd.Name)
End Sub

'routine chiamata dall'evento Click
Private Sub mEsegui(ByVal s As String)
    'MsgBox che identifica il
    'nome del CommandButton passato
    'come parametro
    MsgBox "Hai premuto: " & s
End Sub

Le due variabili Public(quindi visibili ed utilizzabili dall'esterno dell'oggetto che andremo a creare). La prima è preceduta da WithEvents, una parola chiave che specifica che la variabile cmd è una variabile oggetto utilizzata per rispondere agli eventi generati da un oggetto ActiveX(il nostro CommandButton) e che è valida solo nei moduli di classe. La seconda variabile è una variabile oggetto di tipo UserForm. L'evento cmd_Click() sarà quello che risponderà al click sull'oggetto cmd, eseguendo la routine mEsegui().

...e una Collection.
Inseriamo una UserForm(Inserisci-->UserForm) al progetto e aggiungiamole 4 CommandButton. Questo il codice della UserForm:

Option Explicit

'dichiaro le variabili a livello
'di UserForm(visibili cioè da
'tutta la UserForm)
Dim colCommandButton As Collection
Dim myCmd As clsCommandButton

'evento eseguito all'avvio della userForm
Private Sub UserForm_Initialize()
    
    'dichiarazione variabile
    Dim ctl As MSForms.Control
    
    'controllo non vi sia già un
    'oggetto colCommandButton
    '(in questo specifico caso,
    'non servirebbe)
    If Not colCommandButton Is Nothing Then
        'se non c'è, creo l'oggetto
        Set colCommandButton = Nothing
    End If
    
    'creo l'oggetto Collection
    Set colCommandButton = New Collection
    
    'per ogni Control dell'insieme
    'Controls della UserForm
    For Each ctl In Me.Controls
        'se il controllo è un CommandButton
        If TypeOf ctl Is MSForms.CommandButton Then
            'creo un nuovo oggetto
            Set myCmd = New clsCommandButton
            'metto come riferimento alla variabile
            'cmd dell'oggetto creato, l' Item
            '(ctl) dell'insieme Controls a cui
            'fa riferimento il ciclo in questo momento
            Set myCmd.cmd = ctl
            'metto come riferimento alla variabile
            'frm dell'oggetto creato, la UserForm
            Set myCmd.frm = Me
            'aggiungo l'oggetto alla Collection
            colCommandButton.Add myCmd
        End If
    Next
    
    'Set a Nothing della variabile oggetto
    Set ctl = Nothing
    
End Sub

'evento eseguito alla distruzione della UserForm
Private Sub UserForm_Terminate()
    'Set a Nothing delle variabili oggetto
    Set myCmd = Nothing
    Set colCommandButton = Nothing
End Sub

Abbiamo dichiarato e istanziato una Collection(colCommandButton) visibile da tutta la UserForm e dichiarato una variabile oggetto di tipo clsCommandButton(myCmd) che è la classe che abbiamo creato in precedenza. Nell'evento Initialize della UserForm, dichiariamo un'altra variabile oggetto di tipo MSForm.Control(ctl) che ci servirà per ciclare tutti controlli presenti sulla UserForm. Se i controlli sono di tipo CommandButton, andiamo a creare e ad aggiungere un nuovo oggetto alla Collection. Alla variabile oggetto cmd viene assegnato per  riferimento il controllo e alla variabile oggetto frm viene assegnata per riferimento la UserForm. Sarà sufficiente lanciare la UserForm e fare click su uno dei pulsanti per vedere il risultato. Se aggiungiamo altri CommandButton alla nostra UserForm, non dobbiamo modificare nulla nel codice perché verranno aggiunti alla Collection alla prima apertura della UserForm.

Un array di OptionButton.
Potrei aver necessità di avere un array per controlli che si trovano all'interno di un Frame, ad esempio degli OptionButton. Aggiungiamo una nuova UserForm al progetto. Inseriamo un Frame(Frame1) e al suo interno posizioniamo due OptionButton. Molto spesso ci si dimentica dei Frame che risultano invece utilissimi per dividere i controlli sulla UserForm sia dal punto di vista del layout, sia dal punto di vista della programmazione. All'esterno del Frame mettiamo altri 2 OptionButton. Ci serve una nuova classe(Inserisci-->Modulo di classe) e modifichiamone il nome in clsOptionButton.Questo il codice per la classe:

Option Explicit

'dichiarazione variabili visibili all'esterno
'della classe

'WithEvents  specifica che la variabile
'è una variabile oggetto utilizzata
'per rispondere agli eventi generati '
'da un oggetto ActiveX.
Public WithEvents opt As MSForms.OptionButton
Public frm As UserForm

'evento Click
Private Sub opt_Click()
    'chiamata alla routine mEsegui
    'viene passata come parametro
    'la Caption del'OptionButton
    'sul quale si è fatto Click
    Call mEsegui(opt.Caption)
End Sub

'routine chiamata dal dall'evento Click
Private Sub mEsegui(ByVal s As String)
    'MsgBox che identifica la
    'Caption del'OptionButton passato
    'come parametro
    MsgBox "Hai selezionato: " & s
End Sub

E questo il codice per la UserForm:

Option Explicit

'dichiaro le variabili a livello
'di UserForm(visibili cioè da
'tutta la UserForm)
Dim colOptionButton As Collection
Dim myOpt As clsOptionButton

'evento eseguito all'avvio della userForm
Private Sub UserForm_Initialize()

    'dichiarazione variabile
    Dim ctl As MSForms.Control
    
    'controllo non vi sia già un
    'oggetto colOptionButton
    '(in questo specifico caso,
    'non servirebbe)
    If Not colOptionButton Is Nothing Then
        'se non c'è, creo l'oggetto
        Set colOptionButton = Nothing
    End If
    
    'creo l'oggetto Collection
    Set colOptionButton = New Collection
    
    'per ogni Control dell'insieme
    'Controls del Frame1 di questa
    'UserForm
    For Each ctl In Me.Frame1.Controls
        'se il controllo è un OptionButton
        If TypeOf ctl Is MSForms.OptionButton Then
            'creo un nuovo oggetto
            Set myOpt = New clsOptionButton
            'metto come riferimento alla variabile
            'cmd dell'oggetto creato, l' Item
            '(ctl) dell'insieme Controls a cui
            'fa riferimento il ciclo in questo momento
            Set myOpt.opt = ctl
            'metto come riferimento alla variabile
            'frm dell'oggetto creato, la UserForm
            Set myOpt.frm = Me
            'aggiungo l'oggetto alla Collection
            colOptionButton.Add myOpt
        End If
    Next
    
    'Set a Nothing della variabile oggetto
    Set ctl = Nothing
    
End Sub

'evento eseguito alla distruzione della UserForm
Private Sub UserForm_Terminate()
    'Set a Nothing delle variabili oggetto
    Set myOpt = Nothing
    Set colOptionButton = Nothing
End Sub

Se seleziono gli OptionButton racchiusi nel Frame1, ottengo un MsgBox di risposta. Selezionando gli OptionButton all'esterno del Frame1 non ottengo nulla in quanto sto ciclando solo i controlli dell'insieme Controls del Frame1 e solo quelli fanno parte della mia Collection.

Concludendo.
Alcuni eventi non possono essere utilizzati quando si creano array di controlli. Ad esempio per la TextBox non è possibile utilizzare Exit, Enter, BeforeUpdate e AfterUpdate. Quando inserite un evento, generatelo prima nel codice della UserForm per essere poi sicuri di scriverlo correttamente nel modulo di classe(alcuini eventi si aspettano degli argomenti). E' possibile definire più eventi per lo stesso oggetto all'interno di una classe. Nel file di esempio, scaricabile qui, si trova un esempio relativo alle TextBox con più eventi(il codice non è commentato, ma valgono gli stessi commenti che trovate negli altri moduli del progetto).

Per ulteriori informazioni su Microsoft Excel ed il suo Visual Basic, utilizzate questo forum:
http://social.answers.microsoft.com/Forums/it-IT/officeexcelit/threads


Ultimo aggiornamento di questa pagina: 14/10/2009 - mauro gamberini