Newsgroup: it.comp.lang.delphi
Titolo: Procedura come variabile

Salve ragazzi, ho un problema (come sempre), vorrei passare una 
procedura come variabile
[..stralcio di codice..]
 
	 Tasto := Tbutton.Create(self);
          Tasto.parent := self;
          Tasto.Align := alTop;
          Tasto.Caption := Caption;
          Tasto.onClick := Rifprocedura;
          Tasto.Visible := true;
          Tasto.Height := 20;
          Tasto.Width := 20;
          Tasto.Tag := 0;
          Tasto.Images := ListaImmagini;
          Tasto.ImageIndex := 6;
[..Fine Stralcio di codice..]
questo codice viene generato da una chiamata ad una procedura dove ho 
inserito fra le variabili "RifProcedura : Tprocedure"
ma genera errore
[DCC Error] GestioneForm.pas(872): E2009 Incompatible types: 'method 
pointer and regular procedure'
ovviamente (credo) dovrebbe essere normale perchï¿œ si dovrebbe dichiarare 
na cosa tipo RifProcedura(Sender : Tobject) : Tprocedure, solo che mi 
sono arenato completamente...
grazie per eventuali aiuti :)

 grazie per eventuali aiuti :)
-- 
http://www.evilripper.net
http://www.flickr.com/photos/evilripper/

 grazie per eventuali aiuti :)
vediamo se ho capito .. tu hai :
Procedure creatasto(top,left: Integer; Rifprocedura:Qualcosa)
Var tasto: tbutton;
begin
  Tasto := Tbutton.Create(self);
  Tasto.parent := self;
  Tasto.top := top;
  Tasto.left := left;
  Tasto.onClick := Rifprocedura;
....
end;
la quale viene chiamata con: creatasto(10,20,'tastoclick');
....
Devi definire il tipo di metodo da assegnare al tuo onclick che credo 
sia il tipo standard (TNotifyEvent)
type
   TPremitasto = TNotifyEvent;
...
e prima di chiamare la crea tasto andare a definire nel record "TMethod" 
la procedura da passare all'evento Onclick
Var
     OnClickBt:TMethod;
begin
   OnClickBt.Code := Self.MethodAddress ('Rifprocedura');
   OnClickBt.Data := Self;
a questo punto la chiamata a creatasto viene cosi' modificata
   creatasto(10,20,OnClickBt);
e di conseguenza la creatasto
procedure creatasto(top,left: Integer; oFunz: TMethod);
Var obt: Tbutton;
begin
   obt := Tbutton.Create(self);
   obt.Parent := self;
   obt.Top := 10;
   obt.Left := 100;
   if Assigned(oFunz.Code) then  <-- per sicurezza
      obt.OnClick := TPremitasto(oFunz);
all'evento obt.OnClick viene assegnata la procedura "Rifprocedura" che è 
definita nel modo classico: procedure Rifprocedura(Sender: TObject);
^_Goblin_^
-- 
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/

 [...]
Ti basta una ricerca per individuare indicazioni utili su come 
dichiarare un nuovo tipo di procedura da specificare come parametro o 
memorizzare in una variabile.
Un esempio lo trovi qui:
http://www.delphibasics.co.uk/RTL.asp?Name=Procedure
Se hai Delphi 2009 (o successiva), puoi fare uso anche degli "anonymous 
methods".
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

           Tasto.parent := self;
Non ho letto il resto del post, al quale ti hanno gi� risposto, ma un
TButton 
(o un qualsiasi componente visuale) come parent di se stesso mi lascia 
perplesso.
Ciao
ACSH
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 perplesso.
Probabilmente si tratta di un metodo inserito in un Form, quindi Self � 
corretto in quel caso.


4r4g0rn At Work ha scritto:

il mio problema ï¿œ che la procedura di creazione tasto viene chiamata per 
creare diversi tasti e quindi per ogni tasto c'ï¿œ una procedura diversa 
da chiamare, da qui avevo pensato di usare una variabile di tipo 
Tprocedure solo che non funziona...

 
Allora ho fatto come indicato da te e in una form creata a design time 
tutto perfetto, solo che il progetto al quale sto lavorando fa tutto in 
runtime quindi la form ï¿œ creata a runtime e le procedure sono contenute 
in una unit, come faccio ad assegnargli una procedura contenuta nella unit?
grazie ancora :)

 
Ciao Marco, ho letto il link ma ci ho capito poco, devo darci 
un'occhiata con calma, comunque si uso delphi 2009
grazie :)

 
l'esempio era limitato ad una form(per semplificare il tutto), quindi il 
self � riferito alla form stessa, il progetto � in realt� pi� complesso 
e lavora tutto a runtime � ovvio che un oggetto creato a runtime deve 
avere il parent settato o alla form o al suo contenitore ;)

 grazie ancora :)
La prima cosa che mi viene in mente è utilizzare l'ereditarietà di 
delphi e far derivare tutte le tue form da un unica form base e i vari 
onclick scriverli nella form base, poi trasformare in una function il 
ritorno del TMethod che va a cercare il click nella classe base
qualcosa del tipo:
Var
     OnClickBt:TMethod;
begin
   OnClickBt := AttachBt('ClickMyButton');
la function AttachBt è definita in classe base e ritorna il metodo cercato.
ma non saprei dirti se funziona
Invece sarei curioso di implementare i "anonymous methods", come dice 
Marco.


 ma non saprei dirti se funziona
Ed hai ricostruito a mano il polimorfismo. 
A che pro?


 in una unit, come faccio ad assegnargli una procedura contenuta nella unit?
E' un'esigenza un po' strana e forse perch� non molto chiara. Che vuoi
dire con "le procedure sono contenute in una unit"?? Le form, prima di
essere create a runtime, vengono costruite a design-time. Assegna gli
eventi legati ai bottoni a design-time e quindi cera la form a run-time.


 
cerco di spiegarmi meglio, ho creato una superclasse TPippo che in 
pratica crea a runtime tutto form, dbedit, dbcheck, pulsanti modifica 
inserimento etc..., il problema mi nasce sulle stampe perch� in ogni 
form che creo potrei avere la possibilit� di stampe diverse o di creare 
pulsanti che facciano ad esempio un filtro. al che, creata la procedura 
per creare i pulsanti devo assegnare ad ogni pulsante una procedura che 
faccia quello per cui nasce il pulsante. spero di essere stato chiaro.
esempio
CreaForm
		//crea tutta la form tasti standard compresi
creaTasto
		//crea un tasto non standard che vada a fare cose ma ovviamente devo 
dirgli cosa fare
saluti e grazie per la pazienza :)
 


Se in una form crei "al volo" alcuni componenti e ad essi vuoi assegnare 
i vari eventi "Onclick" a seconda delle tue esigenze, che strada seguire ?
Una via potrebbe essere quella di passare l'evento onclick come stringa, 
quindi decodificarlo ed assegnarlo allo specifico componente.
Una seconda strada è sapere in anticipo in base al componente l'evento 
onclick a cui è associato e assegnarlo.


 i vari eventi "Onclick" a seconda delle tue esigenze, che strada seguire ?
E se voglio andare sulla luna con un piede legato dietro la schiena?
Il problema �: perch� avere un'esigenza del genere? se si ha un'esigenza
del genere vuol dire che c'� qualcosa che non va nel disegno
dell'applicazione. Se si necessita di assegnare al volo degli eventi
OnClick nel modo che indichi, vuol dire che non si sa bene che ruolo
assegnare a quei bottoni, tanto per fare un esempio.


 pulsanti che facciano ad esempio un filtro. 
Non va bene.
Questo requisito si soddisfa con la Visual Form Inheritance. Costruisci
una form base che incorpori le funzioni minime comuni e poi la specializzi
ereditando ciascuna form specifica. Cerca di sfruttare le potenzialit� di
un RAD.


 
giusto per chiarezza, non va bene fare classi per creare oggetti 
visuali? e gli OOP allora?


A volte la teoria si discosta molto dalla pratica .. :(
cmq la domanda principale rimane invariata :
Se in una form crei "al volo" alcuni componenti e ad essi vuoi assegnare
vari eventi "Onclick" a seconda delle tue esigenze, che strada seguire ?
Non � detto che ci sia una falla nel disegno del progetto, (ovviamente 
non mi ritengo infallibile) su un progetto ho usato appunto 
l'assegnazione dinamica degli eventi onclick letti da una tabella e 
scritti in un file script caricato a run time, in questo modo senza 
ricompilare il programma ma distribuendo solo il file di script, e un 
update alla tabella.
^_Goblin_^

 vari eventi "Onclick" a seconda delle tue esigenze, che strada seguire ?
E la risposta rimane invariata. Nel contesto specifico, creare una
superclasse che preveda di costruire il mondo intero � una soluzione
SBAGLIATA. Non � sbagliato, in generale, assegnare degli OnClick a
run-time, � sbagliato applicare questa tecnica nel modo in cui suggerisci
tu.
Il problema dell'OP si risolve diversamente, in maniera "pulita".


 e gli OOP allora?
Non capisco questa domanda. Spiega che intendi. *LA* OOP � la
programmazione orientata agli oggetti (usare i form, ereditare e
specializzare significa proprio usare le caratteristiche della OOP). Non
so cosa siano *GLI* OOP.


 
il motivo non lo capisco, non voglio polemizzare, figurati, ma se posso 
creare una classe che mi crei delle anagrafiche in modo automatico cosa 
c'� di sbagliato?
nello specifico la classe crea il necessario per interagire con i dati 
senza cos� dover ogni volta inserire i vari dbedit, pulsanti etc su una 
form, le uniche chiamate che mi occorre gestire a runtime sono eventi 
eccezionali, per esempio se volessi filtrare gli articoli per 
descrizione far� in modo se volessi filtrare l'anagrafica clienti per 
ragione sociale o per numero di telefono farei in un altro...

 c'� di sbagliato?
Perch�, per l'ennesima volta, non si fa cos�. Non � questa la tecnica
corretta. C'� di sbagliato che, architetturalmente, avere una classe che
crea tutte le anagrafiche accentra troppe responsabilit� e conoscenza in
un punto solo. Una corretta programmazione orientata agli oggetti � basata
su una suddivisione della responsabilit� tra classi e sul data hiding. E
inoltre la vera efficacia di Delphi � nel RAD. Il VFI (ereditato in Visual
Studio, peraltro) � uno degli aspetti pi� potenti di questo sistema,
quindi evita la costruzione a run-time e sfruttalo fino all'osso. Devi
costruire, come gi� detto, una form di anagrafica generale, una "root"
form (magari spoglia), e quindi specializzare le singole anagrafiche
ereditando. In questo modo puoi ereditare sia aspetto visuale che
comportamenti.
