Le Date: usare il controllo ActiveX "Masked Edit Control". - pagina vista: volte

In questo articolo vedremo come poter eseguire una verifica se una data viene scritta in maniera corretta, rispettando cioè la sintassi italiana che prevede di scrivere prima i giorni, poi un separatore (una barra o una lineetta), poi il mese, il separatore, infine l'anno, che potrà essere indicato in forma breve (a due cifre) o estesa (a quattro cifre), esempio 15/12/04 oppure 15/12/2004 (giorno 15/ mese 12/ anno 04 o 2004). Userò la barra "/" come separatore e l'anno a due cifre negli esempi che faremo.

Tra i vari errori di scrittura che si possono verificare, troviamo: 

  • l'eliminazione di un separatore (1512/04 oppure 15/1204)

  • l'eliminazione di tutti i separatori (151204)

  • l'aggiunta o la trasposizione di un separatore (15//12/04, oppure 1/512/04 o ancora 15/12//04, o 15/12/0/4, o 15/1/204, ecc.)

  • l'immissione di un giorno inesistente nel calendario, 32, 35 o altro : 32/12/04

  • l'immissione di un numero mese superiore a 12 (mesi nell'anno) :  31/13/04

  • l'immissione di un giorno di fine mese non esistente per il mese indicato, esempio 30/02/04 (30 febbraio non esiste) oppure 31/11/04 (Novembre ha 30 giorni, ecc.)

  • l'immissione della lettera "o op. O" al posto dello zero  3O/12/04 opp. 3o/12/04

Per l'anno non esiste nessuna possibilità di verifica (a meno che non si definiscano istruzioni che delimitino l'anno minimo o massimo introducibile), infatti, a meno che non si inserisca un anno superiore a 9999, sia Excel sia il vba considerano valido l'anno introdotto, anche se abbiamo errato, scrivendo 15/12/2014 mentre volevamo scrivere 15/12/2004.

Ora, se usiamo celle del foglio di lavoro ovviamente impostate come formato cella a : data, e sbagliamo nello scrivere una data, Excel ci evidenzia l'errore spostando la data così scritta a sinistra nella cella (la considera "testo", non più data) anzichè metterla a destra nella cella, come fa con le date, ma se usiamo scrivere date in una (o più) TextBox poste su UserForm, queste non reagiscono, lasciandoci l'errore di scrittura, e poi troveremo problemi quando lavoreremo con una data che data non è, magari passandola ad una cella di un foglio di lavoro.

Purtroppo per noi, le verifiche di una data, basate su istruzioni che prevedano l'utilizzo di IsDate o di gestione degli errori (On Error GoTo.. opp. If Err.Number = ecc.), o ancora di controllo della posizione dei separatori con Mid, Left, Right (tutti già visti in altri articoli sul tema Data, sui due siti ennius) non intercettano tutti gli errori di scrittura possibili, ma intervengono solo se si verifica un determinato tipo di errore di scrittura, e lasciano passare altri non previsti dalle specifiche istruzioni.

Inoltre alcuni tipi di errori di scrittura, per effetto del diverso modo di "leggere" le date da parte del codice vba, che conosce solo il sistema inglese (mese/giorno/anno) non vengono rilevati come errori. Facciamo un esempio : noi scriviamo la data 06/13/04, dove appare evidente che il mese 13 non esiste; se inseriamo la funzione IsDate per verificare che la data scritta sia realmente una data, la data (per noi scritta errata) passerebbe in quanto il codice la legge, e non trovandola idonea ad una data scritta in italiano, la interpreta come data scritta in inglese: come 13/06/04, e quindi comunque data valida: il giorno 13 del mese di giugno esiste, ed interverrebbe solo se il giorno anzichè 06 fosse 15: in questo caso la data 15/13/04, anche letta in inglese non esisterebbe : 13/15/04 (infatti il mese 15 non esiste neppure in inglese). E questo nonostante si usi magari una "funzione di conversione del tipo", come CDate(data), o la funzione Format per formattare la data "mm/dd/yy" o "dd/mm/yy".

Sebbene sia comunque possibile compilare per ogni TextBox tutta la serie di verifiche da eseguire : se la data è una data, se i mesi o i giorni non sono corrispondenti, se si verificano errori, se i separatori sono nella posizione giusta, ecc., ritengo complicato per i più,  istruire decine di righe di istruzioni e uscirne vincitori, visto anche che dovremmo poter sfruttare "eventi" diversi per attivare alcune o parte di queste istruzioni.

Conviene a questo punto utilizzare il controllo aggiuntivo Masked Edit Control, un "controllo ActiveX" che assomiglia ad una TextBox, ma nel quale è possibile predisporre una "maschera" per l'introduzione dati.

Vediamo intanto come richiamare questo "controllo" : cliccando destro sulla "casella degli strumenti" associata ad una UserForm, scegliere la voce "Controlli Aggiuntivi", e nella finestra che appare, cercare e mettere un segno di spunta accanto alla voce "Microsoft Masked Edit Control, version 6.0" (o versione disponibile sul proprio computer) che corrisponde al file MSMASK32.OCX contenuto nella cartella System32 di Windows.

Ci troveremo con questa icona aggiunta alla Casella degli strumenti

e selezionandola, spostandoci sulla UserForm, potremo posizionarla e dimensionarla come una TextBox. Lo scopo di tutto questo traffico è quello di disporre di una "TextBox" dove troveremo già predisposti sia gli spazi che verranno occupati dai numeri della data che introdurremo, sia i separatori che avremo scelto: dovremo scrivere solo il giorno il mese e l'anno in successione, senza doverci preoccupare di scrivere i separatori e, ad ogni numero digitato, il cursore si posizionerà automaticamente nella posizione successiva, saltando automaticamente i separatori. Tramite questo "controllo" è possibile quindi eliminare tutti gli errori tipici fatti con i separatori. Vediamo una controllo Masked Edit Control con la maschera predisposta:

Come si vede, è stata predisposta la "maschera" per l'introduzione dei dati: i trattini bassi sono i "segnaposto" che verranno sostituiti dai numeri che digiteremo, e i "separatori" rappresentati dalle barre ( / ) ( la maschera è impostata per anno breve, a due cifre, ma sarà possibile definire l'anno a 4 cifre, dipenderà da noi). Vediamo ora quali sono le due "proprietà" del Masked Edit interessate all'impostazione della "maschera":

  • la proprietà Mask, con la quale definiamo il formato della maschera: useremo tanti cancelletti (#) segnaposto, quanti sono i numeri che formeranno la data, e il tipo di separatore che desideriamo (la barra / o un trattino - ) e la imposteremo così:  ## / ## / ##  per l'anno a due cifre, ## / ## / ####  per l'anno a 4 cifre; (ho separato i segnaposto solo per evidenziare il posizionamento, in realtà la vedremo e la scriveremo così:   nella finestra delle proprietà).

  • la proprietà PromptChar che imposta o restituisce il carattere utilizzato (per richiedere l'input all'utente) come segnaposto per i numeri; qui abbiamo usato il trattino basso ( _ ) , ma potevamo usare l'asterisco ( * ) o un'altro carattere. Si preferisce il trattino basso perchè idealizza una linea di base su cui scrivere. E' sufficiente scrivere un solo carattere nelle impostazioni di questa proprietà.

Fino ad ora non mi sembra molto difficile, non trovate? Ora vedremo le istruzioni compilate, però prima è necessario chiarire in quale modo identifichiamo nelle istruzioni la data che avremo scritto nel controllo MaskEdBox1, useremo:

  • la proprietà Text del controllo Masked Edit, che restituisce il testo incluso nel controllo, cioè solo la data che avremo immesso, senza separatori, ad esempio 151204. Questo ci servirà per eseguire verifiche sul giorno e/o sul mese.

  • la proprietà FormattedText del controllo Masked Edit che restituisce la stringa visualizzata nel controllo, quindi la data intera comprensiva dei separatori, questo per intenderci 15/12/04. Questo ci servirà per "usare" la data per passaggi successivi (ad esempio per trasferirla ad una cella del foglio di lavoro).

I più attenti avranno però letto che queste due proprietà restituiscono un formato "testo" (stringa), non un formato data, dovremo quindi provvedere poi a formattare e rendere come "data" il testo immesso nel controllo.

Velocemente pensiamo ora all'evento che useremo per attivare le istruzioni: io suggerisco l'evento Exit del MaskEdBox1 (questo il "nome" del primo Masked Edit Control posto su UserForm). Questo evento si verifica nel momento in cui il MaskEdBox1 perde lo stato attivo, cioè ci spostiamo su un'altro controllo presente, per esempio premendo un CommandButton. L'evento Exit è particolarmente indicato perchè possiede l'argomento Cancel che, impostato a True, ci consente di mantenere lo stato attivo sul controllo, per intervenire con correzioni, evidenziando la parte da correggere.

Vediamo la routine: non vi spaventate, ho inserito tutte le verifiche possibili  (tranne quelle sui "separatori", inutili visto che le "barre" sono nella maschera):

  • Private Sub MaskEdBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    d = MaskEdBox1.Text 
    'la variabile "d" sarà uguale al contenuto dei soli numeri nella maskedbox
    If d = "" Then Exit Sub 
    'se non avremo scritto niente, si esce dalla routine
    If Left(d, 2) > 31 Then 
    'ora controlliamo la storia del giorno che non deve superare il 31; se i primi due valori della 'variabile "d" sono superiori a 31, si avvisa con un messaggio, si selezionano i due primi numeri, e si esce dalla routine
    MsgBox "Giorno Errato"
    Cancel = True
    MaskEdBox1.SelStart = 0
    MaskEdBox1.SelLength = 2
    Exit Sub
    ElseIf Mid(d, 3, 2) > 12 Then
     'ora controlliamo che il mese non superi il numero 12, si avvisa, si esce
    MsgBox "Mese Errato"
    Cancel = True
    MaskEdBox1.SelStart = 3
    MaskEdBox1.SelLength = 2
    Exit Sub
    ElseIf Mid(d, 5, 2) = "" Or  Mid(d, 6, 1) = ""  Then
     'aggiungiamo una verifica che controlla che non ci siamo scordati 'di scrivere l'anno, o anche la seconda e ultima cifra dell'ann, si avvisa, si seleziona, si esce
    MsgBox "Manca l'anno"
    Cancel = True
    MaskEdBox1.SelStart = 6
    MaskEdBox1.SelLength = 2
    Exit Sub
    End If
    '--------per rendere completo il sistema di verifica, inseriamo le istruzioni che controllino anche di non superare il 'giorno di fine mese rispetto ai mesi di febbraio e dei mesi a fine 30
    e = Left(d, 2) 
    'con la variabile "e" prendiamo il giorno della data introdotta
    f = Mid(d, 3, 2)
     'con la variabile "f" prendiamo il mese della data introdotta
    Select Case f   'usiamo il Select Case che verificherà  il Caso Febbraio (02 in numero)
    Case "02"
    If e > 29 Then  
    'se il giorno ("e") è maggiore di 29 avvisiamo, selezioniamo e usciamo dalla routine
    MsgBox "Giorno inesistente nel mese " & f & ""
    Cancel = True
    MaskEdBox1.SelStart = 0
    MaskEdBox1.SelLength = 2
    Exit Sub
    End If
    Case "04", "06", "09", "11"
    'ora si controlla i Case dei mesi di 30 giorni
    If e > 30 Then  
    'se il giorno ("e") è maggiore di 30 avvisiamo, selezioniamo e usciamo dalla routine
    MsgBox "Giorno inesistente nel mese " & f & ""
    Cancel = True
    MaskEdBox1.SelStart = 0
    MaskEdBox1.SelLength = 2
    Exit Sub
    End If
    End Select

  • 'finite tutte le verifiche, a questo punto prendiamo con la variabile "a", la data completa di separatori ma vista come 'testo, la formattiamo usando il formato data inglese, e la passiamo ad una cella del foglio sottostante; penserà excel a 'convertirla come data in italiano, ed accettarla nella cella impostandone il formato cella a data.
    a = MaskEdBox1.FormattedText 
    [A1] = Format(a, "mm/dd/yy")
    ' oppure usando la funzione di conversione del tipo di dati CDate, senza necessità di 'Format, così:  [A1] = CDate(a) - la funzione CDate provvede già ad assimilare il testo "a" come data, ma in inglese; è nel passaggio alla cella sul foglio che Excel provvede a convertirla in formato italiano.
    End Sub

Avrei esaurito l'argomento data, e spero di aver illustrato esaurientemente come intervenire (esistono comunque altri sistemi) nel verificare l'esattezza di una data scritta.

Buon lavoro.

prelevato sul sito www.ennius.altervista.org