Sviluppo

Come faccio? - parte XII

Gianni Ceccarelli
 

stesura originale in inglese di Eric Slaats - liberamente tradotto da Gianni Ceccarelli
comparso per la prima volta su Os/2 e-Zine! volume 2 numero 10

Bentornati. Il mese scorso abbiamo discusso un po' di teoria. Penso acnora che sia sempre necessario, ma anche la conoscenza pratica è importante. Pericò torniamo alla filosofia che abbiamo stabilito per questi articoli. La prima parte diceva "tenetelo semplice". La seconda era "siate pigri", ovvero non fate ciò che il sistema può fare per voi. Questo mese torneremo a parlare dei dialog, prenderemo in considerazione alcuni semplici costrutti e saremo molto pigri!

Finora abbiamo sempre creato delle frame window per construire le nostre applicazioni. Questo significa che abbiamo dovuto chiamare tutta una serie di funzioni iniziali per far funzionare il tutto. Questo è un elenco di ciò che, in molti casi, deve essere fatto:

  1. WinInitialize
  2. WinCreateMsgQueue
  3. WinRegisterClass
  4. WinCreateStdWindow
  5. while (WinGetMsg (hab, &qmsg, 0, 0, 0)) WinDispatchMsg (hab, &qmsg);
  6. WinDestroyWindow (hwndFrame);
  7. WinDestroyMsgQueue (hmq);
  8. WinTerminate (hab);

Il codice tra le linee serve solo per la creazione della finestra. E, credetemi, questo è un caso semplice! In applicazioni più grandi, devono essere create finestre per la client area, la linea di stato, le toolbar, ecc. Questo porta una grande flessibilità, ma può anche diventare piuttosto complicato.

Ad ogni modo, si possono immaginare molte applicazioni per le quali non è necessario creare una frame window. Un dialog potrebbe essere sufficiente. Il grande vantaggio è che possiamo crearlo con un editor di dialog! Questo metodo porterà vantaggi soprattuto nelle applicazioni con molti controlli nella client area. Ed esempio, SmeHtm (Smalled Html extensions) è stato creato quasi completamente in questo modo (usando un dialog editor).

Lo svantaggio di questo metodo è che non è facile applicare menu, barre di scorrimento, icone, ecc. usando i flag FCF_. Comunque, ci sono metodi per aggirare queste limitazioni. Questo mese vedremo un'applicazione che avrà un dialog come finestra principale, e aggiungeremo un menu per renderla più completa.

Un programma molto semplice

Andiamo con ordine. Prima di addentrarci nelle difficoltà di applicare menu ad un dialog, vediamo prima come usare un dialog come finestra principale. Negli articoli precedenti abbiamo visto che un dialog può essere aperto chiamando WinDlgBox. Con questa chiamata non dovremo preoccuparci di code o distribuzione dei messaggi. Il codice seguente funzionerà per qualsiasi dialog che abbia DIALOGID come identificatore!

void main(void)
    {
    HAB hab = WinInitialize(0);
    HMQ hmq = WinCreateMsgQueue(hab,0);

    WinDlgBox(HWND_DESKTOP,
            HWND_DESKTOP,
            WinDefDlgProc,
            NULLHANDLE,
            DIALOGID,
            0);

    WinDestroyMsgQueue(hmq);
    WinTerminate(hab);
    }

Con questo programma potrete eseguire qualsiasi dialog sul desktop. (Provate.) Le funzionalità di base possono essere controllate molto facilmente. Ovviamente il dialog non farà gran che, perchè usiamo WinDefDlgProc, ma funziona! Questo significa per semplici applicazioni (anche con bordo ridimensionabile), possiamo semplificare di molto i nostri programmi. Bello, eh?

Ora, per aggiungere le varie funzionalità in modo "normale" dobbiamo usare qualche trucco. In una frame window possiamo gestire le cose con i flag FCF_. Molte di queste cose possono essere impostate sui dialog con i dialog styles, che possono essere applicati facilmente con l'editor. (Non ci addentreremo nella creazione dei dialog adesso. Questo genere di cose verranno trattate un'altra volta.) Ci sono però due aspetti importanti che non possono essere gestiti dai dialog editor: i menu e l'icona dell'applicazione. Ce ne occuperemo tra un minuto. Ma prima:

Tocca a noi tutta l'inizializzazione?

Qual'è il momento migliore per applicare un menu o l'icona? Nel caso della frame window questo non era un problema, visto che OS/2 se ne occupava automaticamente durante l'inizializzaione della finestra. Con un dialog, è diverso. Ovviamente potremmo fare il tutto dopo che il dialog è stato creato, nella parte principale del programma. Personalmente, però, non lo trovo un metodo molto elegante. Vorremmo simulare quello che accade nel caso delle frame window: gestire tutto durante la creazione della finestra.

Ora, ogni finestra che viene creata riceve un messaggio per notificarle che è stata creata. Per le frame window, si tratta del messaggio WM_CREATE: in risposta a questo messaggio possiamo gestire tutte le inizializzazioni aggiuntive. Se però provate a gestire il messaggio WM_CREATE per un dialog, vedrete che non funziona! Così come i dialog hanno una loro window procedure dedicata, hanno anche uno specifico messaggio "creazione dialog". Si tratta del messaggio WM_INITDLG. Perciò si agganceremo a questo messaggio per applicare il menu e l'icona.

Aggiungere un'icona

Viviamo in un'era visuale. E se non mi sbaglio, le cose potranno solo peggiorare! Perciò aggiungere un'icona alla vostra applicazione è il minimo che possiate fare. Abbiamo visto che per una frame window questo è molto semplice; definite un'icona tra le risorse con il giusto ID e aggiungete il flag FCF_ICON quando create la finestra. Ovviamente è ancora necessario creare il file di risorse. Fatto questo, dobbiamo cominciare a cercare un modo per attaccare l'icona alla finestra. Ora questa è già una cosa difficile di per sé! Mi accorgo spesso che quando voglio provare qualcosa di nuovo, non so proprio dove guardare. Devo usare una funzione, quella funzione è in effetti una macro che invia un mesaggio, o è meglio inviare direttamente il messaggio? Ho scoperto che in molti casi se volete fare qualcosa ad una finestra (o qualsiasi controllo, in effetti), è di solito una buona idea esaminare i vari messaggi. E, infatti, c'è un messaggio per applicare un'icona ad una finestra; è il messaggio WM_SETICON.

NOTA: ho impiegato un sacco di tempo per trovare questo messaggio nella documentazione! Se cercate sotto "messages", vedrete che non è nell'indice. E cercare WM_SETICON non dà i risultati voluti! La cosa strana è che WM_SETICON appare cercando "icon".

Il messaggio WM_SETICON accetta solo un parametro: mp1 deve essere l'handle di un'icona. Di nuovo, come si ottiene l'handle di un'icona? Sì, ricominciamo a cercare nella documentazione, solo per incontrare un'altra sorpresa. Se volete caricare un'icona, dovete usare una funzione che carica un puntatore. Un puntatore è essenzialmente un'icona con un "hot spot". Inoltre, sia le icone sia i puntatori hanno aree trasparenti. Beh, sapendo questo, possiamo individuare la funzione giusta: WinLoadPointer. Questa funzione ritorna un valore di tipo HPOINTER.

HWND       hwndDeskTop // Handle alla finestra del desktop.
HMODULE Resource        // Handle al modulo contente la risorsa.
ULONG       idPointer   // Indentificatore del puntatore da caricare
HPOINTER    hptr        // valore di ritorno

hptr = WinLoadPointer(hwndDeskTop,  Resource,  idPointer);

Il primo parametro della funzione è semplicemente un default di OS/2: HWND_DESKTOP contiene sempre l'handle del desktop. Anche il valore Resource è semplice: è come nei precedenti esempi sulle frame window, le risorse sono incluse nel file .EXE. Perciò non dobbiamo complicarci la vita caricando moduli, e possiamo usare NULLHANDLE. Poiché sappiamo l'ID dell'icona, possiamo finalmente scrivere il codice per fare quello che ci serve e piazzarlo nella window procedure del dialog.

HPOINTER hptr = (HPOINTER)WinLoadPointer(HWND_DESKTOP, NULLHANDLE, 1);
WinSendMsg(hwndDlg, WM_SETICON, (MPARAM) hptr, 0l);

Aggiungere il menu

Per l'esempio di questo mese (ZIP, 17.7k) ho usato un menu preso da un esempio precedente, perciò non stupitevi se il menu è un po' strano. La funzione per caricare un menu è WinLoadMenu.

HWND       hwndFrame   // Handle della finestra
HMODULE hmod            // Handle del modulo contente le risorse
ULONG       idMenu      // Identificatore del menu

WinLoadMenu(hwndFrame, hmod, idMenu);

Non dovremmo farci distrarre dal fatto che questa funzione nomina una frame window. Non fateci caso, e usate l'handle del dialog. Per quanto riguarda HMODULE, è come per l'icona: la risorsa è inclusa nell'eseguibile, quindi useremo NULLHANDLE. L'identificatore del menu è noto. Tutto questo ci porta al codice seguente:

WinLoadMenu(hwndDlg, NULLHANDLE, MAIN);

Se proviamo, non funziona (strano, eh?), ma perché? Una frame window, come anche un dialog, è composta di varie finestre. C'è la client area, la barra del titolo, i pulsanti, il menu di sistema, ecc. Una volta creata, la finestra le tiene tutte in un certo ordine (ne riparleremo in un futuro articolo). Tutto quello che abbiamo fatto è stato caricare un menu, ma non abbiamo detto alla frame window (dialog nel nostro caso) di aggiungerlo ai controlli di frame. Possiamo informare la finestra di ciò usando il messaggio WM_UPDATEFRAME. In questo messaggio dobbiamo passare il flag FCF_ che identifica il controllo di frame da aggiungere (o rimuovere). La window procedure aggiornerà la finestra di conseguenza, e quindi mostrerà il menu. Tutto questo porta al codice seguente per WM_INITDLG:

WinLoadMenu(hwndDlg, NULLHANDLE, MAIN);
WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM) FCF_MENU, 0l);

Per mostrare che funziona ho aggiunto un po' di codice per il messaggio WM_COMMAND. Ogni volta che viene selezionata un'azione dal menu, il messaggio WM_COMMAND inviato all'applicazione produrrà un beep.

Bene, basta per questo mese. Il mese prossimo ci addentreremo nelle possibilità dei dialog.


[Pagina precedente] [Sommario] [Pagina successiva]