Le TextBox nelle UserForm e il SetFocus.

 

Quando si usano delle istruzioni in vba per controllare se i dati immessi in una TextBox sono corrispondenti alle nostre esigenze, o non restino vuote (senza dati), è necessario utilizzare degli "eventi" che attivino questi controlli, eventi legati ad "oggetti" presenti sulla UserForm. In genere io uso l'evento Click di un CommandButton, al quale faccio prima controllare l'esattezza dei dati ammessi nelle TextBox, e se tutto è Ok, l'esecuzione delle istruzioni previste per quell'evento. Tipico esempio quello sotto.

Private Sub CommandButton1_Click()

If TextBox1 = "" then  'Se la textbox1 è vuota

MsgBox "Inserire i dati richiesti"   'fai apparire questo messaggio

TextBox1.SetFocus  'riporti il focus sulla TextBox1

Exit Sub  'esci dalla routine e non esegui le istruzioni sottostanti

End If 

Range("A1") = TextBox1 'in caso la textbox1 contenga dati, esegue questa istruzione

End Sub
 

Come vediamo, usiamo l'istruzione SetFocus per riportare il focus sulla textbox interessata. Poichè l'esecuzione di questa istruzione è affidata all'"oggetto" CommandButton che in questo momento ha il focus, il codice esegue il comando senza fallire. Questo perchè dopo aver generato l'evento Click(Index As Long) il controllo attivo passa all'"oggetto" immediatamente successivo sulla userform, che possieda la proprietà "TabIndex" . ( Quando si inseriscono oggetti sulla userform, tutti gli oggetti inseriti che possiedono questa proprietà, ricevono un indice progressivo assegnato dal programma, il valore indice (TabIndex) inizia con zero (0) assegnato al primo oggetto, e si incrementa di un valore per ogni altro oggetto inserito. E' quindi questo valore che determina la sequenza di selezione oggetti generata per esempio, dal tasto Invio.) Ritornando al nostro Click, l'istruzione TextBox1.SetFocus Porta il focus sull'oggetto indicato anzichè lasciarlo all'oggetto previsto dal successivo valore presente nel TabIndex del CommandButton.

E dopo questa lungagnata, "Non mi faccio un brodo? Ma me lo faccio doppio!" Come diceva un comico in una reclame televisiva. E' successo, e non me ne ero mai accorto, che se invece di un evento Click di un CommandButton, si voglia scegliere un evento proprio della stessa TextBox1 per ottenere questo benedetto controllo immissione dati, siamo necessariamente portati ad utilizzare due eventi tipici: AfterUpdate oppure Exit. Però entrambi questi eventi, sembra non intercettino un istruzione come TextBox1.SetFocus in quanto l'evento stesso è successivo alla lettura dell'istruzione, e come tale segue la normale procedura di selezione dell'oggetto successivo rappresentato dal suo TabIndex. In parole povere, non si riesce a far ritornare il focus sulla TextBox1. (Questa istruzione in effetti viene eseguita, ma è tanto rapida che non la vediamo, vedremo solo ciò che Exit o AfterUpdate fanno alla fine: quella di spostare il focus sull'oggetto successivo). Tra l'altro, per un esempio come quello citato all'inizio, dove si voglia controllare se una textbox rimane vuota, l'evento AfetUpdate non interverrebbe comunque: AfterUpdate vuol dire: "dopo l'aggiornamento", ma se in una textbox non scriviamo niente, non l'abbiamo "aggiornata" e quindi l'evento non viene attivato.

Rimane quindi un'unica possibilità, se vogliamo usare un evento di una textbox,  quello di scegliere l'evento Exit . E non sarà più necessario usare un istruzione SetFocus, ma sfruttare il metodo Cancel dell'evento Exit con una semplice istruzione come questa:

Cancel = True

Questa istruzione equivale ad interrompere l'uscita dalla textbox (exit) e lascia il focus sulla textbox stessa. Andrà posizionata subito sotto l'istruzione If...Then in modo che si interrompa l'uscita riposizionando lo "Stato Attivo" (focus) sulla textbox, e possano essere eseguite le successive istruzioni. Presento un esempio nel quale si controlla che nella textbox si inseriscano solo numeri e non lettere o numeri e lettere (IsNumeric) e un controllo che impedisca l'immissione di valori negativi, il tutto con la segnalazione di un messaggio di "Errato", e la selezione del valore immesso come non valido. Questo è l'esempio:

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Dim MyVar, MyCheck, Search, SearchString, where
Dim X
X = Mid(TextBox1, 1, 1)
'legge il primo carattere nel textbox
MyVar = TextBox1.Value
 'Assegna il valore alla variabile.
MyCheck = IsNumeric(MyVar)
' Restituisce Vero.
If MyCheck = False Or X = "-" Then 
'se non è un numero o se inizia col segno meno, allora
Cancel = True  
'QUESTO è IL PUNTO IN CUI POSIZIONARE CANCEL
SearchString = TextBox1.Text
'text che contiene i dati
Search = TextBox1
'text con parola da cercare
where = InStr(SearchString, Search)
If where Then
TextBox1.SelStart = where - 1
' l'inizio della selezione e
TextBox1.SelLength = Len(Search)
' la lunghezza.
'TextBox1.SetFocus
MsgBox "Errato !!"
End If

Else
TextBox2.SetFocus
End If
End Sub

Se sarò stato di aiuto per qualcuno, tanto meglio. Buon lavoro.