Differenze tra le versioni di "Gli Eventi"
(19 versioni intermedie di uno stesso utente non sono mostrate) | |||
Riga 5: | Riga 5: | ||
Queste situazioni, appunto, scatenano un ''Evento'' ben preciso che, nella realtà, eseguono un determinata Funzione (o Metodo). <SUP>[[[#Note|nota 1]]]</sup> | Queste situazioni, appunto, scatenano un ''Evento'' ben preciso che, nella realtà, eseguono un determinata Funzione (o Metodo). <SUP>[[[#Note|nota 1]]]</sup> | ||
− | In Gambas, per ogni | + | In Gambas, per ogni Oggetto grafico presente nelle librerie standard a corredo, sono già predefiniti degli Eventi, alcuni per le operazioni nella normale interattività con l'interfaccia grafica, altri legati ovviamente alla particolare funzione dell'Oggetto stesso. |
− | Per fare un esempio, tutti gli | + | Per fare un esempio, tutti gli Oggetti grafici, presenti nelle librerie grafiche di Gambas, dispongono dell'Evento "_Click()", che corrisponde sempre e comunque alla pressione e al conseguente rilascio del tasto del mouse in corrispondenza dell'area grafica occupata dall'Oggetto stesso. In Oggetti particolari, per continuare con gli esempi, come ad esempio "ScrollView", sono presenti Eventi particolari, come "_Scroll()" che, ovviamente, sono implementati per gestire le caratteristiche peculiari dell'Oggetto, in questo caso lo ''scrolling'' della barra. |
− | + | ||
+ | =Gli Eventi degli Oggetti - la routine ''Risponditore''= | ||
Per poter usufruire degli Eventi di un particolare ''Oggetto'', è necessario implementare un "'''Risponditore'''", ovvero una funzione che riceve l'Evento, e che esegua il codice necessario a processarlo. | Per poter usufruire degli Eventi di un particolare ''Oggetto'', è necessario implementare un "'''Risponditore'''", ovvero una funzione che riceve l'Evento, e che esegua il codice necessario a processarlo. | ||
Riga 17: | Riga 18: | ||
In gambas, la nomenclatura dei Metodi Evento, segue una ben precisa logica, che non può essere elusa, pena il non funzionamento del Metodo stesso. Questa logica prevede che il nome del Metodo sia composto dal nome dell'Oggetto cui si riferisce l'Evento e un carattere di ''underscore'', seguito dal nome dell'Evento: | In gambas, la nomenclatura dei Metodi Evento, segue una ben precisa logica, che non può essere elusa, pena il non funzionamento del Metodo stesso. Questa logica prevede che il nome del Metodo sia composto dal nome dell'Oggetto cui si riferisce l'Evento e un carattere di ''underscore'', seguito dal nome dell'Evento: | ||
− | < | + | '''PUBLIC''' SUB <<FONT Color=blue>'''Gruppo'''</font>>'''_'''<<FONT Color=red>'''Evento'''</font>>() |
− | ''' | + | ...... |
+ | End | ||
+ | Poniamo un esempio pratico: | ||
+ | '''Public''' Sub <FONT Color=blue>Button1</font><FONT Color=red><B>_</b>Click()</font> | ||
. . . | . . . | ||
END | END | ||
Riga 24: | Riga 28: | ||
<BR>In gambas, dunque, gli Eventi sono associati ad un singolo gestore, che può essere identificato dal nome dell'Oggetto stesso oppure dal nome del GROUP, seguito dal tipo di Evento. | <BR>In gambas, dunque, gli Eventi sono associati ad un singolo gestore, che può essere identificato dal nome dell'Oggetto stesso oppure dal nome del GROUP, seguito dal tipo di Evento. | ||
<BR>Tramite GROUP è possibile ''unificare'' gli Eventi in un singolo gestore generale, relativo allo stesso Oggetto ''Parent'' di tutto (es. una Form). | <BR>Tramite GROUP è possibile ''unificare'' gli Eventi in un singolo gestore generale, relativo allo stesso Oggetto ''Parent'' di tutto (es. una Form). | ||
− | <BR>Non è però possibile unificare anche il tipo di Evento, come invece succede con altri linguaggi. Per cui l' | + | <BR>Non è però possibile unificare anche il tipo di Evento, come invece succede con altri linguaggi. Per cui l'Evento "_Click()", ad esempio, può essere gestito da un solo Metodo "_Click()", e non può venir mischiato con un Evento "_DblClick()". |
<BR>Quindi, a prescindere da chi scatena l'Evento, il Metodo è sempre quello, ed è gestito internamente a Gambas, per cui non è possibile modificarne la logica. | <BR>Quindi, a prescindere da chi scatena l'Evento, il Metodo è sempre quello, ed è gestito internamente a Gambas, per cui non è possibile modificarne la logica. | ||
− | + | ||
− | |||
− | |||
Se più Oggetti vengono associati allo stesso Gruppo, lo stesso Evento verrà gestito dallo stesso Metodo. E' ovvio che poi all'interno del Metodo si dovrà capire chi ha scatenato l'Evento (se necessario), e in questo caso viene a proposito la parola-chiave LAST che, appunto, ritorna l'Oggetto che ha scatenato l'Evento. | Se più Oggetti vengono associati allo stesso Gruppo, lo stesso Evento verrà gestito dallo stesso Metodo. E' ovvio che poi all'interno del Metodo si dovrà capire chi ha scatenato l'Evento (se necessario), e in questo caso viene a proposito la parola-chiave LAST che, appunto, ritorna l'Oggetto che ha scatenato l'Evento. | ||
− | |||
− | |||
− | Per assegnare uno o più Oggetti, creato da codice, ad un gruppo di Eventi propri della ''Classe'', alla quale l'Oggetto appartiene, è possibile adottare almeno tre modalità. <SUP>[[[#Note|nota | + | =Gli Eventi degli Oggetti - Assegnare a un Gruppo di Eventi un Oggetto creato da codice= |
+ | I "Gruppi" aggregano i gestori di Eventi di un insieme di più Oggetti. <SUP>[[[#Note|nota 2]]]</sup> | ||
+ | |||
+ | Per assegnare uno o più Oggetti, creato da codice, ad un gruppo di Eventi propri della ''Classe'', alla quale l'Oggetto appartiene, è possibile adottare almeno tre modalità. <SUP>[[[#Note|nota 3]]]</sup> | ||
<BR>Vediamo alcuni esempi con un Oggetto grafico, quale è il "Button". | <BR>Vediamo alcuni esempi con un Oggetto grafico, quale è il "Button". | ||
− | + | ||
+ | ==Assegnazione esplicita di un Gruppo di Eventi== | ||
L'Assegnazione diretta ed esplicita dell'Oggetto creato ad un Gruppo di Eventi avviene con la parola-chiave "'''AS'''": | L'Assegnazione diretta ed esplicita dell'Oggetto creato ad un Gruppo di Eventi avviene con la parola-chiave "'''AS'''": | ||
Public Sub Form_Open() | Public Sub Form_Open() | ||
Riga 45: | Riga 49: | ||
<FONT Color=gray>' ''Crea l'Oggetto e dichiara di quale Contenitore sarà "Figlio", in tal caso in quale Contenitore sarà mostrato.'' | <FONT Color=gray>' ''Crea l'Oggetto e dichiara di quale Contenitore sarà "Figlio", in tal caso in quale Contenitore sarà mostrato.'' | ||
' ''Inoltre, assegna l'Oggetto ad un Gruppo di Eventi che viene chiamato "Bottone".''</font> | ' ''Inoltre, assegna l'Oggetto ad un Gruppo di Eventi che viene chiamato "Bottone".''</font> | ||
− | With bt = NEW Button(Me) <FONT Color= | + | With bt = NEW Button(Me) <FONT Color=red><B>As</b></font> <FONT Color=darkgreen>"Bottone"</font> |
.X = 100 | .X = 100 | ||
.Y = 100 | .Y = 100 | ||
Riga 54: | Riga 58: | ||
End | End | ||
− | Public Sub | + | |
+ | Public Sub <FONT Color=darkgreen>Bottone</font>_Click() | ||
Message.Info("Tasto premuto.") | Message.Info("Tasto premuto.") | ||
End | End | ||
− | + | ||
+ | ==Assegnazione mediante il Metodo "Object.Attach()"== | ||
Una seconda modalità è l'assegnazione mediante il Metodo "Object.Attach()". | Una seconda modalità è l'assegnazione mediante il Metodo "Object.Attach()". | ||
Public Sub Form_Open() | Public Sub Form_Open() | ||
Riga 75: | Riga 81: | ||
<FONT Color=gray>' ''Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Il 2° argomento dev essere sempre il Contenitore principale.''</font> | <FONT Color=gray>' ''Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Il 2° argomento dev essere sempre il Contenitore principale.''</font> | ||
− | <FONT Color= | + | <FONT Color=blue><B>Object.Attach</b></font>(bt, Me, <FONT Color=darkgreen>"Bottone"</font>) |
End | End | ||
− | Public Sub | + | |
+ | Public Sub <FONT Color=darkgreen>Bottone</font>_Click() | ||
Message.Info("Tasto premuto.") | Message.Info("Tasto premuto.") | ||
End | End | ||
− | + | ||
+ | ==Assegnazione mediante la Classe "Observer"== | ||
La terza modalità è l'assegnazione mediante la Classe "Observer". | La terza modalità è l'assegnazione mediante la Classe "Observer". | ||
− | Private obs As Observer | + | Private obs As <FONT Color=blue>Observer</font> |
+ | |||
Public Sub Form_Open() | Public Sub Form_Open() | ||
Riga 102: | Riga 111: | ||
<FONT Color=gray>' ''Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Come nella prima modalità, il nome identificativo del Gruppo di Eventi sarà attribuito mediante la parola-chiave "AS".''</font> | <FONT Color=gray>' ''Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Come nella prima modalità, il nome identificativo del Gruppo di Eventi sarà attribuito mediante la parola-chiave "AS".''</font> | ||
− | obs = New <FONT Color= | + | obs = New <FONT Color=blue><B>Observer</b></font>(bt) <FONT Color=red><B>As</b></font> <FONT Color=darkgreen>"Bottone"</font> |
End | End | ||
− | Public Sub | + | |
+ | Public Sub <FONT Color=darkgreen>Bottone</font>_Click() | ||
Message.Info("Tasto premuto.") | Message.Info("Tasto premuto.") | ||
Riga 112: | Riga 122: | ||
End | End | ||
− | = | + | |
+ | =Produrre e scatenare un Evento proprio di un Oggetto creato dall'utente - Le istruzioni "EVENT" e "RAISE"= | ||
Quanto sopra descritto, fa riferimento ad una situazione standard, ovvero l'utilizzo degli oggetti di Gambas, e i loro eventi. | Quanto sopra descritto, fa riferimento ad una situazione standard, ovvero l'utilizzo degli oggetti di Gambas, e i loro eventi. | ||
Cosa succede quando creiamo un nostro oggetto, e abbiamo la necessità di associargli eventi per gestire particolari condizioni? | Cosa succede quando creiamo un nostro oggetto, e abbiamo la necessità di associargli eventi per gestire particolari condizioni? | ||
Riga 124: | Riga 135: | ||
EVENT Change() 'le parentesi non sono abbligatorie, in mancanza di parametri | EVENT Change() 'le parentesi non sono abbligatorie, in mancanza di parametri | ||
... | ... | ||
− | + | Per far scatenare l'Evento, si usa la parola-chiave '''RAISE''', seguita dall'identificatore dell'Evento. | |
− | Ora abbiamo l'oggetto completo dell' | + | |
− | A questo punto vogliamo usare la | + | Così, riprendendo l'ultimo esempio, dobbiamo solo decidere dove all'interno della routine scatenare l'Evento in questione. In questo caso inseriamo un "RAISE Change()" in ogni parte del codice della classe in cui viene modificato il valore della variabile associata "$var", dopo che questa viene modificata (non importa dove). |
− | Come per gli | + | Ora abbiamo l'oggetto completo dell'Evento. |
+ | A questo punto vogliamo usare la Classe nella nostra applicazione... | ||
+ | Come per gli Eventi delle Classi contenute nelle librerie di Gambas, è sufficiente creare la Classe nel Modulo, o altra Classe, che utilizza la nostra MyObject: | ||
... | ... | ||
DIM $my AS MyObject | DIM $my AS MyObject | ||
Riga 140: | Riga 153: | ||
---- | ---- | ||
− | |||
Nell'esempio precedente abbiamo creato tutta la logica necessaria per implementare un semplice evento. | Nell'esempio precedente abbiamo creato tutta la logica necessaria per implementare un semplice evento. | ||
− | Ma la domanda potrebbe sorgere spontanea: e se io volessi passare dei dati tramite l' | + | Ma la domanda potrebbe sorgere spontanea: e se io volessi passare dei dati tramite l'Evento? |
− | |||
− | |||
+ | Anche in questo caso, la cosa è molto semplice, basta dichiarare - come consueto - i parametri formali necessari nella dichiarazione dell'Evento: | ||
... | ... | ||
− | EVENT Change(var AS String) | + | '''EVENT''' Change(var AS String) |
... | ... | ||
− | + | In questo esempio abbiamo aggiunto il parametro "var", di tipo String, allo stesso Evento creato in precedenza. | |
− | In questo esempio abbiamo aggiunto il parametro "var", di tipo String, allo stesso | + | Nella stessa Classe è necessario modificare opportunamente tutte le istruzioni RAISE, riferite all'Evento "_Change()": |
− | Nella stessa | ||
... | ... | ||
'''RAISE''' Change($var) | '''RAISE''' Change($var) | ||
... | ... | ||
− | Inoltre, sarà necessario modificare opportunamente tutti i | + | Inoltre, sarà necessario modificare opportunamente tutti i Metodi "risponditori" a questo Evento: |
− | |||
PUBLIC SUB MY_Change(var AS String) | PUBLIC SUB MY_Change(var AS String) | ||
... | ... | ||
Riga 164: | Riga 173: | ||
... | ... | ||
END | END | ||
+ | In questa situazione, oltre allo scatenare un Evento, abbiamo la possibilità di fornire ulteriori informazioni ai Metodi "risponditori", e questo, ovviamente, amplia notevolmente le possibilità nelle nostre applicazioni. | ||
+ | <BR>E' comunque consigliato non esagerare nel numero di parametri passati tramite gli Eventi, perchè ciò potrebbe causare una riduzione delle risorse e della velocità di esecuzione del programma. | ||
− | + | ===Esempio pratico=== | |
− | + | L'esempio, che segue, da una Classe principale viene sollevato un Evento in una Classe secondaria. in partcolare Nella Classe principale viene chiamata una routine presente nella Classe secondaria (che chiameremo "Cprova.class") che scatenerà l'Evento previsto nella Classe principale. | |
− | + | <BR>In questo caso la parola-chiave "'''Event'''" è posta in una ''Classe'' <U>secondaria</u> e scatena un Evento previsto nella ''Classe'' principale. | |
− | |||
− | |||
− | Nella Classe principale viene chiamata una routine presente nella Classe secondaria (che chiameremo "Cprova.class") che scatenerà l' | ||
− | <BR>In questo caso la parola-chiave "'''Event'''" è posta in una ''Classe'' < | ||
<FONT color=gray>' ''Qui siamo nella classe '''principale''' FMain.Class'' | <FONT color=gray>' ''Qui siamo nella classe '''principale''' FMain.Class'' | ||
Riga 178: | Riga 185: | ||
− | + | Public Sub Form_Open() | |
<FONT color=gray>' ''Creiamo la variabile "evProva" del tipo della classe secondaria CProva:''</font> | <FONT color=gray>' ''Creiamo la variabile "evProva" del tipo della classe secondaria CProva:''</font> | ||
Riga 186: | Riga 193: | ||
prova.funzSecond() | prova.funzSecond() | ||
− | + | End | |
<FONT color=gray>' ''Se sollevato l'Evento "evento" nella classe secondaria, viene scatenata questa routine, alla quale viene passata una stringa:''</font> | <FONT color=gray>' ''Se sollevato l'Evento "evento" nella classe secondaria, viene scatenata questa routine, alla quale viene passata una stringa:''</font> | ||
− | '''Public''' Sub <FONT color=blue>evProva</font><FONT color= | + | '''Public''' Sub <FONT color=blue>evProva</font><FONT color=red>_evento</font>(<FONT color=purple>testo As String</font>) |
<FONT color=gray>' ''Il testo, contenuto nella variabile stringa, passata dalla classe secondaria, viene mostrato in console:''</font> | <FONT color=gray>' ''Il testo, contenuto nella variabile stringa, passata dalla classe secondaria, viene mostrato in console:''</font> | ||
Print <FONT color=purple>testo</font> | Print <FONT color=purple>testo</font> | ||
− | + | End | |
− | + | Quando viene chiamata la sub-routine nella classe secondaria ''Cprova.class'', questa solleva l'Evento nella Classe Principale: | |
− | Quando viene chiamata la sub-routine nella classe secondaria Cprova.class, questa solleva l'Evento nella Classe Principale: | ||
− | |||
<FONT color=gray>' ''Questa invece è la classe '''secondaria''' "CProva.class"'' | <FONT color=gray>' ''Questa invece è la classe '''secondaria''' "CProva.class"'' | ||
' ''Con '''Event''' viene dichiarato l'Evento (al quale in questo esempio è dato il nome “evento”) ed un parametro di tipo "Stringa".'' | ' ''Con '''Event''' viene dichiarato l'Evento (al quale in questo esempio è dato il nome “evento”) ed un parametro di tipo "Stringa".'' | ||
' ''Tale parametro rappresenta il tipo di valore che sarà passato alla routine della Classe "principale"; routine che sarà invocata dalla sollevazione dell'evento medesimo:''</font> | ' ''Tale parametro rappresenta il tipo di valore che sarà passato alla routine della Classe "principale"; routine che sarà invocata dalla sollevazione dell'evento medesimo:''</font> | ||
− | + | <FONT color=#009900><B>Event</b></font> <FONT color=red>evento</font>(<FONT color=purple>txt As String</font>) | |
+ | |||
'''Public''' Sub funzSecond() | '''Public''' Sub funzSecond() | ||
Riga 212: | Riga 218: | ||
<FONT color=gray>' ''Con '''Raise''' viene sollevato l'Evento “evento”, il quale scatenerà la sub-routine "evProva_evento(testo As String)" presente nella classe principale, e le passa il valore della variabile “s”:''</font> | <FONT color=gray>' ''Con '''Raise''' viene sollevato l'Evento “evento”, il quale scatenerà la sub-routine "evProva_evento(testo As String)" presente nella classe principale, e le passa il valore della variabile “s”:''</font> | ||
− | <FONT color=#009900>Raise</font> <FONT color= | + | <FONT color=#009900>Raise</font> <FONT color=red>evento</font>(<FONT color=purple>s</font>) |
− | + | End | |
− | + | ==Usare l'istruzione ''EVENT'' nella Classe principale e sollevarvi un Evento== | |
L'istruzione ''Event'' può essere presente all'interno della ''Classe'' <SPAN style="text-decoration:underline">principale</span> e sollevare un Evento previsto nella ''Classe'' principale medesima. | L'istruzione ''Event'' può essere presente all'interno della ''Classe'' <SPAN style="text-decoration:underline">principale</span> e sollevare un Evento previsto nella ''Classe'' principale medesima. | ||
<BR>Esempio: | <BR>Esempio: | ||
− | <FONT color=#009900><B>Event</b></font> <FONT color= | + | <FONT color=#009900><B>Event</b></font> <FONT color=red>evento</font>(testo As String) |
− | '''Public''' Sub Form<FONT color= | + | '''Public''' Sub Form<FONT color=red>_evento</font>(s As String) |
Print s | Print s | ||
− | + | End | |
− | |||
− | <FONT Color=darkorange><B>Raise</b></font> <FONT color= | + | Public Sub Form_Open() |
+ | |||
+ | <FONT Color=darkorange><B>Raise</b></font> <FONT color=red>evento</font>("Evento sollevato !") | ||
− | + | End | |
− | ===Impossibilità di un "Modulo" di sollevare un proprio Evento | + | ===Sollevazione di un Evento senza passaggio di dati=== |
− | L'uso dell'istruzione ''Event'' < | + | Ovviamente potrà essere sollevato un Evento <U>senza</u> che avvenga contestualmente un passaggio di dati. |
+ | <BR>Pertanto nella dichiarazione dell'Evento <U>non</u> sarà previsto alcun parametro formale. | ||
+ | <FONT color=#009900><B>Event</b></font> <FONT color=red>evento</font> | ||
+ | |||
+ | |||
+ | Public Sub Form_Open() | ||
+ | |||
+ | <FONT Color=gray>' ''Solleva il solo semplice Evento senza passaggio di dati:''</font> | ||
+ | <FONT Color=darkorange><B>Raise</b></font> <FONT color=red>evento</font> | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | Public Sub Form<FONT color=red>_evento</font>() | ||
+ | |||
+ | Print "Evento sollevato !" | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | =Impossibilità di un "Modulo" di sollevare un proprio Evento= | ||
+ | L'uso dell'istruzione ''Event'' <U>non</u> può avvenire all'interno di un "Modulo", <SPAN style="text-decoration:underline">non essendo capace</span> il "Modulo" di sollevare un '''proprio''' ''Evento''. | ||
<BR>Ricordiamo che soltanto la ''Classe'' è capace di avere un ''Evento'' come propria risorsa, e quindi di sollevarlo. | <BR>Ricordiamo che soltanto la ''Classe'' è capace di avere un ''Evento'' come propria risorsa, e quindi di sollevarlo. | ||
Il "Modulo" è, però, capace mediante una propria routine ''[[Gli_eventi#Gli_Eventi_degli_Oggetti_-_la_routine_Risponditore|Risponditore]]'' di intercettare un ''Evento'' appartenente e sollevato in una ''Classe''. | Il "Modulo" è, però, capace mediante una propria routine ''[[Gli_eventi#Gli_Eventi_degli_Oggetti_-_la_routine_Risponditore|Risponditore]]'' di intercettare un ''Evento'' appartenente e sollevato in una ''Classe''. | ||
<BR>A tal riguardo mostriamo un esempio, nel quale avremo il Modulo principale con il seguente codice: | <BR>A tal riguardo mostriamo un esempio, nel quale avremo il Modulo principale con il seguente codice: | ||
− | + | Public Sub Main() | |
Module1.Avvia() | Module1.Avvia() | ||
− | + | End | |
che invoca una ''Procedura'' posta in un "Modulo" secondario, chiamato ''Module1.module'', avente il seguente codice: | che invoca una ''Procedura'' posta in un "Modulo" secondario, chiamato ''Module1.module'', avente il seguente codice: | ||
'''Public''' cl1 As Class1 | '''Public''' cl1 As Class1 | ||
Riga 253: | Riga 281: | ||
cl1.ClasseSecondaria() | cl1.ClasseSecondaria() | ||
− | + | End | |
− | + | ||
+ | Public Sub Class1<FONT Color=red>_Evento</font>(s As String) | ||
Print s | Print s | ||
− | + | End | |
Come si può notare, tale "Modulo" secondario dichiara e istanzia una ''Classe'' secondaria, chiamata ''Class1.class'' con il codice che segue, invocandone altresì una ''Procedura'' contenente l'istruzione ''Raise'': | Come si può notare, tale "Modulo" secondario dichiara e istanzia una ''Classe'' secondaria, chiamata ''Class1.class'' con il codice che segue, invocandone altresì una ''Procedura'' contenente l'istruzione ''Raise'': | ||
− | <FONT Color=#006400>'''Event'''</font> <FONT Color= | + | <FONT Color=#006400>'''Event'''</font> <FONT Color=red>Evento</font>(s As String) |
'''Public''' Procedure ClasseSecondaria() | '''Public''' Procedure ClasseSecondaria() | ||
Riga 268: | Riga 297: | ||
For b = 1 To 20 | For b = 1 To 20 | ||
− | If b == 10 Then <FONT Color=darkorange><B>Raise</b></font> <FONT Color= | + | If b == 10 Then <FONT Color=darkorange><B>Raise</b></font> <FONT Color=red>Evento</font>("Evento sollevato dopo " & CStr(b) & " cicli !") |
Next | Next | ||
− | + | End | |
La ''Classe'' solleva il '''proprio''' ''Evento'' che sarà intercettato nella sub-routine "Class1_Evento()" del "Modulo" secondario ''Module1.module''. | La ''Classe'' solleva il '''proprio''' ''Evento'' che sarà intercettato nella sub-routine "Class1_Evento()" del "Modulo" secondario ''Module1.module''. | ||
− | + | ||
+ | =Passare una Struttura con Event= | ||
Riguardo a tale argomento si rinvia alla lettura della seguente pagina: [[Passare_una_Struttura_con_Event|Passare una Struttura con Event]] | Riguardo a tale argomento si rinvia alla lettura della seguente pagina: [[Passare_una_Struttura_con_Event|Passare una Struttura con Event]] | ||
− | + | =Interruzione di un Evento= | |
Per interrompere, o comunque impedire la sollevazione di un determinato evento, è possibile utilizzare il comando ''Stop'' innanzi alla parola chiave ''Event''. | Per interrompere, o comunque impedire la sollevazione di un determinato evento, è possibile utilizzare il comando ''Stop'' innanzi alla parola chiave ''Event''. | ||
Esempio di interruzione dell'evento chiusura del ''Form'': | Esempio di interruzione dell'evento chiusura del ''Form'': | ||
− | + | Public Sub Form_Close() | |
− | If Message.Question("Chiudo?","Si","No") = 2 Then <FONT color= | + | If Message.Question("Chiudo?","Si","No") = 2 Then <FONT color=red>Stop Event</font> |
− | + | End | |
Come è possibile notare, il comando ''Stop'' non disabilita né blocca il Controllo, semplicemente interrompe la sollevazione del previsto Evento. | Come è possibile notare, il comando ''Stop'' non disabilita né blocca il Controllo, semplicemente interrompe la sollevazione del previsto Evento. | ||
Riga 294: | Riga 324: | ||
[1] L'Evento di una ''Classe'' è un ''Metodo'' che non viene invocato da alcuna ''chiamata di funzione'', ma che si attiva autonomamente all'inverarsi di un presupposto previsto dal codice sorgente della ''Classe'' medesima. | [1] L'Evento di una ''Classe'' è un ''Metodo'' che non viene invocato da alcuna ''chiamata di funzione'', ma che si attiva autonomamente all'inverarsi di un presupposto previsto dal codice sorgente della ''Classe'' medesima. | ||
− | [2] Vedere al riguardo anche le seguenti pagine: | + | [2] La creazione di un "Gruppo di Eventi" fa riferimento a una sub-routine, e in particolare a un ''Evento'' al quale fanno riferimento due o più Oggetti. |
+ | <BR>Lo scopo dell'attribuzione di più Oggetti a un unico "Gruppo di Eventi" è quello di adottare una scorciatoia per usare <U>un solo Nome comune</u> per identificare quell'<U>Insieme di Oggetti</u> che fanno riferimento a quello specifico ''Evento''. | ||
+ | <BR>L'istruzione ''LAST'' restituisce l'Oggetto, fra tutti quelli appartenenti al "Gruppo di Eventi", che ha sollevato l'<I>Evento</i> indicato nella dichiarazione della sub-routine. | ||
+ | |||
+ | [3] Vedere al riguardo anche le seguenti pagine: | ||
* [[Assegnare da codice più oggetti ad un Gruppo di eventi]] | * [[Assegnare da codice più oggetti ad un Gruppo di eventi]] | ||
* [[Proprietà particolari degli oggetti]] | * [[Proprietà particolari degli oggetti]] |
Versione delle 02:46, 14 lug 2024
In quasi tutti i linguaggi di programmazione attuali, esiste il concetto di Evento.
Un Evento è una situazione che viene scatenata al verificarsi di una determinata condizione. Un semplice esempio è la pressione del mouse su un bottone della finestra cui stiamo agendo.
Queste situazioni, appunto, scatenano un Evento ben preciso che, nella realtà, eseguono un determinata Funzione (o Metodo). [nota 1]
In Gambas, per ogni Oggetto grafico presente nelle librerie standard a corredo, sono già predefiniti degli Eventi, alcuni per le operazioni nella normale interattività con l'interfaccia grafica, altri legati ovviamente alla particolare funzione dell'Oggetto stesso. Per fare un esempio, tutti gli Oggetti grafici, presenti nelle librerie grafiche di Gambas, dispongono dell'Evento "_Click()", che corrisponde sempre e comunque alla pressione e al conseguente rilascio del tasto del mouse in corrispondenza dell'area grafica occupata dall'Oggetto stesso. In Oggetti particolari, per continuare con gli esempi, come ad esempio "ScrollView", sono presenti Eventi particolari, come "_Scroll()" che, ovviamente, sono implementati per gestire le caratteristiche peculiari dell'Oggetto, in questo caso lo scrolling della barra.
Indice
- 1 Gli Eventi degli Oggetti - la routine Risponditore
- 2 Gli Eventi degli Oggetti - Assegnare a un Gruppo di Eventi un Oggetto creato da codice
- 3 Produrre e scatenare un Evento proprio di un Oggetto creato dall'utente - Le istruzioni "EVENT" e "RAISE"
- 4 Impossibilità di un "Modulo" di sollevare un proprio Evento
- 5 Passare una Struttura con Event
- 6 Interruzione di un Evento
- 7 Note
- 8 Riferimenti
Gli Eventi degli Oggetti - la routine Risponditore
Per poter usufruire degli Eventi di un particolare Oggetto, è necessario implementare un "Risponditore", ovvero una funzione che riceve l'Evento, e che esegua il codice necessario a processarlo.
In Gambas, la costruzione di queste funzioni, che in realtà sono "Metodi" della Classe [nota 1] che le contiene, è piuttosto semplice.
L'ambiente di sviluppo stesso rende la cosa semplicissima. Se abbiamo familiarità con l'ide di Gambas e, per esempio, creiamo una Form contenente un Button, al doppio click del mouse sul bottone, l'ide apre la scheda Codice relativa alla Form, con il codice contenuto nella classe, e con aggiunto un nuovo Metodo, corrispondente appunto al "Risponditore" al click del pulsante.
Ovviamente la stessa cosa può essere fatta manualmente, se si ha abbastanza padronanza e conoscenza degli Oggetti usati, e i relativi Eventi.
In gambas, la nomenclatura dei Metodi Evento, segue una ben precisa logica, che non può essere elusa, pena il non funzionamento del Metodo stesso. Questa logica prevede che il nome del Metodo sia composto dal nome dell'Oggetto cui si riferisce l'Evento e un carattere di underscore, seguito dal nome dell'Evento:
PUBLIC SUB <Gruppo>_<Evento>() ...... End
Poniamo un esempio pratico:
Public Sub Button1_Click() . . . END
E' da ricordare che, nella costruzione degli Oggetti, sia attraverso l'ide di Gambas, che tramite codice, è possibile associare l'Oggetto a un determinato "gruppo" di Eventi (Proprietà: Group). In questo modo, è possibile associare tutti gli Eventi di tutti gli Oggetti facenti parte di un Gruppo, e di utilizzare Metodi-Evento in comune. All'interno poi dei Metodi sarà possibile determinare chi ha scatenato l'Evento, utilizzando l'istruzione LAST.
In gambas, dunque, gli Eventi sono associati ad un singolo gestore, che può essere identificato dal nome dell'Oggetto stesso oppure dal nome del GROUP, seguito dal tipo di Evento.
Tramite GROUP è possibile unificare gli Eventi in un singolo gestore generale, relativo allo stesso Oggetto Parent di tutto (es. una Form).
Non è però possibile unificare anche il tipo di Evento, come invece succede con altri linguaggi. Per cui l'Evento "_Click()", ad esempio, può essere gestito da un solo Metodo "_Click()", e non può venir mischiato con un Evento "_DblClick()".
Quindi, a prescindere da chi scatena l'Evento, il Metodo è sempre quello, ed è gestito internamente a Gambas, per cui non è possibile modificarne la logica.
Se più Oggetti vengono associati allo stesso Gruppo, lo stesso Evento verrà gestito dallo stesso Metodo. E' ovvio che poi all'interno del Metodo si dovrà capire chi ha scatenato l'Evento (se necessario), e in questo caso viene a proposito la parola-chiave LAST che, appunto, ritorna l'Oggetto che ha scatenato l'Evento.
Gli Eventi degli Oggetti - Assegnare a un Gruppo di Eventi un Oggetto creato da codice
I "Gruppi" aggregano i gestori di Eventi di un insieme di più Oggetti. [nota 2]
Per assegnare uno o più Oggetti, creato da codice, ad un gruppo di Eventi propri della Classe, alla quale l'Oggetto appartiene, è possibile adottare almeno tre modalità. [nota 3]
Vediamo alcuni esempi con un Oggetto grafico, quale è il "Button".
Assegnazione esplicita di un Gruppo di Eventi
L'Assegnazione diretta ed esplicita dell'Oggetto creato ad un Gruppo di Eventi avviene con la parola-chiave "AS":
Public Sub Form_Open() ' Dichiara l'identificatore (variabile) dell'Oggetto e il suo tipo Dim bt AS Button ' Crea l'Oggetto e dichiara di quale Contenitore sarà "Figlio", in tal caso in quale Contenitore sarà mostrato. ' Inoltre, assegna l'Oggetto ad un Gruppo di Eventi che viene chiamato "Bottone". With bt = NEW Button(Me) As "Bottone" .X = 100 .Y = 100 .W = 50 .H = 50 End With End Public Sub Bottone_Click() Message.Info("Tasto premuto.") End
Assegnazione mediante il Metodo "Object.Attach()"
Una seconda modalità è l'assegnazione mediante il Metodo "Object.Attach()".
Public Sub Form_Open() ' Dichiara l'identificatore (variabile) dell'Oggetto e il suo tipo Dim bt AS Button ' Crea l'Oggetto e dichiara di quale Contenitore sarà "Figlio", in tal caso in quale Contenitore sarà mostrato. With bt = New Button(Me) .X = 100 .Y = 100 .W = 50 .H = 50 End With ' Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Il 2° argomento dev essere sempre il Contenitore principale. Object.Attach(bt, Me, "Bottone") End Public Sub Bottone_Click() Message.Info("Tasto premuto.") End
Assegnazione mediante la Classe "Observer"
La terza modalità è l'assegnazione mediante la Classe "Observer".
Private obs As Observer Public Sub Form_Open() ' Dichiara l'identificatore (variabile) dell'Oggetto e il suo tipo Dim bt AS Button ' Crea l'Oggetto e dichiara di quale Contenitore sarà "Figlio", in tal caso in quale Contenitore sarà mostrato. With bt = New Button(Me) .X = 100 .Y = 100 .W = 50 .H = 50 End With ' Per il rilevamento degli Eventi, propri della Classe alla quale appartiene, l'Oggetto viene assegnato ad un Gruppo di Eventi che viene chiamato "Bottone". Come nella prima modalità, il nome identificativo del Gruppo di Eventi sarà attribuito mediante la parola-chiave "AS". obs = New Observer(bt) As "Bottone" End Public Sub Bottone_Click() Message.Info("Tasto premuto.") End
Produrre e scatenare un Evento proprio di un Oggetto creato dall'utente - Le istruzioni "EVENT" e "RAISE"
Quanto sopra descritto, fa riferimento ad una situazione standard, ovvero l'utilizzo degli oggetti di Gambas, e i loro eventi. Cosa succede quando creiamo un nostro oggetto, e abbiamo la necessità di associargli eventi per gestire particolari condizioni?
Gambas, anche in questo caso, dispone degli strumenti adatti per creare nuovi eventi, tramite l'utilizzo dell'istruzione EVENT.
La parola chiave EVENT, seguita dal nome del nuovo evento, istruisce il compilatore che il nome indicato corrisponde ad un evento, ovvero, permette di implementare negli oggetti che utilizzano la nostra classe, i relativi metodi di intercettazione.
Per fare un semplice esempio, mettiamo il caso di avere creato un oggetto, chiamato "MyObject", e abbiamo la necessità di implementare un modo per comunicare con l'esterno il manifestarsi di una determinata situazione interna, ad esempio il cambio di stato di una variabile di classe, ad esempio "$var". Per poter implementare tale cosa, definiamo uno specifico evento, e lo nominiamo "Change". In testa al codice della classe, e dopo eventuali istruzioni INHERITS e CREATE..., inseriamo la seguente istruzione:
... EVENT Change() 'le parentesi non sono abbligatorie, in mancanza di parametri ...
Per far scatenare l'Evento, si usa la parola-chiave RAISE, seguita dall'identificatore dell'Evento.
Così, riprendendo l'ultimo esempio, dobbiamo solo decidere dove all'interno della routine scatenare l'Evento in questione. In questo caso inseriamo un "RAISE Change()" in ogni parte del codice della classe in cui viene modificato il valore della variabile associata "$var", dopo che questa viene modificata (non importa dove). Ora abbiamo l'oggetto completo dell'Evento. A questo punto vogliamo usare la Classe nella nostra applicazione... Come per gli Eventi delle Classi contenute nelle librerie di Gambas, è sufficiente creare la Classe nel Modulo, o altra Classe, che utilizza la nostra MyObject:
... DIM $my AS MyObject Object.Attach($my, ME, "MY") 'attacchiamo gli eventi alla form ME, e diamo al nostro oggetto il nome "MY" ...
Ora creiamo il "Risponditore" adatto:
PUBLIC SUB MY_Change() ... PRINT "Lo stato della variabile $var è cambiato" ... END
Nell'esempio precedente abbiamo creato tutta la logica necessaria per implementare un semplice evento.
Ma la domanda potrebbe sorgere spontanea: e se io volessi passare dei dati tramite l'Evento?
Anche in questo caso, la cosa è molto semplice, basta dichiarare - come consueto - i parametri formali necessari nella dichiarazione dell'Evento:
... EVENT Change(var AS String) ...
In questo esempio abbiamo aggiunto il parametro "var", di tipo String, allo stesso Evento creato in precedenza. Nella stessa Classe è necessario modificare opportunamente tutte le istruzioni RAISE, riferite all'Evento "_Change()":
... RAISE Change($var) ...
Inoltre, sarà necessario modificare opportunamente tutti i Metodi "risponditori" a questo Evento:
PUBLIC SUB MY_Change(var AS String) ... PRINT "Lo stato della variabile $var è cambiato in '" & var & "'" ... END
In questa situazione, oltre allo scatenare un Evento, abbiamo la possibilità di fornire ulteriori informazioni ai Metodi "risponditori", e questo, ovviamente, amplia notevolmente le possibilità nelle nostre applicazioni.
E' comunque consigliato non esagerare nel numero di parametri passati tramite gli Eventi, perchè ciò potrebbe causare una riduzione delle risorse e della velocità di esecuzione del programma.
Esempio pratico
L'esempio, che segue, da una Classe principale viene sollevato un Evento in una Classe secondaria. in partcolare Nella Classe principale viene chiamata una routine presente nella Classe secondaria (che chiameremo "Cprova.class") che scatenerà l'Evento previsto nella Classe principale.
In questo caso la parola-chiave "Event" è posta in una Classe secondaria e scatena un Evento previsto nella Classe principale.
' Qui siamo nella classe principale FMain.Class ' Dichiariamo una variabile del tipo della classe secondaria CProva: Private prova As Cprova Public Sub Form_Open() ' Creiamo la variabile "evProva" del tipo della classe secondaria CProva: prova = New Cprova As "evProva" ' Viene chiamata la sub-routine nella classe secondaria: prova.funzSecond() End ' Se sollevato l'Evento "evento" nella classe secondaria, viene scatenata questa routine, alla quale viene passata una stringa: Public Sub evProva_evento(testo As String) ' Il testo, contenuto nella variabile stringa, passata dalla classe secondaria, viene mostrato in console: Print testo End
Quando viene chiamata la sub-routine nella classe secondaria Cprova.class, questa solleva l'Evento nella Classe Principale:
' Questa invece è la classe secondaria "CProva.class" ' Con Event viene dichiarato l'Evento (al quale in questo esempio è dato il nome “evento”) ed un parametro di tipo "Stringa". ' Tale parametro rappresenta il tipo di valore che sarà passato alla routine della Classe "principale"; routine che sarà invocata dalla sollevazione dell'evento medesimo: Event evento(txt As String) Public Sub funzSecond() Dim s As String s = "E' stato sollevato l'Evento !" ' Con Raise viene sollevato l'Evento “evento”, il quale scatenerà la sub-routine "evProva_evento(testo As String)" presente nella classe principale, e le passa il valore della variabile “s”: Raise evento(s) End
Usare l'istruzione EVENT nella Classe principale e sollevarvi un Evento
L'istruzione Event può essere presente all'interno della Classe principale e sollevare un Evento previsto nella Classe principale medesima.
Esempio:
Event evento(testo As String) Public Sub Form_evento(s As String) Print s End Public Sub Form_Open() Raise evento("Evento sollevato !") End
Sollevazione di un Evento senza passaggio di dati
Ovviamente potrà essere sollevato un Evento senza che avvenga contestualmente un passaggio di dati.
Pertanto nella dichiarazione dell'Evento non sarà previsto alcun parametro formale.
Event evento Public Sub Form_Open() ' Solleva il solo semplice Evento senza passaggio di dati: Raise evento End Public Sub Form_evento() Print "Evento sollevato !" End
Impossibilità di un "Modulo" di sollevare un proprio Evento
L'uso dell'istruzione Event non può avvenire all'interno di un "Modulo", non essendo capace il "Modulo" di sollevare un proprio Evento.
Ricordiamo che soltanto la Classe è capace di avere un Evento come propria risorsa, e quindi di sollevarlo.
Il "Modulo" è, però, capace mediante una propria routine Risponditore di intercettare un Evento appartenente e sollevato in una Classe.
A tal riguardo mostriamo un esempio, nel quale avremo il Modulo principale con il seguente codice:
Public Sub Main() Module1.Avvia() End
che invoca una Procedura posta in un "Modulo" secondario, chiamato Module1.module, avente il seguente codice:
Public cl1 As Class1 Public Sub Avvia() cl1 = New Class1 As "Class1" cl1.ClasseSecondaria() End Public Sub Class1_Evento(s As String) Print s End
Come si può notare, tale "Modulo" secondario dichiara e istanzia una Classe secondaria, chiamata Class1.class con il codice che segue, invocandone altresì una Procedura contenente l'istruzione Raise:
Event Evento(s As String) Public Procedure ClasseSecondaria() Dim b As Byte For b = 1 To 20 If b == 10 Then Raise Evento("Evento sollevato dopo " & CStr(b) & " cicli !") Next End
La Classe solleva il proprio Evento che sarà intercettato nella sub-routine "Class1_Evento()" del "Modulo" secondario Module1.module.
Passare una Struttura con Event
Riguardo a tale argomento si rinvia alla lettura della seguente pagina: Passare una Struttura con Event
Interruzione di un Evento
Per interrompere, o comunque impedire la sollevazione di un determinato evento, è possibile utilizzare il comando Stop innanzi alla parola chiave Event.
Esempio di interruzione dell'evento chiusura del Form:
Public Sub Form_Close() If Message.Question("Chiudo?","Si","No") = 2 Then Stop Event End
Come è possibile notare, il comando Stop non disabilita né blocca il Controllo, semplicemente interrompe la sollevazione del previsto Evento.
Note
[1] L'Evento di una Classe è un Metodo che non viene invocato da alcuna chiamata di funzione, ma che si attiva autonomamente all'inverarsi di un presupposto previsto dal codice sorgente della Classe medesima.
[2] La creazione di un "Gruppo di Eventi" fa riferimento a una sub-routine, e in particolare a un Evento al quale fanno riferimento due o più Oggetti.
Lo scopo dell'attribuzione di più Oggetti a un unico "Gruppo di Eventi" è quello di adottare una scorciatoia per usare un solo Nome comune per identificare quell'Insieme di Oggetti che fanno riferimento a quello specifico Evento.
L'istruzione LAST restituisce l'Oggetto, fra tutti quelli appartenenti al "Gruppo di Eventi", che ha sollevato l'Evento indicato nella dichiarazione della sub-routine.
[3] Vedere al riguardo anche le seguenti pagine: