Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Crear varios objetos de un mismo tipo (https://www.clubdelphi.com/foros/showthread.php?t=83146)

jocaro 16-05-2013 13:15:09

Crear varios objetos de un mismo tipo
 
Hola

En mi aplicación tengo un botón que, cada vez que se pulsa, genera un nuevo objeto con una determinada información. El código es el siguiente

Código Delphi [-]

procedure TSDIAppForm.VentanaNotaClick(Sender: TObject);
var
  sVacio: String;
  tnNodAux: TTreeNode;
  Stream: TStream;
  iLonMat: Integer;
begin

  iLonMat := length(agVentNot);
  SetLength(agVentNot, iLonMat + 1 );

  { Creación de form para ver una nota (se crea un form cada vez que se
    selecciona una nota) }
  agVentNot[iLonMat] := TFrmVerNota.Create(Application);

  { Escribir camino de la nota en cabecera de la ventana }
  tnNodAux := ArbolElementos.Selected;
  agVentNot[iLonMat].Caption := CaminoArbolElementos( tnNodAux, sVacio );

  { Cargar nota en visor TRichView }
  Stream := FrmBasDat.TablaNotas.CreateBlobStream(FrmBasDat.TablaNotas.FieldByName('DesNot'), bmRead);
  agVentNot[iLonMat].RVVerNota.LoadRVFFromStream(Stream);
  agVentNot[iLonMat].RVVerNota.Format;

  agVentNot[iLonMat].Visible := True;

  Stream.Free;

end;


unit VerNota;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,RVScroll, RichView, RVEdit, DBRV, RVStyle,
  RVStr;
type
  TFrmVerNota = class(TForm)
    RVVerNota: TRichView;
    EstiloVerNota: TRVStyle;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FrmVerNota: TFrmVerNota;

implementation

uses
  BasDat;

{$R *.dfm}

end.

Mis dudas son las siguientes:

¿Existe una forma mas elegante de hacerlo que asignándolo a una matriz?
¿Se podría hacer con un objectlist, por ejemplo? En ese caso, ¿como podría ver las propiedades, variables, etc. del objeto, utilizados en el código anterior, ya que lo he intentado y no lo consigo?

¿Al cerrar cualquiera de los forms generados, mediante el aspa de la parte superior derecha, se libera el objeto de éste o hay que mandar un close en el evento FormClose?

Gracias por vuestra atención

maeyanes 16-05-2013 16:04:24

Hola...

Como bien comentas, puedes hacer uso de la clase TObjectList:

Código Delphi [-]
var
  NoteForm: TFrmVerNota;

begin
  NoteForm := TFrmVerNota.Create(nil);
  // Usas la variable NoteForm para asignar propiedades. Ej:
  NoteForm.Caption := 'Something';
  // FNotes sería un objecto de tipo TObjectList
  FNotes.Add(NoteForm)
end;

// Para referenciar un objeto guardado en el TObjectList:
var
  NoteForm: TFrmVerNota;

begin
  NoteForm := FNotes[i] as TFrmVerNota;
  
  // O de esta forma:
  NoteForm := TFrmVerNota(FNotes[i])
end;

Ahora, si usas Delphi 2010 o superior, podrías usar la clase genérica TObjectList<T>:

Código Delphi [-]
uses
  Generics.Collections;

// Se declara y crea un objecto del tipo TObjectList< TFrmVerNota >:
  FNotes := TObjectList< TFrmVerNota > .Create;

// Se usa este objecto en tu método:
FNotes.Add(TFrmVerNota.Create(nil));

// Al ser un TObjectList que contiene elementos del tipo TFrmVerNota, puedes hacer lo siguiente:
FNotes[FNotes.Count - 1].Caption := 'Something';
FNotes[FNotes.Count - 1].Show

// O usar la forma anterior:
var
  NoteForm: TFrmVerNota;

begin
  NoteForm := TFrmVerNota.Create(nil);
  NoteForm.Caption := 'Something';
  NoteForm.Shot;
  FNotes.Add(NoteForm)
end;

Sobre el liberar el formulario al cerrarlo, tendrías que usar el evento OnClose poniendo el valor de la variable Action en caFree:

Código Delphi [-]
procedure TFrmVerNota.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  // Aquí podrías eliminar el formulario del objeto TObjectList:
  FNotes.Remove(Self)
end;

// Para hacer lo anterior, tendrías que declarar una propiedad en la clase TFrmVerNota en la cual le pases el objeto:
type
  TFrmVerNota = class(TForm)
  private
    FNotes: TObjectList< TFrmVerNota >; // O solo TObjectList
  public
    property FNotes: TObjectList< TFrmVerNota >
      read FNotes
      write FNotes;
  end

// Al crear el formulario haces algo como:
FNotes.Add(TFrmVerNota.Create(nil));
FNotes[FNotes.Count - 1).Notes := FNotes;
// ...
FNotes(FNotes.Count - 1).Show


Espero que con esta pequeña explicación se resuelva tu problema.


Saludos...

Nota: Donde veas < TFrmVerNota > debes ponerlo todo sin espacios, esto lo hice así por que el foro elimina el contenido de <TFrmVerNota> si lo escribo todo junto.

jocaro 16-05-2013 19:33:45

Muchisimas gracias maeyanes.

De pequeña explicación, nada. Me has dado una respuesta elaborada y muy clara. Me han funcionado correctamente los cambios que he hecho con ObjectList, a partir de tu código y anotaciones.

No he conseguido que funcione el borrado en el ObjectList, seguro que debido a un error mio. Me produce un 'Access violation at address...'.

Me queda la duda de que pasa cuando cierro el form por medio del aspa superior derecha ¿Sólo se hace un .hide del form, pero no se destruye el objeto? ¿Si borro el objeto de la lista de objetos, se pierde su referencia?. Si es así quedaría liberado sólo con esa operación o habría que hacer el Action := caFree de todos modos?

En fin, un saludo y gracias de nuevo.

maeyanes 16-05-2013 20:25:47

Hola...

El error Access violation at address... se produce por una omisión mía. Te explico: la clase TObjectList puede 'tomar' posesión de los objetos que se agregan, esto se traduce a que, al eliminar un objeto de la lista, esta lo destruye automáticamente.

Para evitar el error de acceso de memoria, tienes que crear el objeto TObjectList pasando False como valor del parámetro del constructor:

Código Delphi [-]
FNotes := TObjectList.Create(False);

con esto le indicas a la lista que no debe destruir los objetos al eliminarlos de la esta.

Entonces el código del evento OnClose ya te debería funcionar sin errores.

Sobre tu duda al cerrar el formulario, si usas el código que te puse de ejemplo, este se destruirá cada vez que uses el botón cerrar del fomulario (la famosa aspa superior derecha :D)


Saludos...

jocaro 17-05-2013 14:07:45

Hola Maeyanes, he cambiado la creación de la lista tal como me comentas, pero sigue produciendo 'Access violation...'

Código Delphi [-]
FNotes := TObjectList.Create(False);

¿Puedes explicarme un poco mas detalladamente el código que me pasas para liberar el formulario? hay detalles que no tengo claros. Por ejemplo:

¿La propiedad sería 'FNotes' o 'Remove'

Código Delphi [-]
    property FNotes: TObjectList< TFrmVerNota >

¿ '.Notes' tengo que definirla a priori?

Código Delphi [-]
FNotes[FNotes.Count - 1).Notes := FNotes;

Gracias una vez mas por todo

maeyanes 17-05-2013 19:15:54

Hola...

¿Podrías poner el código completo de como lo estás haciendo ahora?


Saludos...

jocaro 21-05-2013 12:34:20

Hola Maeyanes, disculpa el retraso. He tenido un pequeño accidente doméstico y no he podido contestar antes.

No puedo poner el código, ya que lo tengo en mi lugar habitual de trabajo y en un par de semanas no podré pasarme por allí.

Si ves alguna manera de contarme la lógica de declaración de la propiedad en la clase TFrmVerNota para pasar el objeto te lo agradecería.

Un saludo


La franja horaria es GMT +2. Ahora son las 20:54:05.

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