Introduzione alle API Win32

Capitolo 43: messaggi ai LISTBOX (1)

Un controllo listbox può essere "popolato" dinamicamente (come nel programmino che abbiamo mostrato in precedenza per evidenziare la possibilità di usarlo per "output di debugging"), ma, spesso, potrà anche servire, invece, popolarlo "una volta per tutte", con dati non destinati a cambiare.

Purtroppo, non si possono specificare direttamente i contenuti iniziali nel file .RC; bisogna, invece, operare comunque "a runtime", cioe` durante l'esecuzione del nostro programma (spesso, all'inizializzazione, cioè rispondendo al messaggio WM_INITDIALOG), eseguendo opportune funzionalità di "riempimento" (normalmente, questo si otterrà spedendo messaggi opportuni al controllo listbox).

(Un modo decisamente anomalo di popolare una listbox è quello messo a disposizione dall'API DlgDirList, che riempie un controllo listbox con l'elenco dei file presenti in un certo folder (con varie opzioni). Non usatela! Al giorno d'oggi, gli utenti si aspettano, quando devono scegliere un file fra tanti, di vedere un'interfaccia utente più sofisticata di una semplice lista di nomi-file -- e hanno ragione, anche perchè non è affatto difficile fornire loro queste migliori interfacce, grazie ai "dialoghi comuni", di cui parleremo più avanti nel corso di questo tutorial. Quest'API è presente solo per compatibilità con un passato antichissimo, e la nomino solo per avvertirvi di non usarla.)

Il modo più normale di "popolare" un controllo listbox è quello di inviargli il messaggio LB_ADDSTRING, con lParam posto all'indirizzo della stringa (che viene accodata alle eventuali altre già presenti); si tratta di una "stringa" nel senso C del termine, cioè un array di caratteri terminato da uno 0 binario. Se il listbox è owner-drawn, e privo del bit di stile LBS_HASSTRING, esso risponde a questo messaggio semplicemente memorizzando l'lParam come dato associato al nuovo elemento.

Al messaggio LB_ADDSTRING, la listbox risponde dando come codice di ritorno l'indice (da 0 in sù) della posizione in lista del nuovo elemento (normalmente, come dicevamo, il nuovo elemento è posto in coda agli altri già presenti, ma questo non si applica se il listbox ha il bit di stile LBS_SORT).

Questo indice, ad esempio, si può usare come valore di wParam nell'inviare alla listbox un messaggio LB_SETITEMDATA, che farà sì che i 32 bit contenuti nell'lParam siano associati come "dati" dell'elemento stesso (similmente, inviare alla lista un messaggio LB_GETITEMDATA, sempre con l'indice di elemento in wParam, permetterà di recuperare, come valore di ritorno, il dato associato a un certo elemento).

(Se si intende aggiungere ad una lista un grande numero di elementi, una piccola ottimizzazione può essere quella di spedirle anzitutto un messaggio LB_INITSTORAGE, con, in wParam, il numero di elementi che si intende inserire, e, in lParam, il numero di byte di cui la lista avrà bisogno per conservare il loro testo; questa operazione non è necessaria, ma può accelerare sostanzialmente le cose.)

Se si vuole inserire un elemento ad una posizione particolare, si può usare il messaggio LB_INSERTSTRING al posto di LB_ADDSTRING; si dovrà allora passare l'indice desiderato (-1, per appendere il nuovo elemento in coda a quelli già presenti) come valore di wParam (questo blocca, ma solo temporaneamente, la funzionalità di ordinamento automatico di un listbox con stile LBS_SORT; vi consiglio di evitare questa situazione, che può causare alcune anomalie, semplicemente non usando mai LB_INSERTSTRING, bensì soltanto LB_ADDSTRING, per popolare listbox con stile LBS_SORT).

Si può rimuovere dalla lista un elemento col messaggio LB_DELETESTRING, sempre con l'indice dell'elemento d'interesse in wParam, e si avrà come valore di ritorno il numero di elementi restanti. Si può anche chiedere il numero di elementi presenti, senza fare modifiche, col messaggio LB_GETCOUNT; e svuotare completamente un listbox col messaggio LB_RESETCONTENT. La cancellazione di un elemento, se la lista è owner-drawn, provoca la spedizione di un messaggio WM_DELETEITEM al proprietario (su Windows 95/98, questo messaggio è spedito anche per la cancellazione di elementi da liste non owner-drawn).

La lunghezza del testo associato a un dato elemento si può richiedere spedendo al listbox il messaggio LB_GETTEXTLEN (sempre con l'indice dell'elemento in wParam), e il testo stesso con LB_GETTEXT (con l'indirizzo del nostro buffer, che deve avere una lunghezza sufficiente e verrà riempito col testo richiesto, passato come lParam).

Si può trovare un elemento che inizia con un certo testo con il messaggio LB_FINDSTRING (oppure, un elemento che ha esattamente un certo testo, con il messaggio LB_FINDSTRINGEXACT); si passerà l'indirizzo della stringa da cercare (terminata come al solito da 0 binario) in lParam, e, in wParam, -1 per cercare nell'intera lista, o, se no, l'indice del primo elemento da non prendere in considerazione nella ricerca (ma la ricerca riprenderà dall'inizio della lista se non ha successo entro la sua fine; il codice LB_ERR, che indica che nulla è stato trovato, viene restituito come valore di ritorno solo se l'elemento cercato non è presente in nessun punto della lista).

Le caratteristiche di dettaglio di una listbox con stile LBS_USETABSTOPS dipendono da come sono settati i suoi "tab stop", cioè, "arresti di tabulazione". Per default, essi sono ogni 32 "unità di dialogo", l'unità di misura, cui già abbiamo accennato, che corrisponde a circa 1/4 della larghezza media dei caratteri del font in uso; in altri termini, i tab stop di default sono ogni 8 caratteri circa, il che può essere già soddisfacente in molti casi. Se non lo è, si può rimediare spedendo alla listbox un messaggio LB_SETTABSTOPS: in wParam metteremo il numero totale di tab-stop che desideriamo, in lParam l'indirizzo di un array di interi corrispondente ai valori dei tab-stop, in unità di misura "dialog unit" e in ordine strettamente crescente. (Ricordiamo anche che abbiamo accennato all'API MapDialogRect, che si può usare per convertire da dialog unit a pixel un qualsiasi rettangolo entro un dialogo).

Per una listbox multi-colonna (cioè, con il bit di stile LBS_MULTICOLUMN), si può stabilire l'ampiezza delle colonne (che sono tutte di eguale larghezza) con il messaggio LB_SETCOLUMNWIDTH; in wParam, si metterà la desiderata larghezza in pixel delle colonne.

Vi sono molti altri messaggi importanti che si possono inviare a un controllo listbox, per controllarne la selezione e lo scorrimento, ma li tratteremo al prossimo capitolo.


Capitolo 42: controlli: i LISTBOX
Capitolo 44: messaggi ai LISTBOX (2)
Elenco dei capitoli