Come accennavamo alla fine del capitolo precedente, la nostra piccola applicazione interattiva di esempio non è ancora del tutto soddisfacente.
Un primo problema emerge quando, nel far "girellare" l'icona sul dialogo, essa si trova a "interagire" con i bottoni che si trovano in alto a destra della dialog-box.
Anzitutto, vediamo l'icona passare "sopra" i bottoni, con l'eccezione di quello che stiamo cliccando, cui invece sembra passare "sotto"; peggio, quando "passa sotto", notiamo che essa sbuca "sporca" dall'altra parte, portando le tracce del bottone che, chiaramente, le è stato "disegnato sopra" (tracce transitorie, perchè se copriamo il dialogo con un'altra finestra e poi lo scopriamo di nuovo, esse non ci sono più -- ma, comunque, si tratta di un effetto grafico indesiderato e molto spiacevole!).
Quando delle "finestre-sorelle" interagiscono
"graficamente" in questo modo, è di solito
un chiaro sintomo che manca, fra i loro bit
di stile, uno in particolare: WS_CLIPSIBLINGS
.
In effetti, non abbiamo messo questo bit di stile nel nostro file .RC (e Windows non lo attiva di default perchè, di solito, le finestre dei controlli sono "ferme", rispetto al dialogo in cui si trovano; quindi, questo "clipping" non darebbe benefici, però potrebbe "costare" un sia pur minimo appesantimento del carico di esecuzione).
Per attivare questo bit di stile per ciascuna
delle finestrelle dei nostri controlli, basta,
nel file .RC, cambiare le righe fra il BEGIN
ed END
del dialogo a qualcosa come:
STATIC
, con implicito SS_ICON
ecc),
WS_CLIPSIBLINGS
risulta l'unico bit di stile che
viene esplicitamente settato; per i "pushbutton"
(BUTTON
, con implicito BS_PUSHBUTTON
ecc),
esso è "in aggiunta" al già asserito BS_BITMAP
,
e quindi usiamo l'operatore di "or, bit-per-bit"
(barra verticale) così che entrambi i bit vengano
settati.
Ricompilando questo RC, e rilinkando il tutto per aggiornare le risorse del nostro EXE, vediamo che, in effetti, la situazione è diventata molto più ragionevole; l'icona passa sistematicamente "sotto" tutti i bottoni (perchè, elencandola per ultima, e quindi facendo sì che venga creata per ultima, implichiamo che è "la più bassa" nell'ordine della "coordinata Z") e comunque non viene "sporcata" da questi passaggi. Se volessimo invece farla passare "sopra", basterebbe naturalmente elencarla, nel file .RC, prima dei bottoni.
Un altro potenziale difetto del nostro programma è che, a forza di clic sui bottoni, è possibile "spinger fuori" l'icona, in modo che essa non risulta più visibile sul dialogo. È discutibile se questo sia "giusto" o meno, ma più interessante può essere asserire che non lo è, e studiare come possiamo rimediare a questo "difetto".
Evidentemente, possiamo arricchire la funzione
WindMove
, che già ci siamo scritti, in modo che,
facoltativamente, limiti lo spostamento che
impartisce alla finestra che tratta, in modo da
mantenerla
all'interno di un certo rettangolo. Un buon modo
per esprimere questo è con un classico idioma
del C: aggiungiamo un parametro, di tipo puntatore
a rettangolo (RECT*
, o LPRECT
che dir si voglia);
se questo parametro è nullo, indica che non si
desidera alcuna limitazione al movimento della
finestra; se non nullo, punta al rettangolo entro il quale
la finestra va mantenuta. Le modifiche necessarie
alla nostra WindMove
sono assai modeste:
return SetWindowPlacement
,
possiamo inserire un test:
Resta solo da decidere quale rettangolo passare alla
WindMove
nella nostra OnDlgCommand
-- e, se
passarle effettivamente l'indirizzo di un rettangolo, o,
invece, un puntatore 0, in modo che essa non ponga
alcun limite allo spostamento dell'icona.
Perchè non lasciare la scelta all'utente interattivo?
Tutto sommato, basta aggiungere un bottone, di tipo
"check box", per la scelta di "limitare il movimento
dell'icona all'interno del dialogo" -- e questo si può
fare semplicemente aggiungendo una AUTOCHECKBOX
fra il BEGIN
e l'END
del dialogo (questo statement è la forma
abbreviata del CONTROL
con classe BUTTON
e stile
da check-box a risposta automatica) -- ricordiamo
che "auto", qui, significa che il segno "spuntatura"
verrà automaticamente messo o tolto nel box quando
l'utente vi fa clic con il mouse, così che il nostro
programma non deve preoccuparsene.
Nella OnDlgCommand
, possiamo aggiungere
una variabile di tipo LPRECT
(puntatore
a RECT
), e una di tipo RECT:
WindMove
, dovremo verificare
se è necessario imporre i limiti, chiedendo al
nuovo auto-checkbox quale sia il suo stato:
WindMove
nello switch
dovranno avere pRectLimit come ultimo parametro.
Resta solo da capire come ottenere, nella variabile
RECT
di nome rectLimit
, il rettangolo di limitazione
del movimento, entro l'if
che abbiamo appena scritto.
Qui ci torna comoda l'API (che vediamo per la prima volta)...:
RECT
il cui indirizzo le è passato
come secondo parametro, le coordinate della "area
cliente" della finestra la cui handle riceve come
primo parametro (attenzione, naturalmente, a non
fare l'errore, tipico dei principianti assoluti del C!,
di passare come secondo parametro una qualsiasi
variabile di tipo LPRECT
, supponendo che in qualche
modo magico la funzione chiamata possa settarne
il valore... i parametri, alle API come a tutte le altre
funzioni, in C sono passati per valore: qui, come
secondo parametro, va passato l'indirizzo di una
nostra variabile, già esistente, di tipo RECT
!).
Una semplice chiamata:
Stiamo, chiaramente, lasciando come esercizio per il lettore quello di "mettere insieme" tutti gli elementi che stiamo offrendo, allo scopo di ricostruire l'intero programma. Una volta fatto ciò, si potrà tornare a compilarlo e linkarlo, e osservare gli effetti.
Una anomalia che rimane, e che pure lasciamo come esercizio da risolvere al lettore: se l'icona è "mezza fuori" dall'area cliente del dialogo, e l'utente clicca sulla checkbox per chiedere che i suoi spostamenti vengano limitati all'interno del dialogo, l'icona, lì per lì, non si sposta; al primo clic su uno dei bottoni con freccia, tuttavia, essa "salta" all'interno del dialogo.
Chiaramente, sarebbe meglio che "saltasse", invece, in risposta al clic stesso sulla checkbox. Suggerimento per la soluzione di questo problemino: basta gestire, come gli altri clic sui bottoni, anche questo; quali "spostamenti" andranno portati in questo caso alla nostra icona...?
Un altro problema, decisamente scocciante per l'utente interattivo di questo programmino, non ammette una soluzione così immediata... l'icona, come da specifiche, risponde ai "clic" sui bottoni-freccia, e va bene; ma se l'utente, come può venire spontaneo, tiene premuto il tasto sinistro del mouse, con il cursore su uno dei bottoni... non succede niente, sinchè, lasciando il tasto stesso, egli non "completa" l'azione di clic. Sarebbe bello, invece, che i bottoni stessi avessero una azione di, diciamo, "ripetizione automatica"; in altri termini, un simile comportamento da parte dell'utente dovrebbe avere come risultato, non la più assoluta immobilità dell'icona, bensì un suo continuo spostamento nella direzione indicata.
Come potremmo ottenere questo tipo di comportamento...? Il seguito, naturalmente, al prossimo capitolo.
Capitolo 16: un esempio (3)
Capitolo 18: timer e subclassing
Elenco dei capitoli