La form
A questo punto mi sembra opportuno dare un’occhiata più da vicino al nostro contenitore di oggetti interattivi. Abbiamo più volte accennato che è anch’esso un oggetto, paragonato a un comune pulsante, infondo è qui la semplicità di questo tipo di programmazione fanno tutti parte della stessa famiglia. Cliccando su una form possiamo constatare nell’object inspector quante proprietà e quanti eventi possiede, alcuni li conosciamo già, altri li scopriremo con il tempo. Nel prossimo progetto useremo alcuni di questi eventi per capire come utilizzarli al meglio nelle nostre applicazioni.
Creiamo un nuovo progetto e salviamolo in una nuova cartella. La prima cosa vorrei finalmente centrare la nostra finestra al centro dello schermo, in automatico, senza essere costretti a utilizzare la finestrina in basso a destra in Design. Nelle proprietà della form cercate “Position” e selezionate la voce che vedete:

Questa proprietà ha diverse opzioni a noi serve quella che ci centra la finestra sullo schermo, ma per provare le differenze potete selezionarle una per volta o leggere la spiegazione nell’help allegato a Delphi (F1 quando la voce è selezionata). Inseriamo un pulsante di chiusura e provate. Se desiderate che questo nuovo progetto abbia lo stile XP sapete come fare, da questo momento in poi non accennerò più al pulsante di chiusura e a questo componente.
Abbiamo più volte detto che tutto quello contenuto nella form è di proprietà della form, ora faremo un test per verificare questa proprietà degli oggetti. Nelle proprietà della form cercate “Font” e selezionate un carattere diverso da quello specificato, e osservate che anche quello del pulsante cambia a indicare che esiste un legame di parentela. Come per il pulsante anche gli altri oggetti messi sulla form e che possiedono un testo erediteranno questa proprietà, ma è sempre possibile modificarla selezionando la proprietà Font di ogni singolo oggetto.
Selezionando la pagina degli eventi della form ci rendiamo conto che ne esistono una moltitudine ma siamo aiutati dal nome dell’evento, che ci fa capire a cosa è associato. Il nostro obiettivo ora è far comparire un messaggio prima che il programma venga mostrato, per questo motivo cercheremo l’evento “onCreate” che viene generato alla creazione della form. Come vedete il nome dell’evento richiama il suo lavoro, ma non dimentichiamo che abbiamo sempre l’help in linea che spiega tutto qualora avessimo bisogno di qualcosa in particolare. Facendo doppio clic di fianco alla voce selezionata viene creta la procedura che ci interessa, tra begin ed end scriveremo la nostra funzione che mostra un messaggio:

Se provate constaterete che prima che la finestra principale venga mostrata avremo la comparsa del nostro messaggio, possiamo continuare in questo senso per testare gli altri eventi più utilizzati in un progetto. Quindi allo stesso modo di come abbiamo fatto prima, cercate l’evento “onClose” che evidentemente, come ci dice il nome, viene richiamato quando la finestra sta per essere chiusa, e implementate il messaggio:

Facendo così quando si preme il pulsante di chiusura viene mostrato questo messaggio e poi chiuso la finestra. Osserviamo anche un’altra cosa però, la nostra finestra è l’unica del nostro progetto quindi è lei la principale, chiudendola si chiude il programma. Pertanto il codice scritto nell’evento “onClose” della finestra principale verrà chiamato quando il programma viene chiuso, allo stesso modo anche l’evento “onCreate” verrà chiamato alla creazione del programma.
Questi due eventi sono molto importanti per un progetto, infatti di solito nell’evento onCreate vengono effettuati i controlli per abilitare l’avvio del programma e per leggere le impostazioni salvate l’ultima volta che è stato utilizzato. In onClose vengono effettuati di solito i salvataggi delle impostazioni oppure un controllo se è possibile chiudere in quel momento il programma senza che venga perso qualche dato. Possiamo fare qualche semplice esempio per capire come è possibile controllare il flusso della creazione e della chiusura in modo interattivo, utilizzando risposte dall’utente per lanciare o chiudere il programma.
In precedenza abbiamo spiegato che MessageDlg è una funzione ma se controllate l’utilizzo che ne abbiamo fatto fino a ora, constaterete che è stata usata come una procedura. In pratica abbiamo usato una funzione senza tener conto della sua risposta, il che non è strano quando la procedura oltre a darci un risultato fa anche qualcos’altro. Nel nostro caso la funzione MessageDlg da come risultato il tipo di tasto premuto, se noi la utilizziamo con un singolo pulsante la risposta non ci interessa, è ovvio che verrà premuto quello. Ma se ricordiamo come è strutturata possiamo notare che è possibile visualizzare diversi tipi di pulsante, quelli che per ora interessano a noi sono il pulsante “Si” e “No” (mbYes, mbNo).
Il nostro intento è chiedere all’utente, alla creazione della form principale, se desidera lanciare il programma, utilizzando MessageDlg. Modifichiamo un poco la nostra chiamata nell’evento onCreate:
procedure TForm1.FormCreate(Sender: TObject);
begin
If MessageDlg('Lanciare il programma?',mtInformation,[mbYes,mbNo],0)=mrNo
Then Halt;
end;
Abbiamo visto che MessageDlg da come risultato un valore Word, quindi un numero. Delphi per comodità ha creato delle risposte già belle è pronte, che ci aiutano a sapere quale tasto è stato premuto. In pratica funziona così: se voglio visualizzare un pulsante “Ok” devo scrivere nei parametri “[mbOk]” per sapere se è stato premuto vado a controllare se la risposta è “mrOk” (dove l’acronimo “mb” sta per “message button” mentre “mr” sta per “message result”). Nel nostro caso volevamo visualizzare i due pulsanti “Si” e “No” quindi abbiamo inserito come parametro “[mbYes+mbNo]” e siamo andati a testare se viene premuto “No”, quindi “[mrNo]”. Se volevamo testare la pressione del tasto “Si” dovevamo testare la risposta “mrYes”. I possibili risultati della funzione MessageDlg sono questi:
mrOk
mrCancel
mrAbort
mrRetry
mrIgnore
mrYes
mrNo
mrAll
mrNoToAll
mrYesToAll
Ognuno di questi messaggi di risposta corrisponde a un valore numerico di tipo Word, quindi compatibili con la funzione in esame, in effetti queste sono Costanti numeriche, che abbiamo visto nel capitolo precedente, proprie del linguaggio.
L’altra cosa nuova che possiamo vedere è la chiamata alla procedura Halt. La chiamata a questa procedura termina in modo anormale (immediatamente) il programma, questa va utilizzata solo in alcuni casi particolari, in quanto termina bruscamente l’esecuzione del programma perdendo gli eventuali dati lasciati in sospeso. In questo caso bisogna utilizzare questo comando perché “Close” non può essere utilizzato nell’evento “onCreate”. La procedura Close termina in modo corretto il programma richiamando tutte gli eventi utilizzati, in “onCreate” dovrebbe chiudere una cosa che si sta creando. Se provate a utilizzarla comunque questa procedura vedrete che in effetti viene chiamata la chiusura ma la form compare ugualmente. Usando Halt invece il programma si ferma lì e l’eventuale codice scritto negli eventi di chiusura non vengono processati.
Facciamo la stessa cosa nell’evento onClose così impariamo a gestire anche la chiusura del programma:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
If MessageDlg('Chiudere il programma?',mtConfirmation,[mbYes,mbNo],0)=mrNo Then
Action := caNone;
end;
Questo evento possiede una variabile “Action” come eventuale azione da intraprendere se viene chiesto di uscire dal programma. Assegnando uno dei possibili valori a questa variabile si ottiene una delle seguenti azioni:
caNone Non viene chiusa e non succede nulla
caHide Non viene chiusa ma viene nascosta e continua a funzionare
caFree La form viene chiusa regolarmente
caMinimize Non viene chiusa ma viene ridotta a icona
Come si vede dal nostro esempio quando compare il messaggio, se si preme Yes non succede nulla e la form viene chiusa, mentre premendo No viene assegnato “caNone” alla variabile Action e il programma continua a funzionare.
Diamo ora lo sguardo a una proprietà della form molto importante, se a runtime provate a modificare la grandezza della form vedrete che questo è possibile, addirittura vi da la possibilità di rimpicciolirla fino all’assurdo. A volte però necessitiamo di finestre fisse, senza possibilità di essere modificate nella loro grandezza. La proprietà che controlla l’apparenza del bordo di una form è “BorderStyle”. Cercandola nella lista delle proprietà vedrete che ha una lista a discesa con più opzioni:

Quella che interessa a noi è quella che vedete evidenziata nella figura, ma potete fare un po’ di prove per vedere come cambia l’apparenza per ogni settaggio. Addirittura se selezionate “bsNone” il bordo della finestra scompare del tutto e l’unico modo per chiuderla è utilizzare il pulsante. Altra proprietà legata all’apparenza della finestra è quella subito prima:

dove possiamo controllare i pulsanti a destra del titolo. Se per esempio vogliamo disabilitare la funzione di riduzione a icona, basta selezionare False nella voce “biMinimize”.
Alcune proprietà possono essere utilizzate anche a runtime, impostando alcuni valori manualmente. Il prossimo esempio utilizzerà “WindowState” per modificare lo stato della form sullo schermo, ma lo faremo servendoci di componenti “RadioButton”. Queste sono le proprietà che ci interessano:

E questi sono i tre pulsanti con le loro scritte:

L’evento onClic di ogni RadioButton imposterà un valore nella proprietà “WindowState”, in questo modo:
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
WindowState := wsNormal;
end;
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
WindowState := wsMaximized;
end;
procedure TForm1.RadioButton3Click(Sender: TObject);
begin
WindowState := wsMinimized;
end;
In modo che ogni volta viene selezionato una scelta viene eseguito un comando, a runtime verificate quello che succede.
La prossima proprietà che vorrei mostrarvi è quella che cambia il titolo della finestra. Come il pulsante possiede la proprietà Caption per modificare la scritta che compare sulla superficie, così la form possiede la medesima proprietà ma per modificare il titolo sulla barra in alto. A questo punto vorrei utilizzare una costante per settare il mio titolo, che poi verrà modificato ogni volta si preme un Radio Button, proviamo.
Ecco la variabile:
CONST TitForm = 'Prova titolo';
Mentre ogni clic sui pulsanti modifica la caption della form:
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
WindowState := wsNormal;
Caption := TitForm+' - '+RadioButton1.Caption;
end;
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
WindowState := wsMaximized;
Caption := TitForm+' - '+RadioButton2.Caption;
end;
procedure TForm1.RadioButton3Click(Sender: TObject);
begin
WindowState := wsMinimized;
Caption := TitForm+' - '+RadioButton3.Caption;
end;
Al posto di scrivere il testo manualmente abbiamo preso direttamente la Caption
del pulsante che viene premuto, in questo modo se per qualche motivo
modifichiamo la scritta sarà tutto automatico.
Per finire vorrei farvi vedere un ultimo evento che possiedono molti oggetti posti sulla form: “onMouseMove”, provate prima a leggere l’help per capire quando viene richiamato, anche se il nome ci dice tutto.
Mettiamo sulla form una label e diamogli un colore blu e un font un po’ più grande della form, nell’evento “onMouseMove” scriviamo il codice che ci permette di sapere la posizione del mouse sulla form. Questo è possibile perché questo evento quando richiamato da le coordinate x,y del mouse sulla superficie della finestra, noi possiamo leggere questi valori, trasformarli in stringa e visualizzarli, ecco come:
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Label1.Caption := IntToStr(x)+'x'+IntToStr(y);
end;
“IntToStr” trasforma il valore passato da x e da y in una stringa, questi due valori vengono separati da un carattere a nostra scelta “x”, tutto sommato tra di loro in modo da ottenere una unica stringa. Potete osservare che questa procedura mi ritorna anche lo stato dei pulsanti speciali, che in alcuni casi potrebbero servirci, nel nostro caso ignoriamo volontariamente quello che la variabile “Shift” contiene.