Introduzione alle API Win32

Capitolo 26: interazioni con gli EDIT

I controlli di Edit possono spedire vari messaggi di notifica (tramite la solita WM_COMMAND) al dialogo che li contiene.

Ogni volta che l'utente modifica il testo dell'edit control, il controllo anzitutto spedisce alla finestra-genitrice un WM_COMMAND con codice di notifica EN_UPDATE; come al solito, LOWORD(wParam) contiene l'ID, e lParam la handle, del controllo di edit. In risposta a questa notifica, il dialogo può, ad esempio, apportare delle modifiche al testo contenuto nel controllo; dopo di che, il controllo spedisce al dialogo una ulteriore notifica, EN_CHANGE, dopo avere mostrato il nuovo testo.

Se il controllo ha barre di scroll, orizzontale e/o verticale, e l'utente usa una di esse, allora il controllo, subito prima di mostrare il nuovo testo, notifica il dialogo con EN_HSCROLL e EN_VSCROLL rispettivamente.

Quando il controllo ottiene il focus (tipicamente perchè l'utente ci ha cliccato su, ma potrebbe esserci anche arrivato in altro modo, come, ad esempio, con un tab), la notifica è EN_SETFOCUS; quando il controllo perde il focus, è invece EN_KILLFOCUS (quest'ultima occasione è un buon momento per "validare" il testo che l'utente ha posto nell'edit, se esso deve rispettare un qualche vincolo sintattico o semantico -- attenti, però, che un Enter, salvo che l'edit non abbia stile ES_WANTRETURN, può causare "il clic del bottone di default" senza aver prodotto EN_KILLFOCUS!).

EN_MAXTEXT è la notifica "il testo ha raggiunto il massimo ammesso"; può essere gestita, in alternativa al settaggio del bit di stile ES_AUTOHSCROLL ecc, per eseguire "scrolling" secondo modalità particolari sotto il totale controllo del programma.

 

Parecchi sono pure i messaggi che possono essere spediti al controllo di edit, per ottenere da esso delle informazioni, o modificarne le operazioni.

WM_UNDO, ad esempio, è la richiesta di "disfare" l'ultima modifica apportata al testo (si può prima spedire EM_CANUNDO, che ritornerà 0 se l'undo non è possibile in questo stato). WM_COPY, WM_PASTE, e WM_CUT, operano sulla clipboard ("appunti") nel modo prevedibile -- in particolare, la "zona" del testo del controllo su cui essi hanno effetto è la "selezione corrente", che è anche quella parte del testo del controllo che viene mostrata all'utente con "highlight".

La selezione corrente può anche essere cancellata, senza effetto sulla clipboard, spedendo all'edit un WM_CLEAR. Il messaggio EM_SETSEL permette di impostare la "selezione corrente": start è in wParam, end in lParam, e inoltre: start=0, end=-1, per fare la selezione di tutto il testo presente; start=-1, per fare una selezione vuota; il "caret" (il cursore tipico dei testi) è posto al più grande fra i due valori start ed end.

Per chiedere quale sia la selezione corrente, EM_GETSEL, con wParam posto all'indirizzo di una DWORD di "inizio", lParam a quello di una DWORD di "fine" (per entrambi è accettabile il valore 0, se quel dato non interessa); come per EM_SETSEL, gli indici partono da 0, e la end è l'indice del primo carattere non selezionato, dopo la selezione corrente.

EM_REPLACESEL cambia il testo della selezione corrente, con una stringa (terminata da 0 binario, come al solito) il cui indirizzo iniziale è lParam; wParam, se diverso da zero, dice al controllo di tenere memorizzato il testo precedente al fine di permettere un eventuale undo.

Ci sono più di altre due dozzine di codici di messaggio EM_xxx, che permettono operazioni assai precise e dettagliate; non sarebbe però appropriato, entro i limiti di un tutorial, entrare nei dettagli di tutte queste operazioni.

Dovendo scrivere un editor, o implementare operazioni molto particolari, sarà certo il caso di ripassarsi tutti i dettagli e le possibilità in un opportuno testo di riferimento (come, ad esempio, la documentazione in linea dell'SDK, disponibile gratuitamente per consultazione e download dal sito Microsoft, purtroppo solo in inglese). Si vedono, a volte, esempi di subclassing portati su controlli di edit, che sembrano ignorare totalmente le enormi potenzialità dei controlli stessi già nel loro stato-base (per non dire dei controlli di Rich Edit, che sono un vasto sovrainsieme di quelli di Edit, aggiungendo varie altre funzioni oltre a quelle di poter mantenere molteplici font e colori, e testo anche al di là dei 64k che normalmente limitano un controllo di Edit).

Fra le cose di una certa importanza generale, notiamo, tuttavia, il messaggio EM_SETREADONLY, con lParam=0 e wParam pari a TRUE perchè l'edit divenga readonly, a FALSE per farlo invece divenire read-write; questo ci risparmia, nel caso assai comune che si voglia cambiare dinamicamente questo bit di stato, la necessità di usare la nostra funzione ricreaWindow (visto che, come abbiamo visto, il bit di stile settato con SetWindowLong non ha, di per sè, alcun effetto).

È inoltre il caso di tenere presenti le API SetDlgItemInt e GetDlgItemInt, che si sposano particolarmente bene con lo stile ES_NUMBER per un controllo di edit: esse, infatti, rendono più comodo il comune compito di comunicare (scrivere, o leggere) il testo di un tale controllo visto come codifica decimale di un numero intero. Non ci sono, purtroppo, equivalenti per altre basi, come l'esadecimale; ove occorra, ciò va invece ottenuto attraverso "subclassing".

 

Gli usi che vengono subito in mente per un dialogo dotato di controlli di edit sono, naturalmente, dei più vari, ma un buon esempio (che, come è in effetti tipico delle applicazioni, enfatizza, non il controllo di edit in quanto tale, ma l'uso che si fa del testo così immesso dall'utente) può essere uno sul quale si sentono spesso fare domande sui newsgroup: "come posso fare il grafico di una funzione immessa dall'utente"?

Il problema si scompone agevolmente in varie parti:

  1. come può l'utente "immettere una funzione"? Dotando il dialogo della nostra applicazione di un controllo di edit, risolveremo agevolmente questa parte del problema.
  2. come possiamo valutare la funzione nei vari punti necessari per delineare un grafico? È questa una questione cui è meno agevole dare immediata risposta, ma vedremo come impostare anche questa parte -- sia in un modo che non ha nulla a che vedere con le funzionalità che ci offre Windows, sia in un altro che invece sfrutta appieno le più ricche ed avanzate funzionalità che le versioni recenti di Windows ci mettono a disposizione.
  3. dati 1 e 2, come possiamo disegnare il grafico così delineato? Nel rispondere a questa parte, avremo finalmente modo di iniziare a vedere i primi rudimenti della parte "grafica" vera e propria delle API di Windows.

Capitolo 25: ri-creare una finestra
Capitolo 27: l'interprete: l'interfaccia
Elenco dei capitoli