Introduzione alle API Win32

Capitolo 21: l'esempio rivisitato (2)

Finalmente, dunque, "armati" dei vari elementi di codice riusabile che abbiamo via via sviluppato e "impacchettato" nei capitoli precedenti, possiamo ormai venire al codice specifico della nostra applicazione di esempio. (Se ne potrebbe ancora estrarre qualche brano riusabile, ma a un qualche punto bisogna pur smettere...!):

// esemdlg.c #define STRICT #define WIN32_LEAN_AND_MEAN #define OEMRESOURCE #include <windows.h> #include <windowsx.h> #include "resource.h" #include "esemdlg.h" #include "dlgclose.h" #include "ctlimmag.h" #include "windmove.h" #include "aggnot.h" // // inizializzazione del dialogo: subclassing dei bottoni e // definizione delle immagini di bottoni e static // BOOL OnDlgInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) { // garantisce che i bottoni spediscano notifica (via WM_COMMAND) // di PUSHED e UNPUSHED alla pressione/rilascio del tasto sinistro // del mouse su di essi static long add_push_unpush[] = { WM_LBUTTONDOWN, BN_PUSHED, WM_LBUTTONUP, BN_UNPUSHED, 0 }; Aggiungi_Notifiche(hwnd, IDC_BUTTON1, add_push_unpush); Aggiungi_Notifiche(hwnd, IDC_BUTTON2, add_push_unpush); Aggiungi_Notifiche(hwnd, IDC_BUTTON3, add_push_unpush); Aggiungi_Notifiche(hwnd, IDC_BUTTON4, add_push_unpush); // mette le opportune immagini a bottoni e static Mostra_BM_bottone(OBM_LFARROW, hwnd, IDC_BUTTON1); Mostra_BM_bottone(OBM_RGARROW, hwnd, IDC_BUTTON2); Mostra_BM_bottone(OBM_UPARROW, hwnd, IDC_BUTTON3); Mostra_BM_bottone(OBM_DNARROW, hwnd, IDC_BUTTON4); Mostra_Icona_static(IDI_HAND, hwnd, IDC_STICON); return TRUE; } // dichiarazione "forward" della procedura-timer, gestore di // periodiche "callback" da parte di Windows quando un // timer viene istallato VOID CALLBACK ProceduraTimer(HWND hwnd, // finestra associata UINT uMsg, // sempre il codice WM_TIMER UINT idEvent, // identificatore del timer DWORD dwTime // "istante attuale" ("tempo di sistema") ); // // risposta ai comandi (si sposta l'icona se un bottone viene // cliccato; si gestisce il timer a fronte di ogni pressione // e rilascio di un bottone). // void OnDlgCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { if(codeNotify == BN_PUSHED) { // richiede 5 chiamate al secondo della procedure di timer // per simulare i clic se un bottone e` tenuto premuto // da notare: l'id del controllo e` usato come id del timer SetTimer(hwnd, id, 200, ProceduraTimer); } else if(codeNotify == BN_UNPUSHED) { // fa cessare la callback periodica di timer KillTimer(hwnd, id); } const int dp = 5; // numero pixel di spostamento per ogni clic // gestiamo solo comandi di clic-su-bottone: if(codeNotify != BN_CLICKED) return; LPRECT pRectLimit = 0; // default: niente limiti RECT rectLimit; HWND hStatic = GetDlgItem(hwnd, IDC_STICON); if(SendDlgItemMessage(hwnd, IDC_LIMITS, BM_GETCHECK, 0, 0)==BST_CHECKED) { // sono richiesti i limiti allo spostamento, dunque // scopriamo entro quale rettangolo e` limitato // (usiamo l'intera area-client del dialogo): GetClientRect(hwnd, &rectLimit); pRectLimit = &rectLimit; } switch(id) { // i bottoni con freccia richiedono spostamento case IDC_BUTTON1: WindMove(hStatic,-dp,0,pRectLimit); break; // sinistra case IDC_BUTTON2: WindMove(hStatic,+dp,0,pRectLimit); break; // destra case IDC_BUTTON3: WindMove(hStatic,0,-dp,pRectLimit); break; // alto case IDC_BUTTON4: WindMove(hStatic,0,+dp,pRectLimit); break; // basso // "spostamento di zero" per garantire, se richiesto, che l'icona // rientri nei limiti del rettangolo case IDC_LIMITS: WindMove(hStatic,0,0,pRectLimit); break; // entro-i-limiti } } // // la procedura di timer: simula clic sul bottone il cui ID e` lo stesso // del timer // VOID CALLBACK ProceduraTimer(HWND hwnd, // finestra associata UINT uMsg, // sempre il codice WM_TIMER UINT idEvent, // identificatore del timer DWORD dwTime // "istante attuale" ("tempo di sistema") ) { HWND hwndBottone = GetDlgItem(hwnd, idEvent); OnDlgCommand(hwnd, idEvent, hwndBottone, BN_CLICKED); } // // La dialog procedure: usa i crackers di windowsx.h, e quindi delega // alle procedure teste` viste l'effettiva gestione dei messaggi // BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { HANDLE_MSG(hwndDlg,WM_CLOSE,OnDlgClose); HANDLE_MSG(hwndDlg,WM_INITDIALOG,OnDlgInitDialog); HANDLE_MSG(hwndDlg,WM_COMMAND,OnDlgCommand); } return FALSE; }

...e così, ci siamo! Raccomando al lettore di prepararsi i vari file di sorgente ed header visti in questo capitolo e nei due precedenti, costruire la piccola applicazione risultante, provarla, e, magari, "azzardarsi" a tentare qualche piccola modifica al suo esatto comportamento -- per esempio, non sarebbe male che, quando è richiesto il "movimento limitato", all'icona fosse impedito di sovrapporsi ai vari bottoni; come si potrebbe ottenere questo...?

Per vostra comodità, ho anche raccolto tutti i file sorgenti e header in questione nell'archivio esem1.zip, che contiene anche il file esem1.mf, che dà un esempio di file di input per la utility nmake del Visual C++ della Microsoft (non dovrebbe esservi difficile "tradurlo" in un analogo file di input per il gmake della GNU, o altre simili utility che accompagnano i vari compilatori e ambienti di sviluppo; più che altro, dovrete tradurre i vari comandi cl diretti al compilatore Microsoft negli equivalenti comandi necessari per usare il vostro compilatore preferito). Se avete istallato l'ambiente di sviluppo VC++, vi basterà il comando nmake /f esem1.mf al prompt di comandi per comandare la costruzione dell'intero esempio.

 

Naturalmente, abbiamo appena cominciato la nostra carrellata introduttiva sul mondo delle API di Windows -- ci mancano ancora, se non altro, alcuni controlli elementari (le "edit box", le "list box", le "combo box") -- e poi, naturalmente, tutti quelli avanzati e cosiddetti "comuni"; per non dire dei controlli "disegnati dall'utente", dei quali ancora non abbiamo parlato; dei font -- per ora, non si è presa in esame la possibilità che diversi controlli possano usare font diversi fra loro; dei colori -- nulla si è detto di cosa possa fare un dialogo per usare colori non-standard... e questo, solo per dare un minimo di impostazione ai soli dialoghi modali, e ai controlli che tipicamente vi si trovano -- dopo di che, naturalmente, si dovrà parlare di come fare le "nostre" finestre, ecc, ecc...

Proprio per questa ragione di "mole", non ripeteremo ogni volta tutti i dettagli che abbiamo già presentato -- l'uso dei file di include, la strutturazione del programma in termini di funzioni riutilizzabili, eccetera; presenteremo, più che altro, "pezzetti" di programma, o funzioni utili, con notazioni su come e quando usarle, lasciando il lavoro di "ricucitura" di queste pezze in un opportuno "panno", al volonteroso e diligente lettore.


Capitolo 20: un subclassing migliore
Capitolo 22: controlli: gli EDIT
Elenco dei capitoli