Newsgroup: it.comp.lang.delphi
Titolo: Componenti ed eventi: mi manca qualche cosa...

Sto iniziando a studiare la progettazione/realizzazione di componenti con
Delphi 5. A scopo didattico volevo realizzare una cosa semplicissima, il
mio primo componente: un semplice Button cui  vorrei associare di default
un metodo da eseguire al click. In pratica, se "il programmatore" trascina
il componente su una form *e non fa niente altro*, cliccando sul pulsante
dovrebbe essere eseguito automaticamente il metodo associato all’evento
click del componente. Se invece "il programmatore" dopo aver trascinato il
componente sulla form associa all’evento OnClick un metodo, dovrebbe avere
la possibilità di scegliere se il suo codice sovrascrive o "si aggiunge" al
metodo di default. 
Non ci riesco. :-(
Sono riuscito ad associare
l’evento OnClick in fase di run-time utilizzando il metodo CreateWnd, ma
così facendo perdo qualsiasi impostazione del programmatore. Ho provato
allora a scrivere nel componente un metodo associato ad un messaggio di
windows (
p.es
. WM_LBUTTONDOWN) ma oltre al fatto che non ho trovato il
messaggio legato al click, ma solo buttondown e buttonup (che NON sono la
stessa cosa), se l’utente invece di cliccare mi preme Invio con il focus
sul pulsante, non funziona. Inoltre, apparentemente se il programmatore ha
legato un metodo all’evento OnClick, questo viene ignorato in fase di
esecuzione.
Delphi è il terzo linguaggio OOP che utilizzo. Negli altri
due questo banale esercizio l’avevo risolto in meno di un’ora, qui sono due
giorni che ci provo e non ottengo nulla...
Aiutatemi a capire dove
sbaglio, per favore.
BrunoS
--------------------------------
Inviato via 
http://usenet.iol.it

 metodo di default.
Hai provato nel tuo componente a mettere un
    procedure Click; override;
nella definizione della classe del tuo componente e ad una implemetanzione
tipo
procedure MyButton.Click;
begin
 inherited;
 if assigned (Fonclick) then FOnClick(Self)
 else
 begin
  ...
 end;
end;
eventualmente potresti usare una proprietą boolean che dice se l'onclick
deve eseguire il codice standard o quello legato all'evento onclick senza
bisogno di slegarlo...
ciao
Matteo

Matteo
Grazie mille, mi hai comunque dato una grossa mano


 Grazie mille, mi hai comunque dato una grossa mano
Figurati. Spero solo di non aver detto castronerie... ma per quello mi posso
immaginare una bacchettata dal NG :)
Ciao
Matteo

immaginare una
bacchettata dal NG :)
Se passi dalle parti di Arona (NO) ti offro da
bere.


 bere.
Se passi dalle parti di Imola idem ;)
Ciao
Matteo

> [Ri-megacut]
Hai fatto un lavoro enorme, e non metto in dubbio che
funzioni, ma mi sembra strano che non ci sia un metodo piů semplice. Prima
di Delphi, io ho usato PowerBuilder (per poco piů di 6 mesi, giusto il
tempo di darci un'occhiata) e MS Visual FoxPro (per 5 anni). Di
quest'ultimo possiamo discutere se sia o meno un vero linguaggio, ma
sicuramente č OOP (come anche PowerBuilder).
Entrambi implementano quello
che io voglio in modo drammaticamente semplice. Ad esempio con VFP se ho la
classe myButton che ha il metodo/evento Click, se utilizzo l'oggetto in una
form e scrivo (piů o meno):
function myButton1.Click
showmessage('Ciao')
endfunction
ottengo automaticamente una
sovrascrittura dell'evento Click della classe, se invece scrivo:
function myButton1.Click
  Tmybutton::Click       
  showmessage('Ciao')
endfunction
la riga aggiunta rappresenta il richiamo al metodo/evento
della classe progenitrice.
PowerBuilder implementa la stessa medesima
cosa, con una sintassi leggermente diversa (e che non mi ricordo piů, dato
che l'ho vista piů di 5 anni fa), ma sono certo che c'era ed era
analogamente semplice.
In questo senso mi aspettavo che inherited facesse
piů o meno il lavoro della riga aggiunta nel secondo esempio, ma non č
cosě.
Possibile che con Delphi l'unico modo sia quello di fare tutto il
rigiro che hai postato tu?


Ciao BrunoS,
da quello che dici credo di aver capito che sei nuovo a Delphi.
L'esempio che ti faceva Matteo era quello della scrittura di un nuovo
componente (classe) che aveva delle funzionalitą nuove rispetto al
componente TButton originario. L'esempio che fai tu in PB o Visual
foxpro č totalmente diverso (se non sbaglio ;-)) poiche' li tu usavi
semplicemente una istanza di una classe gią creata.
Non capisco inoltre cosa intendi per "la riga aggiunta rappresenta il
richiamo al metodo/evento della classe progenitrice." in riferimento
al Tmybutton::Click   nel seguente pezzo di codice:
function myButton1.Click
  Tmybutton::Click       
  showmessage('Ciao')
endfunction
Ciao, Rocco.

.............
Non ci siamo proprio, non riesco a
spiegarmi. Se mi permettete ci provo con due pezzi di codice Visual FoxPro
semplificato (ho eliminato tutte le parti non significative all'esempio)
spero di farmi capire così:
Questa è la definizione di classe di VFP,
equivalente alla definizione del componente di Delphi (i due sistemi usano
terminologie differenti):
**************************************************
*-- Class:
mybutton
*
DEFINE CLASS mybutton AS commandbutton
  Name = "mybutton"
PROCEDURE Click
    messagebox('Messaggio Componente')
    return
ENDPROC
ENDDEFINE
*-- EndDefine: mybutton
**************************************************
Commento: ho creato
un "componente" derivato dalla classe base Commandbutton (equivalente alla
TButton) ed ho specificato del codice da eseguire al verificarsi
dell'evento click sulle istanze di questa classe.
 
Adesso utilizziamo il
componente:
**************************************************
*--
Class:        myform
*
DEFINE CLASS myform AS form
  ADD OBJECT
mybutton1 AS mybutton WITH 
             Caption = "Solo istanza",
Name = "Mybutton1"
  ADD OBJECT mybutton2 AS mybutton WITH
Caption = "Prima componente poi istanza", 
             Name = "Mybutton2"
ADD OBJECT mybutton3 AS mybutton WITH 
             Caption = "Prima
istanza poi componente",
             Name = "Mybutton3"
  ADD OBJECT
mybutton4 AS mybutton WITH 
             Caption = "Solo Componente",
Name = "Mybutton4"
  PROCEDURE mybutton1.Click
    * solo istanza
messagebox("Messaggio Istanza")
    return
  ENDPROC
  PROCEDURE
mybutton2.Click
    * prima componente poi istanza
    mybutton::Click()
messagebox("Messaggio Istanza")
    return
  ENDPROC
  PROCEDURE
mybutton3.Click
    * prima istanza poi componente
messagebox("Messaggio Istanza")
    myButton::Click()
    return
ENDPROC
  * per "solo componente", non serve codice...
ENDDEFINE
*--
EndDefine: myform
**************************************************
Commento: ho creato una form, vi ho posto 4 istanze della stessa
classe/componente che mi consentono di esemplificare le 4 possibili
combinazioni come da commenti inclusi.
Ora quello che vorrei, è ottenere
qualcosa di altrettanto semplice (vi assicuro che le righe che ho eliminato
sono poche e si riferiscono sopratutto al settaggio delle proprietà
relative a posizione e dimensioni dei vari pulsanti) in Delphi.
Se non
sono riuscito a spiegarmi stavolta, mi arrendo... 
Il bello è che questa
era la domanda semplice, perchè poi ne ho in serbo una che ritenevo più
complessa, e già mi tremano le vene... :-)


 Io vorrei implementare un comportamento di default per il mio componente;
il programmatore che utizza il componente deve essere libero di:
1*) non scrivere nulla, e l'oggetto eredita il comportamento di default
E quale dovrebbe essere il codice di dafault secondo te? Quello standard del
padre o il tuo?? quello standard del padre Tbutton o sù di lì ci deve essere
altrimenti le actione non funzionano più (sempre che non le simuli te col
tuo codice):
  if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <>
@Action.OnExecute) then
    FOnClick(Self)
  else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
    ActionLink.Execute
  else if Assigned(FOnClick) then
    FOnClick(Self);
- scrivere del codice che
*sostituisca* il comportamento di default
sempre il tuo o quello dei padri ancestrali? stesso avvertimento sopra. c'è
il rischio di perdere compatibilità con future Delphi e/o versioni
precedenti se inizi a sovrascrivere e non implementare la VCL di Delphi.
- scrivere del codice che
*integri* il comportamento di default (scegliendo anche in che punto
lanciare il metodo di default).
Dammi qualche info in più perchè non riesco a capire dove vuoi arrivare...
Ciao
Matteo

relative a posizione e dimensioni dei vari pulsanti) in Delphi.
Ora ho capito e credo di poter dire :-(
che in delphi non lo fai cosi' facilmente.
Ciao, Rocco.

essere altrimenti le actione non funzionano piů (sempre
che non le simuli >te col tuo codice):
Qui c'č la chiave del discorso.
Dello strato software di basso livello non mi interessa nemmeno sapere che
esiste. Tutta la logica contenuta nella VCL deve restare immutata e
funzionante.
Io vorrei solo incapsulare del codice in un componente ed
evitare che il programmatore debba richiamare manualmente la/le procedure
incapsulate collegandola/e all'evento in fase di sviluppo. Speravo ci fosse
un modo sul componente per specificare "questa procedura deve essere
associata all'evento X", ed in effetti qualche sistema l'abbiamo trovato,
ma apparentemente ciň non si puň fare senza introdurre alcune pesanti
limitazioni (ne abbiamo discusso nei post precedenti).
Direi che per
ora, l'unica soluzione č quella di incapsulare metodi nel componente senza
associarli a nessun evento e rimandare al programmatore il compito di
associare gli eventi in fase di sviluppo.
Grazie


associare gli eventi in fase di sviluppo.
Questo č giusto ( un evento č un puntatore ad un metodo).
La cosa che intendevi tu sarebbe possibile se un evento puntasse
sempre ad un metodo (definito virtual ed implementato nel padre) e che
questo venisse overraidato dal metodo eventualemente definito
dell'utilizzatore dell'oggetto (forse in italiano questa frase fa un
po schifo, perdonatemi :-)).
Questa soluzione (con i suoi pro e i suoi contro) pero' non apartiene
a Delphi.
Ciao, Rocco.