PDA

Ver la Versión Completa : se puede enviar un procedimiento como parametro a otro??


jasmad
26-06-2012, 18:16:37
Hola,

alguien sabe si es posible enviar un procedimiento como parametro de otro por ejemplo:

procedure HacerAlgoYLlamarUnProcedimientoDesconocido(procedimientoDesconocido : procedure);
begin
codigo...
procedimientoDesconocido;//
end;

Neftali [Germán.Estévez]
26-06-2012, 18:25:43
Sí.
Puedes mirar como ejemplo el método Synchronize de la clase TThread.

procedure Synchronize(Method: TThreadMethod);

Si miras los ejemplos sobre threads del FTP (http://terawiki.clubdelphi.com/Delphi/Ejemplos/), verás varias de estas llamadas.

roman
26-06-2012, 19:38:23
En el caso que comenta Neftali, el parámetro es un método. También puedes pasar procedimientos regulares como parámetros a otro procedimiento pero tienes que declarar un tipo de datos para ello. Es decir, no puedes usar directamente la palabra reservada procedure en la declaración del parámetro.

Aquí un ejemplo:


type
TProcDesconocido = procedure;

procedure HazAlgo(Proc: TProcDesconocido);
begin
Proc;
end;

procedure Saluda;
begin
ShowMessage('Hola');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
HazAlgo(Saluda);
end;


El tipo procedure puede también tener parámetros:


type
TProcDesconocido = procedure (S: String);

procedure HazAlgo(Proc: TProcDesconocido);
begin
Proc('mundo');
end;

procedure Saluda(S: String);
begin
ShowMessage('Hola ' + S);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
HazAlgo(Saluda);
end;


// Saludos

mamcx
26-06-2012, 19:43:27
Tambien se puede usar metodos anonimos:

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/anonymousmethods_xml.html

function MakeAdder(y: Integer): TFuncOfInt;
begin
Result := { start anonymous method } function(x: Integer)
begin
Result := x + y;
end; { end anonymous method }
end;

Chris
26-06-2012, 21:08:28
Tambien se puede usar metodos anonimos:

Pero sino me equivoco, estos están solamente disponibles a partir de D2009.

jasmad
12-07-2012, 19:27:40
perdon por la respuesta tardia
gracias por sus respuestas que me han servido de mucho
lo que me parecio muy interezante fue lo del
Synchronize(Method: TThreadMethod)
que menciono Neftali y estoy planeando implementar pero no se donde llamarlo
sera en el execute del thread ?
lo que quiero es implementar una clase thread que envie en un hilo un conjunto de instrucciones y ejecute un dataset.post o dataset.append y veo que el Synchronize puede ayudar a ejecutar el post sin saltarse algun paso que bote la aplicacion como un dataset.commit que se ejecute en el hilo principal sin haber ejecutado el post que esta en el hilo aparte,
no se si me explico :)

Neftali [Germán.Estévez]
13-07-2012, 10:37:22
que menciono Neftali y estoy planeando implementar pero no se donde llamarlo
sera en el execute del thread ?

No normal es que esté en el Execute, si.
Piensa que cuando en el thread debes acceder a un elemento/objeto que no pertenece al thread, como por ejemplo los componentes de la VCL que están definidos fuera (la VCL no es Thread-safe) debes hacerlo llamando a este método.

Ten en cuenta que si te pasas el tiempo del Thread lamando a Synchronize, el resultado será como si no utilizaras el thread. ;)

jasmad
13-07-2012, 22:41:37
creo que te entiendo,
si tengo una clase que hereda a tthread tengo que hacer el llamado de synchronize en el execute
algo asi:

procedure TPublisher.Execute;
begin
try
if(Self.tabla.State in dsEditModes)then begin
Synchronize(@Self.tabla.Post);
end;
except
on e:exception do handleException(e);
end;
end;

y en una funcion que guarde los cambios del dataset
crear una instancia y llamarlo antes del commit
algo asi:

procedure TdmConexionDB.aceptarCambiosDataSet(var dataset: TIBCTable);
var
posteador:TPublisher;
bm:string;
begin
activarTransaccion;
try
try
bm:=dataset.Bookmark;
//la idea es que con el synchronize se ejecute el post antes del commit porque el programa se caeria
//pero que corra en otro hilo para que no se pegue la aplicacion
posteador:=TPublisher.Create(dataset);//esta linea ejecuta en un hilo aparte el codigo que se encuentra en el execute de TPublisher
transacciones.CommitRetaining;
except
on e: Exception do
begin
transacciones.RollbackRetaining;
MessageDlg('Error '+e.ToString,'aceptarCambiosDataSet ' + dataset.Name + #13#10 + e.Message,mtError, [mbOK], 0);
end;
end;
finally
dataset.Bookmark:=bm;
end;
end;

yo lo entendi asi pero si me equivoco en algo te agradeceria que me corrigieras

gracias

belpab
27-03-2014, 16:39:02
Hola a todos.

Estoy intentando seguir los pasos que me dice Roman (http://www.clubdelphi.com/foros/showpost.php?p=436063&postcount=3) y no consigo pasar un procedimiento por parámetros a otro.

Os explico lo que quiero hacer y me comentáis si veis que estoy haciendo mal.

intento hacer un procedimiento que cree una botonera de TPV pero queme sirva para cualquier tabla.

procedure TForm1.cargararticulos(Pagina, filas, columnas: Integer;panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido);

este procedimiento crea la botonera con el cliendataset que se le pasa ( parámetro “tabla”) en el tscrollbox que se le pasa ( parámetro “panel” ) y quiero asignarle al evento click de cada botón un procedimiento ( parámetro “proc”).

para ello me he creado un tipo “TProcDesconocido” así:

TProcDesconocido = procedure (SENDER: TObject);

y me he definido el procedimiento “PonClickArticulos”

procedure PonClickArticulos(Sender: TObject);

que hace lo que yo quiero asignar al evento click y que paso al procedimiento “cargararticulos” en el parámetro “proc”.

Quedaría algo así


type
TProcDesconocido = procedure (SENDER: TObject);


private
procedure PonClickArticulos(Sender: TObject);
procedure CargarArticulos(Pagina, filas, columnas: Integer;
panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido );


procedure TForm1.PonClickArticulos(Sender: TObject);
begin

End;

procedure TForm1.cargararticulos(Pagina, filas, columnas: Integer;panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido);
var
Boton: tspeedbutton;
begin

Boton:= TSpeedButton.Create(Self);
Boton.OnClick:= Proc;

end;



procedure TForm1.button1Click(Sender: TObject);
begin


CargarArticulos(p,f,c,scrollBArticulos,TablaArticulos,PonClickArticulos);
end;




y al compilar me devuelve este error

[DCC Error] principal.pas(218): E2009 Incompatible types: 'method pointer and regular procedure'

alguien me puede decir que estoy haciendo mal...

Un saludo y gracias de antemano.

belpab
27-03-2014, 19:07:30
Hola a todos.

Estoy intentando seguir los pasos que me dice Roman y no consigo pasar un procedimiento por parámetros a otro.

Os explico lo que quiero hacer y me comentáis si veis que estoy haciendo mal.

intento hacer un procedimiento que cree una botonera de TPV pero queme sirva para cualquier tabla.


procedure TForm1.cargararticulos(Pagina, filas, columnas: Integer;panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido);

este procedimiento crea la botonera con el cliendataset que se le pasa ( parámetro “tabla”) en el tscrollbox que se le pasa ( parámetro “panel” ) y quiero asignarle al evento click de cada botón un procedimiento ( parámetro “proc”).

para ello me he creado un tipo “TProcDesconocido” así:


TProcDesconocido = procedure (SENDER: TObject);

y me he definido el procedimiento “PonClickArticulos”


procedure PonClickArticulos(Sender: TObject);

que hace lo que yo quiero asignar al evento click y que paso al procedimiento “cargararticulos” en el parámetro “proc”.

Quedaría algo así

type
TProcDesconocido = procedure (SENDER: TObject);


private
procedure PonClickArticulos(Sender: TObject);
procedure CargarArticulos(Pagina, filas, columnas: Integer;
panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido );


procedure TForm1.PonClickArticulos(Sender: TObject);
begin

End;

procedure TForm1.cargararticulos(Pagina, filas, columnas: Integer;panel : tscrollbox; tabla : tclientdataset;proc : TProcDesconocido);
var
Boton: tspeedbutton;
begin

Boton:= TSpeedButton.Create(Self);
Boton.OnClick:= Proc;

end;



procedure TForm1.button1Click(Sender: TObject);
begin


CargarArticulos(p,f,c,scrollBArticulos,TablaArticulos,PonClickArticulos);
end;


y al compilar me devuelve este error

[DCC Error] principal.pas(218): E2009 Incompatible types: 'method pointer and regular procedure'

alguien me puede decir que estoy haciendo mal...

Un saludo y gracias de antemano.

belpab
27-03-2014, 19:09:54
lo paso a este hilo (http://www.clubdelphi.com/foros/showthread.php?t=79333). Por error abri uno nuevo cuando queria seguir el hilo

Chris
27-03-2014, 19:41:56
Lo que sucede es que una instancia de TProcDesconocido debe ser un procedimiento independiente o desconocido, que no forme parte de ninguna clase u objeto. Tú estás pasando lo que se conoce como "Procedure of Object", un procedimiento de objeto. Es por eso del error de "Tipos incompatibles".

PonClickArticulos al ser parte de la clase TForm1 viene a ser un Procedure of Object. Para que tu código compile mejor utiliza la clase TNotifyEvent (Ya definida por Delphi por su popularidad) en el parámetro proc del procedimiento CargarArticulos.:



private
procedure PonClickArticulos(Sender: TObject);
procedure CargarArticulos(Pagina, filas, columnas: Integer;
panel : tscrollbox; tabla : tclientdataset;proc: TNotifyEvent );


procedure TForm1.PonClickArticulos(Sender: TObject);
begin

End;

procedure TForm1.cargararticulos(Pagina, filas, columnas: Integer;panel : tscrollbox; tabla : tclientdataset;proc: TNotifyEvent);
var
Boton: tspeedbutton;
begin

Boton:= TSpeedButton.Create(Self);
Boton.OnClick:= Proc;

end;



procedure TForm1.button1Click(Sender: TObject);
begin


CargarArticulos(p,f,c,scrollBArticulos,TablaArticulos,PonClickArticulos);
end;

ecfisa
28-03-2014, 04:35:05
Hola belpab.
lo paso a este hilo (http://www.clubdelphi.com/foros/showthread.php?t=79333). Por error abri uno nuevo cuando queria seguir el hilo
No te preocupes, combiné ambos hilos en el inicial.

Saludos :)

belpab
28-03-2014, 09:57:38
Ok muchas gracias ecfisa.

Funciona perfectamente Chirs muchas gracias a ti tambien. No conocía esa clase. De momento funciona perfectamente dentro de la unit del formulario. Voy a probar a sacarla a otra unit que tengo de procedimientos para llamarla desde cualquier parte del programa. a ver que tal se me da. aunque me temo que me dará problemas al usar controles visuales como el speedbutton.

Muchísimas gracias a todos. Como siempre me ha sido de gran ayuda este Maravilloso foro del que tanto he aprendido.