Gli STATIC
, benchè utili e flessibili, non sono certo gli
unici tipi di controlli predefiniti che Windows ci mette a disposizione. I
"controlli elementari", infatti, comprendono anche BUTTON
,
COMBOBOX
, EDIT
, LISTBOX
, e
SCROLLBAR
, mentre i più avanzati "controlli comuni" (la
terminologia non è proprio limpida...!) "iniziano" con il "Rich Edit"
(normalmente nelle due versioni, rispettivamente ANSI e UNICODE,
RichEdit20A
e RichEdit20W
; la macro
RICHEDIT_CLASS
, definita, naturalmente, negli header file di
sistema, permette di usare il nome di classe migliore in ciascun caso).
I controlli comuni proseguono, poi, con la ricca panoplia che comprende
Animate
, HotKey
, Date-Time
Picker
, ProgressBar
, ReBar
,
StatusBar
, Tooltip
, Trackbar
,
UpDown
, Combo Box
estesa,
Header
, IP-Address
, Listview
,
Pager
, TabControl
, e TreeView
(e altri
ancora, in versioni più recenti di Win32!). I nomi delle classi di tutta
questa varietà di controlli "comuni" tendono a cambiare spesso, per cui
per essi si usano normalmente delle macro definite, assieme a tante altre cose,
nell'header file di sistema <commctrl.h>.
L'enorme varietà e ricchezza di questi controlli ci impedirà, naturalmente, di darne una trattazione soddisfacente nell'ambito di quello che vuol essere un "tutorial" (cioè una trattazione puramente introduttiva sul tema "uso delle API Win32"), soprattutto considerando quale vasta, enorme ricchezza funzionale di dettaglio c'è dietro ciascuno di questi (tanti!) controlli predefiniti!
Presenteremo, invece, i controlli più importanti ed elementari, ed eventualmente qualche cenno ed esempio di argomenti più avanzati; quanto basta, possiamo sperare, per indirizzare il lettore verso un uso proficuo dell'help in linea del Platform SDK, di MSDN, e di altri testi disponibili su questi temi.
I controlli BUTTON
sono abbastanza semplici e
versatili. Un BUTTON
è quasi sempre un modo
per l'utente di comunicare al nostro programma,
"cliccando" (col tasto sinistro del mouse, o con
la tastiera) sul bottone stesso; a seconda del
suo "stile", può essere un "pushbutton", una
"checkbox", o un "radiobutton", con aspetti
e significati diversi.
Esistono inoltre i bottoni "owner-drawn" (cioè "disegnati dal proprietario"), nel qual caso il nostro programma si rende pienamente responsabile per l'aspetto del button e per il suo comportamento; e i bottoni "group box", che, pur appartenendo alla stessa classe di finestre, non ricordano per nulla gli altri button, bensì, se mai, gli static, poichè si tratta di pure "decorazioni" della finestra di dialogo, senza alcuna interazione con l'utente (l'aspetto è quello di un rettangolo, normalmente posto attorno a un gruppo di altri controlli, appunto allo scopo di "raggrupparli" visivamente, con un'etichetta di testo in alto a sinistra).
Un "push button" è il più tipico e riconoscibile dei
"bottoni". Il suo stile-base è BS_PUSHBUTTON
;
uno, e uno solo, dei bottoni dei dialogo può invece
essere designato come BS_DEFPUSHBUTTON
, cioè
"bottone di default" -- esso verrà disegnato in modo
leggermente diverso ed "enfatizzato", e, se l'utente
aziona il tasto Enter (Return) dovunque nel dialogo,
sarà "proprio come se" avesse cliccato il bottone
di default (un dialogo può correttamente avere uno
o nessun bottone di default; se ne ha più di uno,
invece, è un errore, e il comportamento non è
definito -- a seconda della versione di Windows, si
possono avere in questo caso effetti differenti).
Un push button mostra il proprio testo (primo
argomento dell'istruzione CONTROL
nel file RC)
centrato nel "bottone" vero e proprio. Quando
viene cliccato, come tutti i bottoni, avverte il
dialogo che lo contiene con il messaggio
WM_COMMAND
, codice di notifica BN_CLICKED
(proprio come uno STATIC
con il bit di stile
SS_NOTIFY
, se cliccato, avverte il dialogo con
lo stesso WM_COMMAND
, ma codice di
notifica SN_CLICKED
).
Una "check box" è una casella che può essere
"spuntata" ("checked") o meno, con un
testo esplicativo a fianco. Con lo stile BS_CHECKBOX
,
si ottiene il comportamento-base: ogni volta che
l'utente clicca, il dialogo riceve il WM_COMMAND
,
ed è responsabile di gestire lo stato on/off della
casella "check box". Spesso utile è invece lo
stile BS_AUTOCHECKBOX
, in cui la casella
"commuta" automaticamente il proprio stato
on/off (oltre a spedire il solito WM_COMMAND
).
Esistono anche caselle "a tre stati" (BS_3STATE
,
e BS_AUTO3STATE
) che, oltre agli stati on e off,
prevedono un "terzo stato indeterminato" (che
è rappresentato "ingrigendo" la casella).
Un "radio button" è simile a una checkbox (gli
stili sono BS_RADIOBUTTON
e -- nulla a che
vedere con le autoradio! -- BS_AUTORADIOBUTTON
),
con un aspetto un poco diverso (rotondo, con o
senza "pallino", invece che quadrato con o
senza "spuntatura"), e una cruciale differenza
di comportamento: un radiobutton non si "spegne"
quando l'utente vi clicca, bensì quando egli
clicca su di un altro radiobutton, che si
accende. I radiobutton indicano, insomma, una
situazione in cui l'utente può scegliere una di
N possibilità, reciprocamente esclusive.
La determinazione "automatica" di quali radio
button di un dialogo siano nello stesso "gruppo"
si appoggia sul loro flag di stile WS_GROUP
e
sull'ordine in cui sono stati creati nel dialogo.
Un "gruppo" comincia dal primo controllo creato,
e continua, nell'ordine di creazione, sino a che
non si incontra un controllo con WS_GROUP
--
quest'ultimo è escluso dal gruppo; ciascun
gruppo successivo al primo inizia da un controllo con
WS_GROUP
, incluso, e prosegue, sempre
nell'ordine di creazione, sino al prossimo controllo
che ha WS_GROUP
, escluso.
Questo concetto di "gruppo", tra l'altro, oltre
alla sua funzione cruciale per gruppi di radio
button, è anche assai rilevante relativamente
alle possibilità di
"navigazione" all'interno del dialogo, da parte
dell'utente che voglia usare la tastiera invece
del mouse: un "gruppo" di controlli (come qui
definito) è anche l'insieme di controlli fra cui
l'utente può muoversi coi tasti-freccia della
tastiera. L'ordine di creazione dei controlli
(che, usando un file .RC, è esattamente
l'ordine con cui i controlli sono elencati fra il
BEGIN
e l'END
del dialogo)
è poi anche lo
stesso ordine in cui l'utente si può muovere
da un controllo all'altro usando TAB, gruppi a
parte (usando il tasto TAB, l'utente potrà
raggiungere direttamente solo i controlli che
hanno il bit di stile WS_TABSTOP
).
Se non usiamo gli stili AUTO
, lo stato
on/off di check box e radio button dipende solo dai
messaggi che il nostro codice invia ai controlli
stessi. Il messaggio BM_SETCHECK
, con
lParam
obbligatoriamente 0, contiene in
wParam
il valore che vogliamo impostare per
lo stato di check del check box o radio button
cui lo spediamo: BST_CHECKED
fà sì che
il bottone appaia "impostato" (col segno di
spuntatura, o il pallino, secondo il suo stile),
mentre BST_UNCHECKED
fà sì che il bottone
appaia "non impostato" ("vuoto").
Si può
anche chiedere ad un bottone il suo stato
di check, spedendogli il messaggio BM_GETCHECK
; lo
stato sarà allora comunicato come valore di ritorno della
API SendMessage
usata per spedire questo
messaggio (i possibili valori di ritorno sono,
nuovamente, BST_CHECKED
e BST_UNCHECKED
).
Si tenga ben presente questo tipo di possibilità:
tenere un "doppione" della informazione "stato del
bottone", visto che il bottone stesso "conosce" il
proprio stato (ed è possibile chiederglelo ogni
volta che esso interessi), è una di quelle "micro
ottimizzazioni" che, 99 volte su 100, è meglio
evitare accuratamente (a tenere simili "doppioni"
dello stato, si corrono vari rischi di "errori di
aggiornamento" fra quel che il nostro programma
"crede" che sia lo stato attuale, e l'opinione che
in merito hanno invece altre "copie ridondanti"
dello stato stesso...).
Lo stile BS_BITMAP
e quello BS_ICON
sono
simili a quelli SS_BITMAP
e SS_ICON
: il
bottone mostra un'immagine (bitmap, o icona,
rispettivamente) invece di un testo. L'immagine
può essere impostata col messaggio
BM_SETIMAGE
(così come, per uno static,
può esserlo col messaggio STM_SETIMAGE
).
Ma torneremo su questi temi più avanti,
quando inizieremo ad affrontare i problemi della
grafica in Windows; similmente, rimandiamo
la gestione degli "owner-drawn" (sia per i
button, sia per gli static), visto che, sino ad
allora, non sapremmo ancora come e cosa
disegnare. Lo stesso vale per i messaggi di
tipo WM_CTLCOLOR
..., che permettono ad
un dialogo di stabilire i colori dei controlli
che contiene (questo richiede l'uso di
meccanismi tipici della "grafica" di Windows,
da cui la decisione di rimandarne l'esame).
Così come uno STATIC
può essere abilitato
a spedire alcuni messaggi (tipo SN_CLICKED
) al
dialogo col bit di stile SS_NOTIFY
, così un
BUTTON
può essere abilitato a spedire altri
messaggi (oltre a BN_CLICKED
, che esso
spedisce comunque!) al suo dialogo, con il
bit di stile BS_NOTIFY
. I messaggi che così
si ottengono sono:
BN_DOUBLECLICKED
, il "doppio click"
(la documentazione Microsoft dice che si
tratta di un messaggio obsoleto presente
solo per compatibilità, ma questo è un
errore della documentazione stessa!)
BN_SETFOCUS
e BN_KILLFOCUS
,
spediti quando il
bottone ottiene e perde il "focus di input"
Viceversa, se un'applicazione, per qualche
strana ragione, vuole simulare il clic su
di un bottone da parte dell'utente, può
farlo spedendo al bottone stesso il
messaggio BM_CLICK
(con entrambi i
parametri obbligatoriamente pari a zero);
questo messaggio deve essere spedito solo ai bottoni
di un dialogo che è attualmente attivo.
Naturalmente, anche altri stili (come
WS_BORDER
, cui già abbiamo accennato),
applicabili a generiche finestre, sono, in
particolare, applicabili anche ai bottoni;
così pure, altri messaggi (come
WM_GETTEXT
e WM_SETTEXT
, cui pure
accennammo), sono, come a tante altre
finestre, applicabili anche ai bottoni.
L'idea che la comunicazione fra finestre, in entrambi i versi, proceda sostanzialmente solo tramite "messaggi", è una potente "unificazione", e corrisponde abbastanza bene all'effettivo funzionamento "interno" di Windows. Tuttavia, esistono delle "vesti alternative" che possiamo dare, sia alla spedizione, sia alla ricezione, analisi, ed elaborazione, dei messaggi stessi, e a volte queste alternative possono offrire una certa comodità. È dunque giunto il momento di prendere nuovamente in considerazione il tema "messaggi", cosa che faremo nei prossimi due capitoli.
Capitolo 9: problemi di struttura
Capitolo 11: macro e API "di comodo"
Elenco dei capitoli