Introduzione alle API Win32

Capitolo 42: controlli: i LISTBOX

I controlli "Listbox", che abbiamo usato nel più semplice dei modi negli ultimi due capitoli, servono, più in generale, a mostrare all'utente elenchi (liste) di stringhe di testo (o, liste di arbitraria grafica, usando il concetto avanzato di "owner-drawn"), eventualmente dando all'utente la possibilità di selezionare uno o più degli elementi elencati.

Il controllo può occupare uno spazio su schermo inferiore a quello necessario per mostrare simultaneamente tutti gli elementi dell'elenco; in questo caso, si potranno avere delle "scroll bar", di cui l'utente potrà servirsi per scorrere avanti e indietro nell'elenco, cioè per visualizzare zone diverse.

Non bisogna confondere i (relativamente semplici) controlli "listbox", con i sofisticati controlli comuni "listview", che svolgono ruoli analoghi ma in modi più complessi. Comunque, anche un "semplice" listbox, così come gli altri controlli "elementari" che abbiamo esaminato sinora, di compiti può svolgerne parecchi, come vedremo, oltre a quello fondamentale di mostrare un semplice elenco di stringhe (con scrolling), è già compito per cui abbiamo utilizzato un list-control nei due capitoli precedenti.

Anche per i controlli Listbox, come per gli altri tipi già visti ai capitoli precedenti, i bit di stile svolgono un ruolo fondamentale. LBS_NOSEL serve per eliminare la possibilità che l'utente effettui una selezione sulla lista; con questo bit di stile, il Listbox è un controllo di "puro output".

Al contrario, i bit di stile (mutualmente esclusivi) LBS_MULTIPLESEL e LBS_EXTENDEDSEL permettono entrambi di abilitare sulla lista la selezione multipla, con due diverse modalità di interazione dal punto di vista dell'utente: la prima prevede semplicemente che ogni clic su di un elemento lo trasformi da non-selezionato a selezionato, o viceversa; la seconda, più sofisticata, prevede l'uso di tasti speciali come SHIFT e CONTROL per i cambiamenti della selezione -- è una modalità di interazione probabilmente familiare agli utenti esperti di Windows.

Il bit LBS_NOTIFY fa sì che il controllo spedisca alla finestra che lo contiene un messaggio di notifica ad ogni clic o doppio clic dell'utente su di un elemento della lista (per la precisione, bisognerà porre NOT LBS_NOTIFY, esplicitamente, fra i bit di stile, se non si vogliono avere queste notifiche). Il bit LBS_WANTKEYBOARDINPUT permette un controllo ancora maggiore da parte del programma, poichè fa sì che il listbox spedisca alla finestra che lo contiene uno speciale messaggio WM_VKEYTOITEM ogni volta che l'utente preme un tasto mentre il focus è sul listbox stesso.

Normalmente, un listbox elenca i propri elementi uno dopo l'altro, in una singola colonna; si può invece ottenere una molteplicità di colonne usando il bit di stile LBS_MULTICOLUMN.

Normalmente, la scroll-bar verticale appare automaticamente (se la finestra del list-box comprende il bit di stile WS_VSCROLL, naturalmente!), se e quando la lista contiene più elementi di quanti possa mostrarne simultaneamente sullo schermo, e sparisce se il numero di elementi è inferiore a questo; per avere invece una scroll-bar verticale sempre visibile (che sarà non abilitata, se non vi è possibile scorrimento), occorre aggiungere al controllo il bit di stile LBS_DISABLENOSCROLL. Se interessa che l'utente possa effettuare uno scroll orizzontale, si userà il bit di stile WS_HSCROLL (e vedremo inoltre più avanti quale altra precauzione sarà necessaria in questo caso).

Il bit LBS_USETABSTOPS fa sì che il controllo espanda i caratteri di tabulazione (control-I, cioè caratteri di valore numerico 9) presenti nelle stringhe che contiene. LBS_NOREDRAW evita che il controllo si ridisegni automaticamente ad ogni cambiamento (questo bit può essere messo o tolto in qualsiasi momento, spedendo al controllo opportuni messaggi di WM_SETREDRAW, con wParam rispettivamente FALSE o TRUE). LBS_NOINTEGRALHEIGHT evita che la dimensione del controllo venga arrotondata ad un multiplo intero dello spazio necessario per mostrare ciascun elemento; di default, questo arrotondamento avviene automaticamente, mentre, con questo bit, la dimensione del controllo è invece esattamente quella specificata dal programma.

Un controllo listbox mantiene una copia delle stringhe relative agli elementi che contiene, a meno che il listbox non sia "owner-drawn", nel qual caso ciò normalmente non succede; ma si può specificare il bit di stile LBS_HASSTRINGS per far sì che le stringhe vengano memorizzate anche da un controllo listbox owner-drawn.

Il concetto di "owner-drawn" per un controllo listbox è più raffinato che per i controlli che abbiamo visto sinora, poichè il listbox ha molteplici elementi ("item") e il disegno deve avvenire in modo separato per ciascuno di essi. Ad ogni WM_DRAWITEM, lParam sarà un puntatore ad una struttura dati DRAWITEMSTRUCT, che fra i vari campi ne ha uno, itemID, che identifica l'esatto elemento di cui si richiede il disegno, e un altro, itemData, che può portare informazioni arbitrarie che il programma ha scelto di associare al dato elemento (si tratta spesso di un puntatore a una struttura di dati, o di un indice in una tabella mantenuta dal programma).

Il controllo listbox può essere reso owner-drawn da due diversi bit di stile (mutualmente esclusivi, naturalmente): LBS_OWNERDRAWFIXED, se tutti gli elementi hanno la stessa altezza (il programma dovrà allora rispondere a un singolo messaggio WM_MEASUREITEM, speditogli alla creazione della lista, e i dati di dimensione che fornirà in quell'occasione varranno per ogni elemento); LBS_OWNERDRAWVARIABLE, se ogni elemento può avere altezza diversa (in questo caso, il messaggio WM_MEASUREITEM verrà spedito separatamente per ogni elemento da disegnare).

LBS_NODATA, che funziona solo assieme a LBS_OWNERDRAWFIXED, e senza LBS_HASSTRINGS, permette di avere controlli listbox con un numero enorme di elementi (altrimenti, vi è un limite attorno al migliaio), a patto naturalmente che la finestra contenitrice si prenda tutte le responsabilità di disegno dell'aspetto di ciascun elemento a fronte della sola informazione sul "numero di riga" dell'elemento stesso (è questo che viene passato, in questo specifico caso, come campo itemID della struttura dati DRAWITEMSTRUCT che accompagna ciascun messaggio WM_DRAWITEM).

Al contrario, per il caso molto comune in cui dal listbox non si voglia altro che un elenco di stringhe in ordine alfabetico, si può lasciare l'intera responsabilità dell'ordinamento al controllo stesso, semplicemente dotandolo dei bit di stile LBS_SORT. Questo bit si può usare anche per listbox owner-drawn privi del bit di stile LBS_HASSTRINGS, nel qual caso la finestra che contiene il controllo listbox dovrà rispondere ai messaggi WM_COMPAREITEM che il controllo le lancerà quando necessario per effettuare il sort degli elementi.

Il lettore è, naturalmente, incoraggiato a sperimentare con tutti questi bit di stile, e le loro combinazioni, magari sviluppando per gli stili dei listbox un programmino di sperimentazione analogo a quello che scrivemmo per quelli degli editbox nel Capitolo 22 e seguenti. Si userà il messaggio LB_ADDSTRING, cui già abbiamo accennato nei due capitoli precedenti, per "popolare" opportunamente il controllo listbox.

Naturalmente, molto dell'effetto dei bit di stile che abbiamo qui esaminato è legato ai vari messaggi inviati al controllo, e ai messaggi di notifica che il controllo a sua volta spedisce al contenitore; proseguiremo, dunque, l'esame di questi aspetti, al prossimo capitolo.


Capitolo 41: dialoghi non modali
Capitolo 43: messaggi ai LISTBOX (1)
Elenco dei capitoli