I programmatori che affrontano la programmazione in ambienti grafici (come Win32) provenendo da precedenti esperienze in ambienti orientati al testo (come DOS) sentono spesso la mancanza del buon vecchio idioma "printf di debug". Vi sono, certo, debugger potenti e sofisticati, ma, qualche volta, sarebbe bello poter ottenere un semplice quadro d'insieme dell'esecuzione del nostro programma, esaminando una serie di "stampe" piazzate strategicamente nei punti opportuni.
Naturalmente, è possibile fare queste scritture su di un file di testo, e questo ha i suoi separati vantaggi (permanenza del "log" di esecuzione) e problemi (il file va chiuso, e riaperto in append, ad ogni scrittura, se no un crash del nostro programma lascerebbe una traccia incompleta di esecuzione proprio quando più ne avremmo bisogno per capire le ragioni e la meccanica del crash stesso!).
Le API di Win32 offrono anche una chiamata apposita:
(Naturalmente, non è un problema che questa
API accetti una stringa, invece di un formato e un elenco
variabile di argomenti alla "printf"; è banale, infatti,
fare prima la formattazione da formato+argomenti a stringa --
con sprintf
, o con
l'analoga API wsprint
, o magari con la ricca
e complessa API FormatMessage
-- e poi
emettere la stringa risultante, ad esempio con
OutputDebugString
; il meccanismo "stdarg"
del C offre un modo semplice di impacchettare le due
cose in una, e quello C++ degli "stream" un modo anche
più semplice, elegante, e generale).
Tutto sommato, dunque, c'è ancora posto per un semplice e artigianale "output di debugging fatto in casa", e il controllo listbox offre un ottimo e semplicissimo approccio per implementarlo.
A questo scopo, basta conoscere il seguente minuscolo sottoinsieme delle ricche e varie funzionalità delle listbox (che presenteremo poi in dettaglio in un capitolo successivo):
LBS_NOSEL
elimina tutte
le funzioni di "selezione", trasformando il listbox in un
controllo di "puro output";
LB_ADDSTRING
,
con lParam
posto all'indirizzo di una stringa C
(un array di caratteri terminato da uno 0 binario), quella
stringa viene aggiunta in coda alla lista (il controllo se
ne fa una copia, per cui non occorre che ne mantenga copia
anche il nostro programma).
Questi elementi ci permettono di accennare già una prima bozza di soluzione. Facciamo un piccolo dialogo, con un file RC simile a:
LISTBOX
, il cui scopo dovrebbe però essere,
spero, abbastanza ovvio (la necessità di specificare
esplicitamente NOT LBS_NOTIFY
fra i bit di stile,
per evitare che la listbox ci "avverta" di eventi che non ci
interessano, deriva da un gioco di "default", e non è
qui molto importante).
La semplicissima dialog procedure da connettere a questo
template di dialogo sarà del tipo (omettendo i vari
casi già visti, come il WM_INITDIALOG
per il quale non abbiamo nulla da fare, il WM_CLOSE
per cui dovremo fare la solita EndDialog
, ecc,
ed evidenziando invece il solo frammento d'interesse):
In pratica, al clic sul bottone "OK" (o alla pressione del tasto di Invio, visto che il bottone stesso è quello di default), preleviamo la stringa che l'utente ha immesso nel controllo di edit, e la spediamo al controllo listbox, dove viene accodata alle altre già presenti.
Completando questo programmillo, e giocandoci un poco, diventa evidente che, mentre la funzionalità di base è soddisfacente, vi sono un paio di cosette antipatiche:
WS_VSCROLL
, e questo va bene; ma la
zona visualizzata non cambia -- l'utente deve agire sulla
scroll-bar per vedere l'output più recente. Sarebbe
simpatico avere un automatico scorrimento, quando
una stringa viene emessa, così che l'output più
recente sia, di default, sempre visualizzato.
ES_AUTOHSCROLL
nel nostro controllo di
edit), la listbox ne visualizza solo la prima parte.
Benchè abbiamo specificato fra i suoi bit di stile
anche quello di WS_HSCROLL
, la barra di
scroll orizzontale non appare, anche se evidentemente
ci servirebbe che lo facesse. Questo problema dovrà
sicuramente essere risolto prima che possiamo considerare
questo schema di "output a scopo di debugging" come
soddisfacente a livello "di produzione".
Questi due problemi richiedono un'interazione appena un poco più sofisticata con il controllo listbox, e quindi li riprenderemo in esame più avanti, dopo che avremo dato tutti i necessari dettagli sul controllo stesso.
Un altro problema, più grave e strutturale, non ha invece nulla a che vedere coi listbox: il problema in questione è che questo approccio all'output di debugging, come l'abbiamo ora presentato, è invasivo rispetto ai programmi che vogliono farne uso. Per la precisione, un tale programma deve riservare una certa area sul suo dialogo (deve avere un dialogo, il che è pure un limite, perchè, anche se ancora non abbiamo preso in esame questa problematica, si possono avere tante varietà di applicazioni per Windows che hanno invece un'impostazione assai diversa!) al solo scopo di mostrare il proprio output di debugging. Ma questo output tipicamente non interessa all'utente finale del programma, bensì solo al programmatore che lo sviluppa; le due versioni del programma, quella "da debug" e quella "per release", dovrebbero dunque far uso di diversi layout per il dialogo principale, il che dà svariati tipi di problemi.
Per risolvere questo problema strutturale, bisogna insomma che la listbox di output sia in un dialogo diverso da quello principale, e da esso separato. Non abbiamo però ancora visto come questa separazione sia possibile, e di questo tema ci occuperemo dunque al prossimo capitolo.
Capitolo 39: Indies: l'implementazione
Capitolo 41: dialoghi non modali
Elenco dei capitoli