Introduzione alle API Win32

Capitolo 7: rispondere ai messaggi

Abbiamo accennato al fatto che un controllo static, se fra i suoi bit di stile ha SS_NOTIFY, ci "notifica" (cioè, "ci avverte") se e quando l'utente fa clic con il mouse su di esso.

Più precisamente, quello che succede in questo caso è che lo static (per intenderci -- il codice eseguibile associato alla finestra di classe "static", codice che il sistema ci fornisce) spedisce al dialogo che lo contiene un messaggio WM_COMMAND.

Più in generale, WM_COMMAND viene spedito ad un dialogo a fronte di vari possibili eventi, che, per modo di dire, possiamo considerare eventi "di comando", tipo le selezioni su di un menu, e varie azioni dell'utente su controlli contenuti nel dialogo.

Nei due argomenti, wParam ed lParam, che accompagnano il messaggio WM_COMMAND, sono contenuti tre elementi di informazione.

Questo "impacchettamento" è uno schema che ritroviamo abbastanza spesso in Windows; qui, in particolare, è basato sul fatto di considerare i 32 bit di wParam come composti da due parole di 16 bit l'una. Le macro HIWORD e LOWORD possono essere applicate a qualsiasi "longword" ("parola lunga"), che è di 32 bit, per ottenere le due "parole" ("word", di 16 bit l'una) che la compongono.

Per WM_COMMAND, in particolare:

HIWORD(wParam)
"codice di notifica"
LOWORD(wParam)
"identificatore"
lParam
HWND del controllo

L'identificatore ID è il numero che abbiamo associato al controllo nel file .RC (il nostro solo e unico STATIC, ad esempio, era stato creato con id 101); lParam (su cui sarà necessario un cast, (HWND)lParam, per usarlo) ci informa della "window handle" con la quale possiamo "rispondere" al controllo che ci sta notificando.

Il "codice di notifica" identifica quale evento, esattamente, sia successo. Ad esempio, per il clic su di uno STATIC, il codice di notifica (cioè la parola alta di wParam) vale STN_CLICKED (che e' naturalmente una macro definita negli header file di Windows).

Una volta avvertito dell'evento, il nostro codice è padrone di rispondere ad esso nel modo più opportuno, a seconda della nostra applicazione.

Per esempio, possiamo rispondere al clic dell'utente sul nostro STATIC, cambiando il testo dello STATIC stesso.

Per cambiare il testo di una finestra, si può spedire alla finestra stessa il messaggio WM_SETTEXT, con 0 in wParam, e, in lParam, l'indirizzo della stringa (terminata da 0) che si vuole impostare. Viceversa, per chiedere a una finestra quale sia il suo attuale testo, si può spedirle WM_GETTEXT, con, in lParam, l'indirizzo iniziale di un nostro buffer di caratteri, e, in wParam, la lunghezza di questo buffer.

Per spedire messaggi a una finestra, possiamo usare l'API SendMessage: il suo primo argomento e' l'HWND della finestra, il secondo il codice del messaggio, il terzo wParam, il quarto lParam. La SendMessage ci ritorna, come risultato (di tipo LRESULT), la "risposta" della finestra a questo messaggio.

Supponiamo, dunque, che il nostro scopo sia di commutare il messaggio dello static, alternativamente, fra "Ciao!" e "Salve", quando ci arriva la notifica del clic dell'utente sul controllo. Possiamo farlo, nel modo più semplice (cioè, senza salvarci un bit di "stato" che ci dica a quale messaggio tocca!), come segue:

(Notiamo, come considerazione generale, che è di solito meglio, quando sia possibile, evitare di duplicare informazioni, come si farebbe qui tenendo un "bit di stato" per codificare la stessa informazione che già possiamo recuperare chiedendo e riesaminando il testo attuale della finestra del controllo; la "ottimizzazione" consistente nel mantenere dello "stato" ridondante per evitare di "ricalcolarlo", così come tutte le ottimizzazioni, va applicata con la massima parsimonia e solo a fronte di necessità effettivamente controllate e verificate).

Dovremo dunque fare due piccoli cambiamenti; uno al nostro file .RC, cambiando l'istruzione STATIC in:

CONTROL "Ciao!", 101, "STATIC", SS_CENTER|WS_BORDER|SS_NOTIFY, 60, 40, 40, 10 e uno al nostro file sorgente, cambiando la dialog procedure in: BOOL CALLBACK unaDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg==WM_CLOSE) { EndDialog(hwndDlg, 0); return TRUE; } else if(uMsg==WM_COMMAND) { WORD wNotifica = HIWORD(wParam); WORD wId = LOWORD(wParam); if(wNotifica == STN_CLICKED && wId == 101) { HWND hStat = (HWND)lParam; char buff[6]; const char* pTesto; SendMessage(hStat, WM_GETTEXT, 6, (LPARAM)buff); if(buff[0]=='C') pTesto = "Salve"; else pTesto = "Ciao!"; SendMessage(hStat, WM_SETTEXT, 0, (LPARAM)pTesto); return TRUE; } } return FALSE; }

Esaminando questo piccolo programma, e riflettendo su di esso, vengono in mente parecchie considerazioni importanti; troppo importanti, però, per "comprimerle" nella coda di questo capitolo -- le rimanderemo a un capitolo successivo. Per ora, invece, ci lasciamo con un primo, piccolo esercizio: cambiare le risorse, ed il programma, in modo che nello static sia sempre mostrato il numero di volte che l'utente ha cliccato su di esso -- in altri termini, un contatore di clic.


Capitolo 6: controlli: gli STATIC
Capitolo 8: identificare le risorse
Elenco dei capitoli