Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Se puede hacer un array de procedures (https://www.clubdelphi.com/foros/showthread.php?t=57597)

David 21-06-2008 14:09:43

Se puede hacer un array de procedures
 
Hola

Explico el caso, supongamos que tengo un comboBox con el nombre de varias funciones,

HacerBalance
Facturar
ComprobarIvaClientes
CheckEntregas
CheckPedidos

etc....

Si el usuario va seleccionando, por que le conviene dos de ellos ( o los que quiera), se puede hacer un array con los procedure, recorrer el array y que se ejecute el procedure dependiendo de la posición del array recorrido.

Enfin , lo veo un poco enrevesado, pero si existiera algo así seria tremendo.

pcicom 21-06-2008 14:51:50

claro que yes.. pero te convendria mejor del combo un CheckListBox..

Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
begin

   CheckListBox1.Items.Add('PERAS');
   CheckListBox1.Items.Add('MANZANAS');
   CheckListBox1.Items.Add('UVAS');

end;

procedure TForm1.BitBtn1Click(Sender: TObject);
Var i:integer;
begin


   For i:= 0 to CheckListBox1.count -1 do
   begin
      if CheckListBox1.Checked[i] then
      begin
         if CheckListBox1.Items.Strings[i]='PERAS' then peras
         if CheckListBox1.Items.Strings[i]='MANZANAS' then manzanas
         if CheckListBox1.Items.Strings[i]='UVAS' then uvas
      end;
   end;

end;

procedute TForm1.Peras;
begin
   //Tu Codigo
end;
procedure TForm1.Manzanas;
begin
   //Tu Codigo
end;

procedure TForm1.Uvas
begin
   //Tu Codigo
end;


Ufff.........

David 21-06-2008 15:04:32

no, no es lo que busco, primero quiero que sea un comboBox, porque ocupa menos espacio, aunque un comboBox con checks por el momento no estaria mal, pero luego con ese procedimiento no eliges el orden de los procedimientos, el orden siempre puede variar.

Fenareth 21-06-2008 15:17:40

Hola David...

Con el ejemplo que te da pcicom es una base muy buena aun cuando lo quieras implementar con un ComboBox...

En el evento Change del ComboBox sería:

Código Delphi [-]
if ComboBox.Text = 'Peras' then Peras;
if ComboBox.Text = 'Manzanas' then Manzanas;
if ComboBox.Text = 'Uvas' then Uvas;
.
.
.
etc... y así con todos los procedimientos que quieras elaborar...

Saludos :)

coso 21-06-2008 15:27:25

Bueno, estan lo que seria array de procedure of object...

Código Delphi [-]
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    procedure Funcion_1;
    procedure Funcion_2;
    procedure Funcion_3;
    procedure Funcion_4;
    procedure Funcion_5;
    procedure FormActivate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    funciones : array [1..5] of procedure of object;
  end;
var
  Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormActivate(Sender: TObject);
begin
        Funciones[1] := Funcion_1;
        Funciones[2] := Funcion_2;
        Funciones[3] := Funcion_3;
        Funciones[4] := Funcion_4;
        Funciones[5] := Funcion_5;
end;
procedure TForm1.Funcion_1;
begin
        ShowMessage('funcion 1');
end;
procedure TForm1.Funcion_2;
begin
        ShowMessage('funcion 2');
end;
procedure TForm1.Funcion_3;
begin
        ShowMessage('funcion 3');
end;
procedure TForm1.Funcion_4;
begin
        ShowMessage('funcion 4');
end;
procedure TForm1.Funcion_5;
var
        i : integer;
begin
        ShowMessage('Funcion 5 : todas');
        for i := 1 to 4 do
        begin
                Funciones[i];
        end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
        s : string;
begin
        s := (sender as TControl).Name;
        Funciones[strtoint(stringreplace(s,'Button','',[rfReplaceAll,rfIgnoreCase]))];
end;
end.

tiene 5 buttons los cinco asignados el onbuttonclick a Button1Click; (los nombres tienen q ser Button1,Button2, etc...)

en tu caso seria usar

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
begin
     Funciones[ComboBox1.ItemIndex];
end;



saludos

David 21-06-2008 16:13:15

1 Archivos Adjunto(s)
Lo que ha puesto coso es lo que queria, he realizado un pequeño ejemplo que adjunto.

coso 21-06-2008 16:39:07

lo mismo, solo que un poco mas simplificado ...

Código Delphi [-]
unit Main;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Spin;
type
  TForm1 = class(TForm)
    cbFunciones: TComboBox;
    btnAdd: TButton;
    btnEjecutar: TButton;
    spin: TSpinEdit;
    ListBox1: TListBox;
    procedure btnAddClick(Sender: TObject);
    procedure btnEjecutarClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
  private
    { Private declarations }
  public
    origen    : array [0..5] of procedure of object;
    lista     : array [0..100] of procedure of object;
    procedure funcion0;
    procedure funcion1;
    procedure funcion2;
    procedure funcion3;
    procedure funcion4;
    procedure funcion5;
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnAddClick(Sender: TObject);
begin
  if cbFunciones.Text <> '' then
  begin
    ListBox1.Items.Add(cbFunciones.Text);
    lista[spin.value] := Origen[cbFunciones.ItemIndex];
    spin.value := ListBox1.Items.Count;
    btnEjecutar.Enabled := true;
  end;
end;
procedure TForm1.FormActivate(sender : TObject);
begin
        Origen[0] := funcion0;
        Origen[1] := funcion1;
        Origen[2] := funcion2;
        Origen[3] := funcion3;
        Origen[4] := funcion4;
        Origen[5] := funcion5;
end;
procedure TForm1.btnEjecutarClick(Sender: TObject);
var
 i : integer;
begin
    cbFunciones.Enabled := false;
    btnEjecutar.Enabled := false;
 
    for i := 0 to spin.Value - 1 do Lista[i];

    ListBox1.Clear;
    Spin.Value := 0;
    btnAdd.Enabled := true;
    cbFunciones.Enabled := true;
end;
procedure TForm1.funcion0;
begin
  ShowMessage('Ejecutando la función 0');
end;
procedure TForm1.funcion1;
begin
  ShowMessage('Ejecutando la función 1');
end;
procedure TForm1.funcion2;
begin
  ShowMessage('Ejecutando la función 2');
end;
procedure TForm1.funcion3;
begin
  ShowMessage('Ejecutando la función 3');
end;
procedure TForm1.funcion4;
begin
  ShowMessage('Ejecutando la función 4');
end;
procedure TForm1.funcion5;
begin
  ShowMessage('Ejecutando la función 5');
end;

end.
;

saludos :p

PD : seguro que hay tambien alguna manera de hacer
Código Delphi [-]
  ...
  for i := 0 to max_ori do 
    Origen[i] := GetFunctionByName('funcion'+inttostr(i));
  ...
para ya rizar el rizo :D

David 21-06-2008 16:48:41

Bueno he seguido investigando y me he encontrado con un problema.

supongamos esto :

Código Delphi [-]
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, dxCntner, dxEditor, dxExEdtr, dxEdLib, Spin;

type
  TForm1 = class(TForm)
    cbFunciones: TComboBox;
    btnAdd: TButton;
    btnEjecutar: TButton;
    spin: TSpinEdit;
    ListBox1: TListBox;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure btnAddClick(Sender: TObject);
    procedure btnEjecutarClick(Sender: TObject);
  private
    { Private declarations }
  public
    funciones : array of procedure of object;
    metodos : array of array[0..3] of String;
    procedure funcion1(nombre:String);
    procedure funcion2(valor,nombre:String);
    procedure funcion3;
    procedure funcion4(nombre,valor,arg:String);
    procedure funcion5;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnAddClick(Sender: TObject);
begin
  if cbFunciones.Text <> '' then
  begin
    SetLength(metodos,spin.Value+1);
    metodos[spin.Value][0] := cbFunciones.Text;
    metodos[spin.Value][1] := edit1.Text;
    metodos[spin.Value][2] := edit2.Text;
    metodos[spin.Value][3] := edit3.Text;
    spin.Value := spin.Value + 1;
    btnEjecutar.Enabled := true;
    listBox1.Items.Add(cbFunciones.Text);
  end;
end;

procedure TForm1.btnEjecutarClick(Sender: TObject);
var
 i : integer;
begin
  cbFunciones.Enabled := false;

  btnEjecutar.Enabled := false;
  for i:= 0 to high(metodos) do
  begin
    SetLength(funciones,i+1);
   if metodos[i][0] = 'funcion1' then
      funciones[i] := funcion1(metodos[i][1]); //Aquí da error
    if metodos[i][0] = 'funcion2' then
      funciones[i] := funcion2(metodos[i][1],metodos[i][2]); // Aquí tb da Error
    if metodos[i][0] = 'funcion3' then
      funciones[i] := funcion3;
    if metodos[i][0] = 'funcion4' then
      funciones[i] := funcion4(metodos[i][1],metodos[i][2],metodos[i][3]); // Aquí da error
    if metodos[i][0] = 'funcion5' then
      funciones[i] := funcion5;
  end;

  for i:= 0 to high(funciones) do
  begin
    funciones[i];
    application.ProcessMessages;

    spin.Value := spin.Value - 1;

    if i <> high(funciones) then
      sleep(6000);
  end;

  funciones := nil;
  metodos := nil;
  btnAdd.Enabled := true;
  ListBox1.Clear;
  cbFunciones.Enabled := true;
end;

procedure TForm1.funcion1(nombre:String);
begin
  ShowMessage('Ejecutando la función 1:'+nombre);
end;

procedure TForm1.funcion2(valor,nombre:String);
begin
  ShowMessage('Ejecutando la función 2'+valor+' '+nombre);
end;

procedure TForm1.funcion3;
begin
  ShowMessage('Ejecutando la función 3');
end;

procedure TForm1.funcion4(nombre,valor,arg:String);
begin
  ShowMessage('Ejecutando la función 4'+nombre+' '+valor+' '+arg);
end;

procedure TForm1.funcion5;
begin
  ShowMessage('Ejecutando la función 5');
end;

end.

En todos los puntos donde le he pasado un argumento me da este error:

Incompatible types: 'Procedure of object' and 'procedure, untyped pointer or untyped parameter'

coso 21-06-2008 18:10:39

Si, es normal. El array que tu tienes lo has creado para objetos tipo procedure a secas, en tu ultimo codigo estabas intentando meter procedures con argumento alla. Seria como meter un TBitmap en un array de TShapes, por ejemplo. Si lo que quieres es hacer un array con procedures que le mandas argumentos, o con funciones, deberas declararlo de otra manera

Código Delphi [-]
    procedures_sin_nada   : array [0..10] of procedure of object;
    procedures_con_arg    : array [0..10] of procedure (s : string) of object;
    procedures_con_arg_2  : array [0..10] of procedure (a : double; td : TEdit) of object;
    funciones_con_arg     : array [0..10] of function (s : string) : string of object 
    ...

lo que se esta realmente guardando en el array es la direccion de memoria donde se encuentra cargada dicha funcion, su puntero o pointer.

Para tener varios tipos de funciones (con varios tipos y numero de argumentos) lo mejor es crear un solo tipo con una cadena de argumento y luego parsearlos. Ten en cuenta que es trabajoso, al menos hacerlo la primera vez , por lo que quiza no te acabe a salir a cuenta.

Te pongo un ejemplo

Código Delphi [-]
procedure TForm1.Funcion1(s : string);
var 
        sl : TStringList;
        arg_1 : integer;
        arg_2 : double;
        arg_3 : TEdit;
begin
        sl := TstringList.Create;
        sl.commatext := s; // siendo s, por ejemplo s := '3.2 test Edit1';
        
        arg_1 := strtofloat(sl[0]);
        arg_2 := sl[1];
        arg_3 := (FindComponent(sl[2]) as TEdit);
        ...
        sl.free;
end;

PD: en tu codigo, estas usando un array dinamico, esto es, sin indicarle la cantidad de elementos que tiene. No se si se le tiene que asignar o no memoria en este caso, pues es, a lo sumo, un array de enteros. A ver si alguien del foro lo aclara :/

Venga, saludos.

Delphius 21-06-2008 19:32:43

Hola David, disculpa que te pregunte: ¿Van a cambiar mucho esos procedimientos? ¿Puede que en algún momento se agreguen más? ¿Tienen algo en común?

No me convence mucho la idea de tener arrays de procedures. Yo más bien considero que puede ser más indicado emplear una fábrica o Factory. Posiblemente alguna Fabrica abstracta.

Habría que estudiarle un poco la idea pero me parece más indicado y certero tener clases "Productos" y dejar que cada una asuma la responsabilidad de hacer su propio algoritmo. Y luego una Fábrica crea la/s clase/s Productos adecuadas.

Si no se me entiende la idea, te recomiendo la lectura de estos temas:

Wikipedia (Español)
Fábrica (o Factoría) Abstracta
Fábrica (o Factoría)

About.com (Inglés)

Factory Patterns

Por el tema de que se pueda elegir más de una cosa por hacer... habría que ver de que manera hacerlo. Lo más simple es tener un FOR e ir creando y destruyendo los productos que se necesiten:

for cantidad_de_productos hacer:
Crear_producto(¿NombreProducto?)
Producto.Hacer()
LiberarProducto()

No se si se entiende la idea. No se si estás puesto con el tema de clases y el uso de patrones. Pero al menos a mi me parece más adecuado el uso de una Fabrica que estar empleando esos arrays.

Saludos,

coso 21-06-2008 20:24:43

No. Yo creo que lo mejor en tu caso son los arrays, incluso la solucion sencilla de fenareth o pcicom ya te sirven.

saludos.

Delphius 21-06-2008 20:45:04

Cita:

Empezado por coso (Mensaje 295042)
No. Yo creo que lo mejor en tu caso son los arrays, incluso la solucion sencilla de fenareth o pcicom ya te sirven.

saludos.

Puede servir.
Si sólo van a existir pocos métodos a realizar el tener así puede ser viable.

Mas bien yo ofrecí ese punto de vista por lo que estuve viendo a como se estaba llevando el hilo: funciones y procedimientos con o sin parámetros... muchos corchetes...

Imaginate si en vez de esos 4 o 10 son 20.
El código puede resultar un tanto ilegible y engorroso. ¿Y si hay métodos que comparten ciertas similitudes? ¿Y si luego es necesario ampliar las posibilidades?

Y algo que por el momento no se contempla ¿Y si un proceso o actividad necesita obligadamente de una secuencia determinada?

El uso de una fábrica puede facilitar muchas cosas. Por ejemplo, veo que en su ejemplo inicial menciona a CheckEntregas y CheckPedido. ¿Que diferencia a una de otra? ¿Se puede compartir algo en común y aligerar el código?

Para situaciones en donde el código a lo largo del tiempo va a ser estable la manera en que ofrecen sus códigos puede resultar viable.

Pero para situaciones en donde puede llegar a existir código redundante, o bastante similar, en donde no se prevee la cantidad la cantidad de opciones y "productos" a considerar considero que el uso de una Fábrica es más adecuado.

No pretendo imponer mi idea. Mas lo digo para que David analice objetivamente su situación.

Saludos,

coso 21-06-2008 20:46:19

ok. Las discusiones sobre teoria abstracta no me van, puesto que transforman las soluciones en problemas.

saludos.

Delphius 21-06-2008 20:59:19

Cita:

Empezado por coso (Mensaje 295046)
ok. Las discusiones sobre teoria abstracta no me van, puesto que transforman las soluciones en problemas.

saludos.

Hola coso,
Me da un poco de mal sabor la forma en que escribiste:(
Yo ofrecí un punto de vista solo eso.
No se trata de una discusión.

¿Que causan problemas? ¿A que te refieres?

Yo simplemente hago un comentario y doy un punto de vista analítico a la situación pero no por ello va a traer problemas. Es posible que mi punto de vista no sea adecuado y esté equivocado.
Pero no por ello debo mantenerme callado.

Es preferible prepararse y examinar mejor un problema antes de dar un paso.
En ocasiones tener un diseño cerrado es muy favorable, y en otras no.

La elección de una Fabrica tiene sus desventajas, como muchas cosas de la vida, pero no por ello lo constituye una mala elección.

Si he dicho algo malo dime.

Tu y yo no sabemos lo que planea David, el verá y analizará las diversas alternativas y optará por la que le es más favorable.

Espero que tomes a bien mis comentarios.

Saludos,

coso 21-06-2008 21:01:53

ok. Las discusiones sobre teoria abstracta no me van, puesto que transforman las soluciones en problemas.

saludos.

xEsk 22-06-2008 03:06:05

Bajo mi punto de vista, no me ha parecido una discusión sobre "teoría abstracta", sino que ha dado una opción igual que has dado tu :eek: y no hacia falta este segundo mensaje repetido, quizás no sea tu intensión, pero suena a: "cierra la boca, me importa una mierda tu opinión" xD

Saludos.

Fenareth 22-06-2008 03:23:47

Pensé que solo a mi me había sonado a eso... :(

Delphius siempre ha dado sus opiniones basadas en conceptos más profundos, a veces no nos preocupamos en analizar tan en detalle ciertos problemas, mientras nos sirva la respuesta que nos den hasta ahí lo dejamos...

Sus aportaciones son tan valiosas como las tuyas coso y si a David le interesa tomarlas en cuenta qué bien por él. Si no, pues tal vez alguien más que lo lea le interese...

Saludos y aquí no pasa nada... todos tan amiguitos como siempre :)

eduarcol 22-06-2008 03:32:22

Cita:

Empezado por Fenareth (Mensaje 295132)
...
Saludos y aquí no pasa nada... todos tan amiguitos como siempre :)

y ahora, que hacemos con las apuestas que habien en esta pelea?, era la estelar de la noche :D

poliburro 22-06-2008 03:35:40

Cita:

Empezado por eduarcol (Mensaje 295137)
y ahora, que hacemos con las apuestas que habien en esta pelea?, era la estelar de la noche :D


que no la estelar de esta noche eran las ramitas?

Fenareth 22-06-2008 03:36:32

Cita:

Empezado por eduarcol (Mensaje 295137)
y ahora, que hacemos con las apuestas que habien en esta pelea?, era la estelar de la noche :D

Jajajaja, tan amiguitos abajo del ring porque no debemos perder el glamour... Pero arriba que se den con todo y que corran las apuestas... !!! :D :D

Es una bromita, viva la paz :o :p


La franja horaria es GMT +2. Ahora son las 15:09:25.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi