Salve e benvenuti a "Come faccio?". In questa serie discuteremo semplici problemi riguardanti la programmazione e la filosofia del Presentation Manager (PM). "Come faccio?" è rivolto a chi è interessato alla programmazione in PM o più semplicemente a coloro che sono curiosi di conoscere come girano gli stessi programmi in PM. Per ben comprendere l'argomento trattato è raccomandata una piccola esperienza nella programmazione (preferibilmente in C++).
Questo mese daremo uno sguardo alle basi di ogni programma Presentation Manager. In altre parole: come posso creare una finestra?
Quello che mi mancava erano semplicemente i significati di tutto ciò e come il tutto potesse interagire. Dunque questo è una panoramica (spero illuminante) su come far girare un programma Presentation Manager.
La GUI è modellata sul paradigma degli eventi e i programmi PM lavorano grazie agli eventi. Questo significa che se vogliamo imparare a programmare in PM dobbiamo conoscere il paradigma degli eventi. Per esempio:
Come si intuisce facilmente, ogni azione che possiamo compiere sotto il PM causerà un evento. Quando questo avviene il sistema operativo manderà un messaggio al programma. Questo messaggio fornirà al programma stesso il modo con cui operare sull'evento generato. Così, invece di seguire uno schema sequenziale preciso, i programmi PM inviano, ricevono e rispondono a messaggi (eventi).
Il Presentation Manager è organizzato attorno al concetto di finestra. Ogni area su uno schermo OS/2 è considerata una finestra, tutti i controlli in OS/2 sono finestre. Così un bottone, una titlebar, un entryfield, un'icona della titlebar, etc. sono tutte finestre. Questo porta alla conclusione che ogni "normale" finestra delle applicazioni è strutturata da un ulteriore numero di finestre tutte diverse. Le finestre delle applicazioni sono il modo con cui l'utente e le applicazioni stesse interagiscono. Ogni evento causato dall'utente è un'azione portata su di una finestra.
Come fa il PM a sapere dove mandare un messaggio che è stato generato dal sistema? Per questo, ogni applicazione crea una coda dei messaggi; ogni messaggio generato dalla finestra di un programma PM è inviato a questa coda. Una coda messaggi è un posto dove gli stessi sono registrati finché non vengono elaborati (ci sono alcune differenze sottili, ma queste non fanno parte dello scopo di questo articolo).
Prima di discutere su come un programma PM gestisce i messaggi vediamo come essi sono fatti. I messaggi PM sono descritti dalla struttura della coda messaggi (QMSG):
typedef struct _QMSG { HWND hwnd; // Window handle the message is addressed to ULONG msg; // The message MPARAM mp1; // Message parameter 1 MPARAM mp2; // Message parameter 2 ULONG time; // Timestamp when the message occurred POINTL ptl; // Mouse position when the message occurred ULONG reserved; } QMSG;
I primi quattro elementi di questa struttura sono effettivamente quelli a cui noi ci interessiamo. Per le persone che non hanno mai programmato in PM questi elementi potrebbero sembrare inusuali e così li spiegheremo: quando si programma il Presentation Manager si usano molti tipi di dati diversi tra loro. Essi sono definiti negli header dei files che si ottengono col proprio compilatore. Nella struttura precedente alcuni di essi sono menzionati.
HWND hwnd: questo è chiamato window-handle (ed è attualmente un unsigned long). Esso contiene un numero a 32 bit che identifica in modo univoco la finestra sul tuo desktop. L'elemento hwnd nel messaggio identifica il ricevente del messaggio
ULONG msg: ULONG è, per OS/2, il tipo di dati unsigned long. Nella struttura precedente l'ULONG contiene un numero a 32 bit che costituisce il messaggio. Tutti i messaggi del PM sono attualmente dei numeri, ma noi li chiameremo col nome presente nel file header PMWIN.H. Molti dei nomi dei messaggi cominciano con WM_(Window Message). Alcuni esempi di messaggi così come sono definiti nel PMWIN.H sono:
WM_COMMAND // Un menu o un bottone sono stati cliccati WM_CHAR // è stato spinto un tasto della tastiera WM_MOUSEMOVE // Viene mosso il mouse WM_PAINT // Si ridisegna una finestra o una sua parte.
MPARAM mp: questo è sempre un ULONG. Un messaggio può usare i due parametri per registrare informazioni richieste per processare il messaggio stesso. Questi possono essere di tutti i tipi, l'identità della voce del menu che ha causato l'evento, o una parte di finestra che deve essere ridisegnata. Due soli ULONG possono sembrare limitanti se si vogliono passare molte informazioni, ma non è così. Il numero a 32-bit può essere un puntatore a una certa area di memoria del sistema. Così si può passare qualsiasi quantità di informazioni (basta passare il puntatore all'area di memoria).
Dopo che un programma ha creato la coda dei messaggi, può creare le finestre. Tutti i messaggi delle finestre create dalla trama dei programmi sono inviati alla specifica coda messaggi. Noi possiamo estrarre messaggi dalla coda stessa (seguendo il citerio FIFO) con una piccola parte di codice che presumibilmente tutti i programmi PM hanno. Questo è chiamato il MESSAGE LOOP. Nella sua forma più semplice questo Message Loop apparirà così:
QMSG qmsg; // Holds one message while (WinGetMsg (hab, &qmsg, NULLHANDLE, 0, 0) WinDispatchMsg (hab, &qmsg);
WinGetMsg è l'API da noi invocata quando vogliamo prelevare un messaggio dalla coda. Il messaggio prelevato dalla coda è posto nella variabile qmsg. Il loop continuerà fino a quando non verrà chiamata la WM_QUIT. Questo farà anche terminare l'applicazione. (WM_QUIT viene inserito nella coda messaggi quando dal menu sistema di una applicazione viene selezionato "chiudi"). Gli ultimi 3 parametri di WinGetMsg sono settati a zero.
La seconda linea del nostro piccolo pezzo di codice è quella dedicata all'invio del messaggio. La funzione WinDispatchMsg invierà il messaggio alla finestra appropriata. Quello che succede è che un pezzo di codice chiamato window-procedure gestisce il messaggio fino a destinazione. Prima di dare uno sguardo alla window-procedure dobbiamo sapere come essa è attaccata alla finestra. Per questo dobbiamo sapere come viene creata una finestra.
hwndFrame = WinCreateStdWindow (HWND_DESKTOP, // Parent (HWND) WS_VISIBLE, // Style (visible) (ULONG) &flFrameFlags, // Creation flags (PULONG) "SampleClass", // Class name (PSZ) "Titlebar Text", // Titlebar text (PSZ) 0, // Client style (ULONG) NULLHANDLE, // Resource handle (HMODULE) 0, // Frame ID (ULONG) &hwndClient); // Client handle (PHWND)
Nelle linee di commento , dopo ogni singolo parametro di questa API, sono spiegati brevemente i valori che la costituiscono come, ad esempio, il tipo di dato. Ancora, possiamo imbatterci in alcune tipologie di dati che non conosciamo. Qui, spiegheremo solo quelli necessari alla corretta comprensione del concetto; gli altri saranno trattati nei prossimi articoli.
HWND_DESKTOP. Il primo parametro è l'aggancio alla finestra "padre" della serie di finestre che noi abbiamo creato. La finestra "padre" è l'area di finestra dove la finestra stessa sarà disegnata. In molti casi questa sarà anche la finestra del desktop (in questo modo viene creato il Multiple Document Interface).
WS_VISIBLE. Ogni finestra può essere "confezionata" su un certo stile; di questo ci occuperemo in futuro. Per ora ci dobbiamo solo preoccupare di rendere visibile questa finestra.
&flFrameFlags. È un puntatore ULONG che contiene informazioni su come questa finestra deve essere creata. Con questa variabile si può fare molto! Ogni bit in questo ULONG ha un significato preciso. Per esempio il primo bit significa "Aggiungi una titlebar alla finestra". Nel file PMWIN.H è definito un certo numero di identificatori. Collegando insieme i bit si ottiene da questo ULONG una serie di combinazioni. In questo modo il PM conosce come costruire l'intelaiatura della finestra. Il nostro piccolo programma usa la seguente struttura del &flFrameFlags per creare finestre:
ULONG flFrameFlags = FCF_TITLEBAR |FCF_SYSMENU |FCF_SHELLPOSITION | FCF_SIZEBORDER |FCF_MINMAX |FCF_TASKLIST;
pszClient. Questa è una stringa che contiene il nome della CLASSE della finestra; è necessaria per attaccare una window-procedure alla finestra. I parametri successivi sono settati a 0. Non faremo nulla con questi al momento. In articoli futuri tratteremo in modo più profondo questi parametri e ne parleremo in modo esaustivo.
&hwndClient. Se la chiamata WinCreateStdWindow è completata, l'hwndClient contiene l'aggancio alla finestra client. Questa area è contenuta nella intelaiatura della finestra. Molto semplicemente questa è l'area dove vengono visualizzate le applicazioni. Per esempio se l'applicazione è un editor, il display ed il testo saranno proposti all'interno di una finestra client.
Tutte le finestre sono basate su una certa window class. È la classe della finestra che definisce le window-procedures. Per esempio un bottone è una finestra per la classe WC_BUTTON. Dentro OS/2 ci sono molte window-procedures di default presenti in ogni tipo (classe) di finestra che OS/2 supporta.
Se scrivi un'applicazione, è preferibile gestire tutti gli eventi che l'applicazione stessa genera. Per esempio, la tua applicazione avrà probabilmente un menu. Tutte le volte che una voce del menu è attivata un messaggio sarà inviato alla window-procedure della finestra principale della tua applicazione. Ma ovviamente il PM non può prevedere cosa farà il tuo programma. Questo significa che devi crearti la tua propria window-procedure e dire al PM dove si trova. Questo si ottiene registrando la tua finestra. La linea seguente del programma di esempio registrerà la nostra classe.
WinRegisterClass(hab, "SampleClass", ClientWndProc, CS_SIZEREDRAW, 0);
I parametri più importanti sono il secondo e il terzo. Il secondo da il nome della classe. Notare che abbiamo usato questo nome nella WinCreateStdWindow. (Normalmente una variabile separata o un define sono usati per settare il nome. Questo rende l'opera di mantenimento e lo stile di programmazione migliori). Il terzo parametro è il puntatore alla funzione window procedure. Questo significa che il nostro programma deve avere una window-procedure chiamata ClientWndProc.
La window-pocedure da sola assomiglia a una grossa dichiarazione che cattura e gestisce tutti i messaggi che vogliamo agganciare. Normalmente essa chiamerà la default window procedure per normali finestre all'interno del kernel di OS/2.
Prossimamente daremo uno sguardo approfondito alle window-procedures. Per adesso ci limitiamo a presentarle. Nel nostro programma di esempio la window procedure apparirà cosi:
//---------------------------------------------------------------- //Window procedure //---------------------------------------------------------------- MRESULT EXPENTRY ClientWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) { switch (msg) { //-------------------------------------------------------------------- // Fill client with default color //-------------------------------------------------------------------- case WM_ERASEBACKGROUND: return MRFROMSHORT(TRUE); } return (WinDefWindowProc (hwnd,msg,mp1,mp2)); }
//-------------------------------------------------------------------- // Initialize application and create message queue //--------------------------------------------------------------------- hab = WinInitialize (0); // Init application hmq = WinCreateMsgQueue (hab, 0); // Create message queue
Quando termina il message-loop (WM_QUIT), si deve fare un po' di pulizia. Questo significa distruggere la finestra, distruggere la coda dei messaggi e indicare al PM che l'HAB non è più valido. Il seguente frammento di codice si occupa della cosa:
//------------------------------------------------------------------- // Clean up (destroy window, queue and hab) //------------------------------------------------------------------- WinDestroyWindow (hwndFrame); WinDestroyMsgQueue (hmq); WinTerminate (hab);
Cliccate quì (ZIP, 12.8K) per prelevare l'intero codice sorgente per il programma e il risultante .EXE che mostra una normale finestra con una titlebar, max/min botton, icone per la title-bar, e il bordo ridimensionabile. Tutti questi componenti sono attivi e questo significa che la finestra puo' essere spostata, massimizzata, minimizzata e dimensionata. Noterete che l'area client non accetta il drop di un colore, una new size, non ricorderà l'ultima posizione etc. Molto lavoro resta ancora per creare una applicazione completa.
Il prossimo mese continueremo con questo esempio e completeremo il codice per creare un programma template che sarà usato come base futura. Questo mese abbiamo concentrato l'attenzione sulla finestra principale; nel prossimo esploreremo la window-procedure e alcuni piccoli messaggi.
- [ Pagina precedente ] - - [ Sommario ] - - [ Just WARP! homepage ] - - [ Pagina successiva ] - |