Ir al contenido


Foto

Ejecutar el contenido de una variable


  • Por favor identifícate para responder
11 respuestas en este tema

#1 Irwin

Irwin

    Newbie

  • Miembros
  • Pip
  • 3 mensajes

Escrito 18 octubre 2014 - 12:17

Saludos amigos, espero puedan ayudarme en este tema.

Quiero hacer una función que se encargue de abrir los formularios que voy necesitando en mi aplicación pero me encontré con e siguiente problema.

Le quiero pasar como parámetro el nombre de la variable que heredará el form y el nombre de la clase form:

Ejemplo:



delphi
  1. function abrir_form(lcNombreForm: String; lcNombreClase: String):boolean;
  2. var
  3.   lcNombreForm: lcNombreClase;
  4. begin
  5.     lcNombreForm := lcNombreClase.create(Application);
  6.     lcNombreForm.ShowModal;
  7.     Result := True;
  8. end;



Entre otros detalles esto es basicamente lo que hará la función. Lo que quiero es que en VAR se ejecute el contenido de la variable lcNombreForm al igual que en la asignación lcNombreClase.

Muchas gracias!
  • 0

#2 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 18 octubre 2014 - 01:09

Quizás te pueda servir de algo:

http://stackoverflow...t-type-is-a-var



delphi
  1. function abrir_form(lcNombreForm: String; lcNombreClase: String):boolean;
  2. var
  3.   lcNombreForm: lcNombreClase;



Hasta donde sé, no es posible, Delphi es fuertemente tipado y además no es interpretado sino que se compila. Por lo que no sería posible asignar un tipo de esta manera.

Saludos

  • 0

#3 Irwin

Irwin

    Newbie

  • Miembros
  • Pip
  • 3 mensajes

Escrito 18 octubre 2014 - 01:13

Vaya!

Voy a revisar el hilo que me indicas a ver que consigo, seguiré buscando porque pienso que de algun modo se podría realizar esta acción.

Saludos!
  • 0

#4 Héctor Randolph

Héctor Randolph

    501st Legion

  • Moderadores
  • PipPipPip
  • 664 mensajes
  • LocationMéxico

Escrito 18 octubre 2014 - 02:44

Hola Irwin

El problema que planteas se puede resolver a tráves del patrón de diseño Factory o Fábrica.

Busca información acerca de este patrón de diseño.

Aquí te dejo un enlace a un documento que habla de este tema en particular con ejemplos en Delphi.

Delphi OOP part 13

Saludos

  • 0

#5 luisgutierrezb

luisgutierrezb

    Advanced Member

  • Miembros
  • PipPipPip
  • 92 mensajes
  • LocationMéxico

Escrito 18 octubre 2014 - 04:46

Si tienes la versión de Del phi que trae código fuente busca la función del application.createform si no,tal vez alguien de por aquí podría ponerla, ahorita no la tengo a la mano como para hacerlo yo

  • 0

#6 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 18 octubre 2014 - 08:57

Hola amigo, aquí te adjunto un ejemplo hecho en Delphi XE3 que puede fácilmente pasarlo a Lazarus.

Lo primero que tienes que hacer es un formulario BASE, este no lo usarás directamente, solo servirá de ancestro del cual heredarás el resto de formularios que quieras que hagan lo mismo, el form BASE no se crea automáticamente al iniciar el programa. Observa el código, lo único raro que tiene es la declaración:  TBaseClass = class of TBase; esto es necesario para lograr lo que quieres, he agregado además una función de clase que crea un form, le da un nombre y lo muestra de forma modal, esta función devuelve un TModalResult (que ya sabemos que es un entero, MrOK, mrCancel, mrYes, etc), esto es más práctico que si devolviera un Booleano, puesto que puedo aprovechar lo que devuelva TModalResult para tomar decisiones.



delphi
  1. interface
  2.  
  3. uses
  4.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  5.   System.Classes, Vcl.Graphics,
  6.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
  7.  
  8. type
  9.   TBase = class(TForm)
  10.   private
  11.     { Private declarations }
  12.   public
  13.  
  14.     class function CrearInstancia(Nombre: string; AOwner: TComponent = nil)
  15.       : TModalResult;
  16.   end;
  17.  
  18.   TBaseClass = class of TBase;
  19.  
  20. implementation
  21.  
  22. {$R *.dfm}
  23. { TBase }
  24.  
  25. class function TBase.CrearInstancia(Nombre: string; AOwner: TComponent)
  26.   : TModalResult;
  27. begin
  28.   if AOwner = nil then
  29.     AOwner := Application.MainForm;
  30.   with Create(AOwner) do
  31.     try
  32.       name := Nombre;
  33.       Result := ShowModal;
  34.     finally
  35.       Free;
  36.     end;
  37. end;
  38.  
  39. end.



Para el ejemplo que te adjunto he creado el form HEREDERO, que hereda de BASE, este tampoco se crea automáticamente, lo único que he agregado son un par de botones, que en su propiedad ModalResult les he colocado mrOK y mrCancel respectivamente.



delphi
  1. unit UHeredero;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  7.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UBase, Vcl.StdCtrls;
  8.  
  9. type
  10.   THeredero = class(TBase)
  11.     Button1: TButton;
  12.     Button2: TButton;
  13.   private
  14.     { Private declarations }
  15.   public
  16.     { Public declarations }
  17.   end;
  18.  
  19.  
  20.  
  21. implementation
  22.  
  23. {$R *.dfm}
  24.  
  25. end.



Nota que tanto en el form Base como en su heredero he removido la variable global (var Form1: TForm1) que se crea automáticamente, esta no es necesaria.

Y ahora solo falta el form Main desde donde se llaman a los herederos de TBase:



delphi
  1. unit UMain;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7.   System.Classes, Vcl.Graphics,
  8.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UBase, Vcl.StdCtrls;
  9.  
  10. type
  11.   TForm1 = class(TForm)
  12.     Button1: TButton;
  13.     procedure Button1Click(Sender: TObject);
  14.   private
  15.     function CrearForm(nombre: string; SuClase: TBaseClass): Boolean;
  16.   public
  17.     { Public declarations }
  18.   end;
  19.  
  20. var
  21.   Form1: TForm1;
  22.  
  23. implementation
  24.  
  25. {$R *.dfm}
  26.  
  27. uses UHeredero;
  28. { TForm1 }
  29.  
  30. function TForm1.CrearForm(nombre: string; SuClase: TBaseClass): Boolean;
  31. begin
  32.   result := SuClase.CrearInstancia(nombre) = mrOk;
  33. end;
  34.  
  35. procedure TForm1.Button1Click(Sender: TObject);
  36. begin
  37.     if CrearForm('Prueba', THeredero) then
  38.     showMessage('Pulsó en Aeptar')
  39.   else
  40.     showMessage('Pulsó en Cancelar')
  41. end;
  42.  
  43. end.



Nota que he agregado la unit UBase en la uses de la interface, luego he creado la función (esta si booleana) con la que es posible llamar a cualquier heredero de TBase,  mostrarlo en forma modal e incluso conocer si pulsó  en aceptar(mrOk) o en cancelar (mrCancel).

Por último un procedimiento en un botón para crear una instancia de THeredero.

Saludos.


  • 0

#7 Irwin

Irwin

    Newbie

  • Miembros
  • Pip
  • 3 mensajes

Escrito 20 octubre 2014 - 03:24

Gracias Wilson,

Voy a implementar el código y a relizar pruebas a ver como funciona.

Saludos a todos!
  • 0

#8 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 20 octubre 2014 - 06:59

Si hay un patrón que reconozco a kilómetros de distancia es Fábrica, también llamado Factoría. O para ser más cool en su nombre original en inglés: Factory. Me lo he estudiado tanto y por tanto tiempo que ya me sale instantáneo.

Como ha propuesto Héctor Randolph, el patrón aplica a estos tipos de casos. El enfoque de Wilson es más que interesante, y seguro que funciona. Pero como yo ando siempre disfrazado del Hoplita con mi espada UML y el escudo Patrones propongo seguir la sintonía de Hector y emplear Fábrica.  :D

Hay variadas maneras de encarar al patrón. Y admito que el estilo que he aprendido del maestro roman es uno de los mejores que he visto. Voy a imitarlo:

1) En una unidad UFactory dispondremos una variable de tipo TStringList que hará de fábrica:



delphi
  1. var
  2.   Factory: TStringList;



Como tal será nuestro punto de acceso para poder crear los diferentes forms (para este caso. El patrón es general y aplica a cualquier grupo de objetos a crear).

2) Esta variable será de acceso "global" y actuará de Singleton. Por tanto agregamos las secciones Initialization y Finalization a la Unit para definir su tiempo de vida:



delphi
  1. Initilization
  2. Factory := TStringList.Create;
  3.  
  4. Finalization
  5. Factory.Free;



3) Ya tenemos nuestra fábrica. Ahora hay que disponer los productos que va a crear. Primero, todos estos forms van a heredar de uno base. Así que comencemos con eso:



delphi
  1. type
  2. TFormBase = class(TForm)
  3. ....
  4. end;



4) Ya con esta clase la magia es aprovechar las referencia de clases. Por tanto añadiremos una para esta clase base:



delphi
  1. type
  2. TFormBaseClass = class of TFormBase;



5) Ahora necesitamos una función que haga justamente el trabajo sucio, crear la clase apropiada según la referencia:



delphi
  1. function CreateForm(NameForm: string): TFormBase;
  2. var
  3.   FormClass: TFormBaseClass;
  4.   Idx: integer;
  5. begin
  6.   // Buscamos en la fábrica el form correspondiente por el nombre y aprovechamos la referencia de clase.
  7.   Idx := Factory.IndexOf(NameForm);
  8.   FormClass := TFormClass(Factory.Objects[Idx]);
  9.  
  10.   // Ya con la referencia, creamos una instancia del form correspondiente
  11.   result := FormClass.Create;
  12. end;



6) Para que funcione cada form pensado que se va a heredar del base se va a registrar en la fábrica:

Form Heredado:


delphi
  1. TFormHeredadoX = class(TFormBase)
  2. ...
  3. end;



Nos registramos:


delphi
  1. Factory.AddObject('NombreDadoFormX', TObject(TFormHeredadoX));



Lo ideal es que cada form a heredar esté en su propia unit, por cuestiones de comodidad y limpieza de código. Cuantos más forms se tenga a crear, más código tendrá la Unit UFactory por lo que es mejor dejar a cada form heredado fuera y agregar en su sección Uses a UFactory.
Por "NombreDadoFormX" es el nombre que vamos a pasar en la función CreateForm.

¿Cuándo registrar cada form? Cualquier momento. Aunque para hacerlo fácil quizá sea más apropiado si se destinara la sección Initialization de la clase cliente (la que hará uso de los forms y pedirá a la fábrica que los cree), o Tener un procedimiento RegisterForms que haga esto:



delphi
  1. uses UFactory, UFormHeredado1, ..., UFormHeredadoN;
  2. ...
  3. Factory.AddObject(FormHeredado1, TObject(TFormHeredado1));
  4. //...
  5. Factory.AddObject(FormHeredadoN, TObject(TFormHeredadoN));



Naturalmente se puede disponer en UFactory un método que nos haga el trabajo de registrarlo. y no estar repitiendo trabajo:



delphi
  1. function RegisterForm(FormName: strings; FormClass: TFormBaseClass): integer;
  2. begin
  3.   result := Factory.AddObject(FormName, TObject(FormClass));
  4. end;



Y entonces con este hipotético RegisterForm en lugar de estar buscando por el nombre también podríamos recuperar por el índice.

Ya con esto está la lección dada. Espero que se haya entendido el objetivo. No he probado el código, lo escribí de memoria pero creo que anda. Esta es una de las tantas formas de hacer uso del patrón... "para complicarlo" más se puede disponer de una clase propia TFactory que encapsule dentro de esta un StringList.
La ventaja de esta forma es que es extensible y no se limita a una cierta cantidad de productos posibles a generar. Muy útil cuando hay muchos, pero si son apenas unos pocos quizá sea más directo tener algo directamente como:



delphi
  1. TFactory = class
  2.   private
  3.     FForm1: TFormHeredado1;
  4.     FForm2: TFormHeredado2;
  5.     FFormN: TFormHeredadoN;
  6.   ...
  7. end;


Es decir no manejarse con listas y directamente tener cada form como atributo y entonces el método CreateForm simplemente regresa la instancia en cuestión.

Repito, como he dicho: el patrón se puede usar de mil formas. La idea central es justamente centrar la creación de los objetos en una clase. Luego las clases clientes simplemente le piden a ésta que les regrese el objeto cuando sea necesario.
Ya que ando en modo profe, va pregunta de examen para la comunidad. ¿Que 3 patrones, y/o conceptos, escenciales son los que dan forma al patrón Fábrica?  ;)

Saludos,
  • 0

#9 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 20 octubre 2014 - 07:06

Ya que ando en modo profe, va pregunta de examen para la comunidad. ¿Que 3 patrones, y/o conceptos, escenciales son los que dan forma al patrón Fábrica?  ;)

Saludos,


Si mal no recuerdo uno de ellos es Singleton. :D
  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 20 octubre 2014 - 07:08

Si mal no recuerdo uno de ellos es Singleton. :D

Que pícaro, a ese ya lo di de regalo  :D ¿Cuales otros 2 faltan?

EDITO: Y agrego. Una pregunta más, quizá algo más complicada de responder... Además de estos 3 patrones escenciales o fundamentales, ¿Cuáles otros patrones son a los que "extiende", "generaliza", amplía o modifica sus concepciones?

Saludos,
  • 0

#11 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 21 octubre 2014 - 07:38

El enfoque de Wilson es más que interesante, y seguro que funciona. Pero como yo ando siempre disfrazado del Hoplita con mi espada UML y el escudo Patrones propongo seguir la sintonía de Hector y emplear Fábrica.  :D


Mi respuesta se basó en un enfoque sencillo que diera solución a la inquietud planteada y por supuesto que funciona.
En atención a que el maestro Delphius plantea una solución basada en patrones, tema por demás interesante, y ya entrados en gastos (o como dicen en mi tierra “Mojado el sombrero mojado el c.u.l.o entero”) entro también en sintonía.

Aunque no soy un experto en patrones he intentado adaptar un ejemplo basado en un Frameowrk que a menudo uso en algunos tipos de aplicaciones, que toma en cuenta los planteamientos de Delphius y que satisface la inquietud planteada por el compañero Irwing.

Como en mi primer ejemplo, crearemos un form Base, del cual heredaremos el resto de forms a crear, en la cual agregamos la referencia de clase, un campo privado del tipo TNotifyEvent y redefinimos el destructor, todo esto para facilitar el accionar de la fábrica.


delphi
  1. unit UBaseForm;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7.   System.Classes, Vcl.Graphics,
  8.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
  9.  
  10. type
  11.   TBaseForm = class(TForm)
  12.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  13.   private
  14.     FOnDestroy: TNotifyEvent;
  15.   public
  16.     destructor Destroy; override;
  17.     property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  18.   end;
  19.  
  20.   TBaseFormClass = class of TBaseForm;
  21.  
  22. implementation
  23.  
  24. {$R *.dfm}
  25.  
  26. destructor TBaseForm.Destroy;
  27. begin
  28.   if Assigned(OnDestroy) then
  29.     OnDestroy(self);
  30.   inherited;
  31. end;
  32.  
  33. procedure TBaseForm.FormClose(Sender: TObject; var Action: TCloseAction);
  34. begin
  35.   Action := caFree
  36. end;
  37.  
  38. end.



Posteriormente creamos 2 herederos de TBaseForm para pruebas, lo único que hacemos es implementar la inicialización para registrar el form en la fábrica .



delphi
  1. unit UHeredero1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7.   System.Classes, Vcl.Graphics,
  8.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UBaseForm, UFabrica;
  9.  
  10. type
  11.   THeredero1 = class(TBaseForm)
  12.   private
  13.     { Private declarations }
  14.   public
  15.     { Public declarations }
  16.   end;
  17.  
  18. implementation
  19.  
  20. {$R *.dfm}
  21.  
  22. initialization
  23.  
  24. FormInfoManager.RegisterForm('Heredero1', THeredero1);
  25.  
  26. end.



Posteriormente implementamos la fábrica justo con las bases que expresa el maestro Delphius, solo con algunos pequeños cambios, esta consta básicamente de dos clases TFormInfo que se encarga de obtener y almacenar la información de cada form registrado; y una segunda clase TFormInfoManager que se encarga de la creación, registro y manipulación de los forms.

La unit UFabrica esta codificada con estilo tradicional de la VCL,  los comentarios dan una muy ligera idea de que va cada cosa.



delphi
  1. unit UFabrica;
  2.  
  3. interface
  4.  
  5. uses Classes, Controls, UBaseForm, Dialogs;
  6.  
  7. type
  8.  
  9.   TFormInfo = class // Manipula cada form heredero de TBase
  10.   private
  11.     FFormClass: TBaseFormClass;
  12.     FForm: TBaseForm;
  13.     FName: string;
  14.  
  15.     procedure DoFormDestroy(Sender: TObject);
  16.   protected
  17.  
  18.     procedure CreateForm; // crea una instancia del form
  19.  
  20.     procedure DestroyForm; // destruye instancia
  21.   public
  22.     constructor Create(const AName: string; AFormClass: TBaseFormClass);
  23.     destructor Destroy; override;
  24.  
  25.     procedure Show;
  26.  
  27.     property Form: TBaseForm read FForm;
  28.     property Name: string read FName;
  29.   end;
  30.  
  31.   { Esta clase controla  la creación, manipulación y destrucción de
  32.     objetos  de la clase TFormInfo }
  33.   TFormInfoManager = class
  34.   private
  35.     FFormList: TList;
  36.  
  37.     function GetCount: Integer;
  38.     function GetItem(Index: Integer): TFormInfo;
  39.   public
  40.     constructor Create;
  41.     destructor Destroy; override;
  42.  
  43.     // Devuelve el form por su nombre
  44.     function GetFormInfoByName(const AName: string): TFormInfo;
  45.     // Registra un form en la fábrica
  46.     procedure RegisterForm(const AName: string; AFormClass: TBaseFormClass);
  47.     // Muestra un form
  48.     procedure ShowForm(const AName: string);
  49.  
  50.     // Devuelve el número de forms regsitrados
  51.     property Count: Integer read GetCount;
  52.     property Items[Index: Integer]: TFormInfo read GetItem; default;
  53.   end;
  54.  
  55.   // Devuleve una única instancia  global de TFormInfoManager
  56. function FormInfoManager: TFormInfoManager;
  57.  
  58. implementation
  59.  
  60. uses SysUtils;
  61.  
  62. { TFormInfo }
  63.  
  64. constructor TFormInfo.Create(const AName: string; AFormClass: TBaseFormClass);
  65. begin
  66.   FName := AName;
  67.   FFormClass := AFormClass;
  68. end;
  69.  
  70. destructor TFormInfo.Destroy;
  71. begin
  72.   DestroyForm;
  73.   inherited Destroy;
  74. end;
  75.  
  76. procedure TFormInfo.CreateForm;
  77. begin
  78.   FForm := FFormClass.Create(nil);
  79.   FForm.OnDestroy := DoFormDestroy;
  80. end;
  81.  
  82. procedure TFormInfo.DestroyForm;
  83. begin
  84.   if (Form <> nil) and not(csDestroying in Form.ComponentState) then
  85.   begin
  86.     FForm.Free;
  87.     FForm := nil;
  88.   end;
  89. end;
  90.  
  91. procedure TFormInfo.DoFormDestroy(Sender: TObject);
  92. begin
  93.   ShowMessage('Me voy  - ' + FForm.Name);
  94.   // Prueba de notificación al cerrar- comentar esta línea
  95.   FForm := nil;
  96. end;
  97.  
  98. procedure TFormInfo.Show;
  99. begin
  100.   if Form = nil then
  101.     CreateForm;
  102.  
  103.   Form.ShowModal; // Aquí podría ser solo Show
  104.   // Form.BringToFront      si no fuera modal
  105. end;
  106. // fin de TFormInfo
  107.  
  108.  
  109. { TFormInfoManager }
  110.  
  111. constructor TFormInfoManager.Create;
  112. begin
  113.   FFormList := TList.Create;
  114. end;
  115.  
  116. destructor TFormInfoManager.Destroy;
  117. var
  118.   I: Integer;
  119. begin
  120.   for I := 0 to Count - 1 do
  121.     Items[I].Free;
  122.   FFormList.Free;
  123.   inherited;
  124. end;
  125.  
  126. function TFormInfoManager.GetCount: Integer;
  127. begin
  128.   Result := FFormList.Count;
  129. end;
  130.  
  131. function TFormInfoManager.GetItem(Index: Integer): TFormInfo;
  132. begin
  133.   Result := TFormInfo(FFormList[Index]);
  134. end;
  135.  
  136. function TFormInfoManager.GetFormInfoByName(const AName: string): TFormInfo;
  137. var
  138.   I: Integer;
  139. begin
  140.   Result := nil;
  141.   for I := 0 to Count - 1 do
  142.     if (CompareText(Items[I].Name, AName) = 0) then
  143.     begin
  144.       Result := Items[I];
  145.       break;
  146.     end;
  147. end;
  148.  
  149. procedure TFormInfoManager.RegisterForm(const AName: string;
  150.   AFormClass: TBaseFormClass);
  151. var
  152.   AFormInfo: TFormInfo;
  153. begin
  154.   AFormInfo := GetFormInfoByName(AName);
  155.  
  156.   if (AFormInfo <> nil) then
  157.     raise Exception.CreateFmt('El form "%s" ya existe', [AName]);
  158.   // Creamos un form y lo agregamos a la lista
  159.   AFormInfo := TFormInfo.Create(AName, AFormClass);
  160.   FFormList.Add(AFormInfo);
  161. end;
  162.  
  163. procedure TFormInfoManager.ShowForm(const AName: string);
  164. var
  165.   AFormInfo: TFormInfo;
  166. begin
  167.   // Form por nombre
  168.   AFormInfo := GetFormInfoByName(AName);
  169.  
  170.   if (AFormInfo = nil) then
  171.     raise Exception.CreateFmt('El form "%s" no existe', [AName]);
  172.  
  173.   AFormInfo.Show;
  174. end;
  175.  
  176. // Variable global
  177. var
  178.   FFormInfoManager: TFormInfoManager = nil;
  179.  
  180.   { Cuando esta función es llamada  comprueba si la variable global
  181.     FFormInfoManager ha sido inicializada - si no lo está crea una única
  182.     instacia de TFormInfoManager y lo pasa a la variable.
  183.     Finalmente la función retorna la variable global }
  184. function FormInfoManager: TFormInfoManager;
  185. begin
  186.   if FFormInfoManager = nil then
  187.     FFormInfoManager := TFormInfoManager.Create;
  188.   Result := FFormInfoManager;
  189. end;
  190.  
  191. initialization
  192.  
  193. finalization
  194.  
  195. FFormInfoManager.Free;
  196. FFormInfoManager := nil;
  197.  
  198. end.



Y por último el form principal desde donde vamos a utilizar la fábrica, en este he agregado un TMainMenu y un TListBox para que al iniciar la aplicación estos recojan automáticamente todos los forms  descendientes de TBaseForm en los  que el desarrollador haya inicializado su registro en la fábrica, para esto utiliza los métodos CrearForms y CargarForms que son muy sencillos y fáciles de entender.



delphi
  1. unit UMain;
  2.  
  3. interface
  4.  
  5. uses
  6.   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7.   System.Classes, Vcl.Graphics,
  8.   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UFabrica, Vcl.StdCtrls, Vcl.Menus;
  9.  
  10. type
  11.   TMain = class(TForm)
  12.     MainMenu: TMainMenu;
  13.     Lista: TListBox;
  14.     miVerForm: TMenuItem;
  15.     procedure ListaClick(Sender: TObject);
  16.     procedure MenuItemClick(Sender: TObject);
  17.     procedure FormCreate(Sender: TObject);
  18.   private
  19.     procedure CargarForms;
  20.     procedure CrearForm(const AName: string);
  21.   public
  22.  
  23.   end;
  24.  
  25. var
  26.   Main: TMain;
  27.  
  28. implementation
  29.  
  30. {$R *.dfm}
  31.  
  32. procedure TMain.CargarForms;
  33. var
  34.   I: Integer;
  35.   AMenuItem: TMenuItem;
  36. begin
  37.   // Recorremos el FormInfoManager
  38.   for I := 0 to FormInfoManager.Count - 1 do
  39.   begin
  40.     // Agregamos cada item a la lista
  41.     Lista.Items.Add(FormInfoManager[I].Name);
  42.     // Por cada form agregamos un sub-menu
  43.     AMenuItem := TMenuItem.Create(self);
  44.     miVerForm.Add(AMenuItem);
  45.     AMenuItem.Caption := FormInfoManager[I].Name; //Le pasamos el nombre del form al caption
  46.     // Le pasamos el ínice al tag del menu
  47.     AMenuItem.Tag := I;
  48.     AMenuItem.OnClick := MenuItemClick; // asignamos el manejador de evento
  49.   end;
  50. end;
  51.  
  52. procedure TMain.FormCreate(Sender: TObject);
  53. begin
  54.   CargarForms;
  55. end;
  56.  
  57. procedure TMain.CrearForm(const AName: string);
  58. begin
  59.   FormInfoManager.ShowForm(AName);
  60. end;
  61.  
  62. procedure TMain.ListaClick(Sender: TObject);
  63. begin
  64.   if Lista.ItemIndex < 0 then
  65.     exit;
  66.  
  67.   CrearForm(Lista.Items[Lista.ItemIndex]);
  68. end;
  69.  
  70. procedure TMain.MenuItemClick(Sender: TObject);
  71. begin
  72. // Creamos el form con base en el tag del menú previamente asignado
  73.   CrearForm(Lista.Items[TMenuItem(Sender).Tag]);
  74. end;
  75.  
  76. end.



Note que el form Main jamás se comunica directamente con TbaseForm ni sus herederos, lo hace a través de la fábrica. Y como indicaba el maestro Delphius esto es muy útil cuando hay muchos forms por manipular, basta solamente con declarar la inicialización en cada heredero y la interfaz de usuario estará lista automáticamente.

Este ejemplo es por supuesto susceptible de mejoras que automatice muchas más tareas, pero solo está adaptado para dar respuesta al amigo Irwing.

Un cordial saludo y gracias a Delphius por sus ideas.





  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 21 octubre 2014 - 03:21

Wilson, se agradece el avance y amplación de los conceptos que he dado. Yo tengo una fábrica algo similar a la que haz elaborado, no es para el manejo de forms pero el estilo se mantiene.
A mi me gusta el tema de los patrones, ayudan mucho. Aunque en ocasiones su abuso puede derivar en patronitis. Aquí me conocen por ser bastante cercano al purismo OO.

Quizá en lo que se podría reveer es que sea la fábrica quien libera el producto. En principio el patrón sugiere que se encarga de crearlas, y luego el cliente operar con éstas. La liberación suele recaer en el cliente. Aunque hay diseños de Fábrica, y otras necesidades, que sugieren que sea la propia fábrica quien se encarga de liberar los productos. En estos tipos de fábricas que liberan lo de esperar es una inicialización perezosa. ¿Que es esto? Que cuando el cliente solicita la creación de un producto la fábrica evalúa si ya mantiene una instancia de éste, de no ser así crea un objeto y devuelve su referencia. Entonces cada vez que el cliente invoque a dicho Producto estará recibiendo la misma y única instancia de cada producto.

Yo tengo recopilado material de años de estudio de este patrón. He concebido al menos unas 8 maneras de implementar este elegante patrón. Cada una tiene sus propias características.

Yo recomiendo mucho acercarse al mundo de los patrones. No muerden. Eso si, lleva años dominar los conceptos... aún hay tantos otros que me faltan poner en práctica...

Saludos,
  • 0




IP.Board spam blocked by CleanTalk.