Disabilitare una voce di menù
Il problema
A volte possiamo desiderare di proteggere da manovre devastanti o comunque errate i dati inseriti con tanta fatica in un foglio di Excel.
Possiamo adottare alcune delle protezioni tra cui c'è quello che ci offre lo stesso Excel: Strumenti / Protezione / Proteggi foglio..., proteggere le celle. Oppure potremo nascondere alcune o tutte le barre degli strumenti e/o dei menù, oppure crearne di nuove costruite ad hoc (cosa che il mio amico Ennius mi ha consigliato di evitare in quanto potrebbe sconvolgere ambienti di lavoro che taluni utenti si sono costruiti con tanta fatica).
Per questi ed altri motivi questa volta ho deciso di mostrarvi come proteggere un foglio di lavoro semplicemente inibendo alcuni comandi indesiderati dalla barra dei menù o dalle barre degli strumenti.
Sia ben chiaro, comunque, che, per quanto ci riguarda, questo lavoro supplementare non mira ad ottenere una protezione inespugnabile al nostro lavoro. Chiunque, con un minimo di conoscenza di programmazione, può eludere le nostre protezioni e distruggere comunque tutto il nostro lavoro. Questo ed altri tipi di protezione, almeno quelli da me presentati, sono rivolti ad utenti corretti e servono solo a facilitargli il lavoro ed evitare di compiere accidentalmente delle manovre errate.
Soluzione
Prima di cimentarci in questa operazione dobbiamo vedere come viene visto un menù dal VBA.
Negli esempi che seguono cerchiamo di torturare le voci: Strumenti / Protezione / Proteggi foglio...
Questo è un esempio di menù che ci viene mostrato da Excel:

Come vedete, per arrivare alla voce che ci interessa, dobbiamo seguire la strada: Strumenti / Protezione / Proteggi foglio...
Anche il VBA, per arrivare a delle voci di menù più interne deve percorrere la stessa strada.

Grazie a questa particolare struttura possiamo decidere a quale livello possiamo disabilitare una voce di menù:
la radice (Strumenti) con tutti i sottomenù
quella intermedia (Protezione) coi suoi eventuali sottomenù
o l'ultima voce del menù (Proteggi foglio) lasciando disponibili via via le voci più a monte
Vediamo brevemente i tre casi.
Disabilitare tutto il menù

Per disabilitare l'intera voce di menù (Strumenti) usiamo la sintassi:
Application.CommandBars("Worksheet menu bar").Controls("strumenti").Enabled = False
Disabilitare una voce del sottomenù

Per disabilitare una voce del sottomenù non è sufficiente specificare semplicemente la voce di menù da disabilitare, ma è necessario specificare l'intero percorso che occorre fare per raggiungere tale voce. Per questo se vogliamo che tutte o parte delle voci comprese nel menù Strumenti siano selezionabili eccetto una o più voci dobbiamo specificarne il percorso:
Strumenti / Protezione
Strumenti / Ricerche...
Di conseguenza l'istruzione sarà:
Application.CommandBars("Worksheet menu bar").Controls("strumenti").Controls("Protezione").Enabled = False
Se l'istruzione ci sembra un pò lunga e poco leggibile possiamo usare anche la forma:
With Application.CommandBars("Worksheet menu bar")
.Controls("strumenti").Controls("Protezione").Enabled = False
End With
Disabilitare voci sempre più basse di un menù

Penso che sia intuitivo, a questo punto, che per raggiungere la voce di menù che ci interessa ad un livello più basso dobbiamo specificarne tutto il percorso:
Strumenti / Protezione / Proteggi foglio... (compresi i punti)
per cui avremo:
Application.CommandBars("Worksheet menu bar").Controls("Strumenti").Controls("Protezione").Controls("Proteggi foglio...").Enabled = False
o, se più ci aggrada:
With Application.CommandBars("Worksheet menu bar")
.Controls("Strumenti").Controls("Protezione").Controls("Proteggi foglio...").Enabled = False
End With
Una nota
Invece dei nomi dei menù, racchiusi tra i doppi apici, possiamo riferirci ad essi usando i loro indici (Item):
Application.CommandBars("Worksheet menu bar").Controls.Item(6).Enabled = False
Application.CommandBars("Worksheet menu bar").Controls(6).Enabled = False
Application.CommandBars("Worksheet menu bar").Controls.Item(6).Controls.Item(9).Controls.Item(1).Enabled = False
Per lavorare sulle altre Barre degli Strumenti
Lo stesso discorso vale per disabilitare i pulsanti di controllo presenti nelle varie Barre degli Strumenti ma qui ci troviamo di fronte ad un'altra difficoltà: reperire il nome o l'indice del controllo.
Se ci è noto il nome della Barra dei menu (Worksheet Menu Bar), non altrettanto potrebbe esserci noto il nome delle altre barre e dei relativi pulsanti. Per ovviare a questo ho messo a punto una routine che riesce a restituirmi tutti i nomi di cui ho bisogno.
In questa routine, tra le dichiarazione delle variabili che userò si distinguono le due dichiarazioni:
Dim Bar As CommandBar
Dim Ctrl As CommandBarControl
Infatti, nei due cicli approntati, con la variabile Bar intendo indicare le CommandBar e con Ctrl i controlli in esse disposti. Debbo confessare che la scelta di quest'ultima associazione è stata abbastanza sofferta in quanto durante la sperimentazione non potevo usare
Dim Ctrl As Control
oppure
Dim Ctrl As CommandBar.Control
perchè non supportati nel seguito della routine di prova.
Un'altra peculiarità del test che sto presentando è che, invece di usare delle MsgBox o scrivere su celle del foglio di Excel, scrivo le notizie nella finestra immediata dell'editor VBA (Visualizza / Finestra immediata).
Sub enumeraBarre()
Dim Bar As CommandBar
Dim Ctrl As CommandBarControl
Dim N, Nome1, Nome2
For Each Bar In Application.CommandBars
If Bar.Visible = True Then
N = Bar.Controls.Count
Nome1 = Bar.Name
Debug.Print Nome1 & "; ";
For Each Ctrl In Bar.Controls
Nome2 =
Ctrl.Caption
Debug.Print
Ctrl.Caption & ", ";
Next
Debug.Print
End If
Next
End Sub
Con questo test intendo esplorare solo le barre degli strumenti visibili al momento dell'utilizzo dell'applicativo. Se volessi passare in rassegna tutte le barre ci accorgeremmo di dover contarne ben 128 (nelle istruzioni appena presentate provate a togliere la "If Bar.Visible = True Then" e relativa "End If").
Con questo test, lavorando sul mio Excel, ottengo questo risultato:
|
Worksheet Menu Bar; &File, &Modifica, &Visualizza, &Inserisci, F&ormato, &Strumenti, &Dati, A&zione, Fi&nestra, &?, Standard; &Nuovo, Apri, &Salva, Autorizzazione (Accesso illimitato), Dest&inatario posta, Stampa (Canon LBP-810), Antepri&ma di stampa, Controllo ortogra&fia..., Ricerc&he..., Tag&lia, &Copia, &Incolla, &Copia formato, &Annulla, &Ripristina, &Annotazioni a penna, Collegamento ipertest&uale..., &Somma automatica, Ordinamento &crescente, Ordinamento &decrescente, &Creazione guidata Grafico, &Disegno, &Zoom, Guida in li&nea Microsoft Excel , Formatting; &Tipo di carattere, &Dimensione carattere, &Grassetto, &Corsivo, &Sottolineato, Allinea a &sinistra, &Centra, Allinea a &destra, &Unisci e centra, &Valuta, Stile perce&ntuale, Stile se¶tore, &Aumenta decimali, &Diminuisci decimali, &Riduci rientro, &Aumenta rientro, B&ordi, Co&lore riempimento, Color&e carattere, Forms; &Etichetta, &Casella di modifica, C&asella di gruppo, &Pulsante, &Casella di controllo, P&ulsante di opzione, C&asella di riepilogo, Ca&sella combinata, &Casella di riepilogo combinata, &Casella combinata a discesa, &Barra di scorrimento, &Casella di selezione, Proprietà di controllo, &Codice, Griglia, &Esegui finestra di dialogo, Visual Basic; &Macro..., &Registra nuova macro..., Protezione..., &Visual Basic Editor, S&trumenti di controllo, &Modalità Progettazione, Microsoft Script Editor, Control Toolbox; &Modalità Progettazione, &Proprietà, &Visualizza codice, &Casella di controllo, &Casella di testo, &Pulsante di comando, &Pulsante di opzione, &Casella di riepilogo, &Casella combinata, &Interruttore, &Pulsante di selezione, &Barra di scorrimento, Etic&hetta, I&mmagine, &Altri controlli..., Drawing; Dise&gno, &Selezione oggetti, &Forme, Li&nea, &Freccia, Re&ttangolo, &Ovale, Cas&ella di testo, &WordArt..., Di&agramma, Cli&pArt..., &Da file..., &Disegno e scrittura a penna, Co&lore riempimento, &Colore linea, Color&e carattere, &Stile linea, &Stile tratteggio, &Stile freccia, &Ombreggiatura, &Stile 3D, |
Su un altro computer o in altri contesti il risultato potrebbe essere diverso.
Un'ultima cosa da notare è che tra i nomi esposti dai vari comandi, a volte troviamo il carattere "&". Questo non è un errore ma è semplicemente una convenzione usata in VBA per impostare uno Shortcuts per tasti di scelta rapida (viene usato il carattere immediatamente a destra di questo carattere speciale) e non ha alcuna importanza indicarlo nell'istruzione che vorremmo usare nel codice.
Application.CommandBars("Formatting").Controls("Tipo di carattere").Enabled = True
Attenzione:
Quando usiamo gli indici possiamo usare sia la sintassi Controls.Item(6) sia la sintassi Controls(6).
Ma attenzione: nell'usare gli indici non sempre troviamo la voce nella locazione che immaginiamo per cui se vogliamo usare gli indici (Item) è consigliabile eseguire preventivamente dei test.
Negli esempi appena mostrati infatti volendo agire sul menù "Strumenti / Protezione / Proteggi foglio..." ci aspetteremmo di poter usare gli indici:
6 - per Strumenti che è la sesta voce nella barra dei menù
8 - che è la posizione occupata da Protezione nel menù Strumenti
1 - che è la posizione occupata da Proteggi foglio... nel sottomenù Protezione
invece ci troviamo la sequenza: 6 - 9 - 1 come mostrato nella terza istruzione appena presentata
Altro avviso importantissimo:
Per evitare malfunzionamenti o menù mutilati nei successivi riavvii di Excel occorre ricordarsi di porre a True le proprietà Enabled delle voci disabilitate con Enabled = False prima di uscire dall'applicazione.
Il modo migliore per rimettere tutto a posto è quello di ripristinare le modifiche apportate alle barre nel modulo ThisWorkbook usando uno degli eventi di chiusura (Workbook_Deactivate).
Conclusioni
Anche questo che ho appena presentato è solo un piccolo contributo a farci crescere nella cognizione del VBA. Io sono sinceramente convinto che non possiamo mai pensare di essere arrivati. Per ogni cosa che apprendiamo ce n'è sempre qualche altra che dobbiamo apprendere.
Buon lavoro
prelevato sul sito www.ennius.altervista.org