Riprendiamo brevemente lultimo stralcio di funzione scritto
nella scorsa puntata:
void CMainFrame::OnModificaEliminahelp()
{
CMenu *pMenu= GetMenu();
pMenu->DeleteMenu(4, MF_BYPOSITION);
DrawMenuBar();
}
Tutte le operazioni effettuate con i menu a runtime, devono essere
effettuate tramite oggetti CMenu. Questi offrono molte funzioni
membro per le più disparate operazioni.
La prima operazione effettuata in OnModificaEliminahelp ,
GetMenu, serve per recuperare il puntatore alle voci di menu
di livello superiore.
Poi con DeleteMenu abbiamo eliminato esattamente la voce
di posizione 4; ricordo che la numerazione è in base 0, cioè la
prima voce è 0, la seconda è 1...
Per riferire i menu i metodi sono solo 2: o per posizione con MF_BYPOSITION
o per ID con MF_BYCOMMAND. E' evidente che il secondo metodo in
questo caso non sia possibile perché le voci di menu di livello
superiore non hanno un identificatore numerico.
Usando DeleteMenu abbiamo eliminato tutto il menu popup,
cioè la voce di menu di livello superiore e tutte le sottovoci.
Se avessimo voluto eliminare solo la voce di menu principale avremmo
dovuto usare RemoveMenu.
In questo caso avremmo potuto usare il menu popup rimasto in vita
per usarlo ad esempio come menu di contesto.
Nell'esempio precedente abbiamo poi infine chiamato DrawMenuBar
per ridisegnare le voci di menu, questo operazione deve essere sempre
effettuata quando la finestra è visibile sullo schermo; per curiosità
vedete cosa succede se la commentate provando poi a ricompilare.
Altra curiosità: dopo aver eliminato la voce, scambiate il menu
con l'altro creato e poi passate nuovamente al primo: vedrete che
la voce dell'Help ricompare, vi sapete spiegare perché?
La ragione non è molto complessa.
Infatti quando scambiate i menu quello che fate è ricaricare le
risorse linkate staticamente al codice, quindi tutte le successive
modifiche effettuate dinamicamente a runtime (a tempo di esecuzione)
vengono annullate. Il problema è ovviamente aggirabile creando un
membro di dati di tipo CMenu e caricandovi poi il menu da modificare;
successivamente dopo lo scambio verrà visualizzato questultimo
e non quello preso dalle risorse.
Vediamo ora come cancellare ad esempio la voce ProvaMenu
del menu Visualizza; a tale scopo in questo menu aggiungiamo
col Wizard una voce EliminaProvaMenu e la linkiamo al codice:
void CMainFrame::OnVisualizzaEliminaprovamenu()
{
CMenu *pMenu= GetMenu()->GetSubMenu(2);
pMenu->RemoveMenu(ID_VIEW_PROVAMENU, MF_BYCOMMAND);
DrawMenuBar();
}
In questo caso, come nel precedente, ci dovremmo assicurare che
la funzione non venga richiamata 2 volte.
Qui abbiamo usato anche GetSubMenu, questa funzione recupera
il puntatore al menu popup di indice specificato dal puntatore al
menu principale. Grazie a questa funzione è possibile recuperare
i puntatori di menu a cascata di qualsiasi profondità: basta mettere
una chiamata di funzione per ogni livello.
Ad esempio: GetMenu()->GetSubMenu(9)->GetSubMenu(0)->GetSubMenu(1)
restituisce il puntatore ad un oggetto CMenu posto al terzo
livello di profondità. Un esempio di menu con molti popup a diverse
profondità è il menu Start (Avvio) di Windows: questo contiene ad
esempio in cascata i popup Programmi -> Accessori
-> Comunicazioni.
Ritornando al codice sopra evidenziato, dopo aver recuperato il
puntatore al popup abbiamo rimosso la voce riferendola tramite il
suo identificatore e quindi abbiamo ridisegnato il menu.
Quando si opera dinamicamente con i menu è preferibile, ove possibile,
riferire le voci tramite il loro identificatore e non per posizione.
Infatti aggiungendo e rimuovendo voci, la loro posizione può cambiare
e si può rischiare di fare errori evitabili da subito usando funzioni
più appropriate.
E' anche possibile modificare una voce di menu: data la sua posizione
o il suo identificatore gli si può assegnare un nuovo identificatore
ed una nuova Caption.
Ad esempio se miomenu è un oggetto di tipo CMenu che punta
ad un menu popup, i seguenti enunciati operano su alcune sue voci:
miomenu.ModifyMenu (ID_VECCHIO,
MF_STRING | MF_BYCOMMAND, ID_NUOVO, "Nuovo Nome");
miomenu.ModifyMenu (POSIZIONE, MF_STRING | MF_BYPOSITION, ID_NUOVO,
"Nuovo Nome");
Il primo enunciato accede alla voce per ID, sostituisce questo con
quello nuovo specificato in ID_NUOVO e cambia il nome della voce
in Nuovo Nome; analogamente il secondo enunciato, ma accede
alla voce per posizione.
Se al posto di MF_STRING viene specificato MF_SEPARATOR, la vecchia
voce viene trasformate in un segno di separatore (la linea orizzontale),
ed i successivi parametri vengono ignorati.
Se inoltre invece di MF_STRING viene specificato MF_POPUP la voce
viene trasformata in un popup (appare la freccia verso destra ad
indicare un sottomenu) ed il parametro successivo invece di essere
l'ID della voce deve essere l'handle al nuovo menu popup.
In or al secondo parametro è possibile anche settare lo stato della
voce: MF_CHECKED, MF_DISABLED, MF_GRAYED... per vedere più in dettaglio
questa funzione, consultare l'MSDN.
Vi rimando nuovamente alla prossima puntata per continuare la trattazione
di questo interessantissimo argomento.
Torna all'indice Generale del corso di Corso di Visual C++ di Software Planet