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
#include
#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