Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Cargar/Guardar un objeto de una clase propia (https://www.clubdelphi.com/foros/showthread.php?t=36008)

Uoha 28-09-2006 19:35:52

Cargar/Guardar un objeto de una clase propia
 
Hace un par de meses que empecé con este bello lenguaje, y me estuve quemando las pestañas de diversas formas pero sin poder solucionar este problema. Por lo que entendí lo que estoy haciendo está bien, pero no lo convenzo al programa, que sigue sin hacer lo que yo quiero :D
Este es el código que tengo escrito
Código Delphi [-]
unit PruebaExport;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls, PruebaExport2;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
  private
  public
  end;
var
  Form1: TForm1;
  F:Finanzas;
  S : TFileStream;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
  f:=finanzas.Create(self);
  F.Integrantes := 10;
  F.Banda := 20;
  F.Coordinador :=30;
  F.Agente := 40;
  F.Porcentaje := true;
  S := tfilestream.Create('C:\archivo',fmCreate);
  s.Write(F,100);
  showmessage(f.todo);
  f.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
S : TFileStream;
begin
  s := TFileStream.Create('C:\archivo',fmOpenRead);
  f := finanzas.Create(self);
  s.Read(F,100);
  s.Free;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
  showmessage(F.Todo);
end;
end.

Código Delphi [-]

unit PruebaExport2;
interface
uses
  SysUtils, Classes;
type
  TIO = class(TDataModule)
  private
  public
  end;
  
  Finanzas = class(Tcomponent)
  function Todo:string;
  public
    Integrantes,Banda,Coordinador,Agente : Single;
    Porcentaje : boolean;
  end;

var
  IO: TIO;

implementation
{$R *.dfm}

function Finanzas.Todo: string; // Muestra las variables.
begin
  if porcentaje = true then
  result := floattostr(integrantes) + '  ' + floattostr(coordinador)
        + '  ' + floattostr(banda) + '  ' + floattostr(agente) + ' Sí'
  else
  result := floattostr(integrantes) + '  ' + floattostr(coordinador)
        + '  ' + floattostr(banda) + '  ' + floattostr(agente) + ' No';
end;
end.

Para probarlo:
  1. Comento la parte que lee el archivo
  2. Compilo
  3. Clickeo el botón (se guarda la información, sale el messagebox)
  4. Cierro el programa
  5. Descomento lo que comenté
  6. Compilo
  7. Me sale el msgbox con todos valores '0'. Si saco 'F := finanzas.create;' en la parte de lectura, el message box inicial me da unos números rarísimos...
¿Qué estoy haciendo o escribiendo mal?
Muchas gracias

jachguate 28-09-2006 20:55:16

La variable F, como tal es un puntero, un número de 4 bytes que indica una dirección en memoria. Cuando vos haces
Código Delphi [-]
s.Write(F,100);
En realidad estas escribiendo un número de 4 bytes (la dirección que tenía en memoria la instancia que creaste en esa corrida en particular).

Claro que cuando ejecutes otra vez el programa, aún cuando recuperés la dirección, en la memoria no habrá una instancia válida del objeto.

Lo que a vos te hace falta es que tu clase sea auto-persistente, en palabras mas modernas, que sea "serializable".

Esto podrías lograrlo dotando de un par de métodos a la clase, por decir: SaveToStream, LoadFromStream, que se encarguen de escribir y leer todas las propiedades de un stream.

Otra posibilidad, mas elaborada, es que crees una clase que sirva de ancestro a todas tu jerarquía, y que dicha clase tenga la lógica para escribir/leer las propiedades publicadas en un stream. Deben ser las propiedades publicadas porque es para estas para las que tenes información de tipo en tiempo de corrida (RTTI).

Finalmente, podrías derivar tus clases de TComponent (formalmente hablando, que dejen de ser clases y sean componentes), y valerte de los métodos WriteComponent y ReadComponent de un stream. Esto ya implementa, mas o menos, lo que explique antes (valiendose de la clase TWriter y TReader de la VCL).

En fin, este es un tema amplio, con lo dicho pretendo, mas que darte una solución, darte las ideas para que encontres una.

Hasta luego.

;)
Hasta luego.

;)

Uoha 29-09-2006 06:43:57

Iluminadora respuesta
 
Muchas gracias jachguate (nunca pensé que iba a tener una respuesta tan buena tan rápido :D:D), entendí mi error... obviamente opté por la opción de heredar de TComponent :D. Sin embargo esta opción ya la había intentado y tampoco me había sido de utilidad, no la había podido implementar, y ahora volví a intentarlo con pocos resultados. Antes y después de postear vi que había muchos tutoriales sobre distintas maneras de hacer esto, pero me gustaría saber si existe una simple y breve que utilize el writeComponent y el readComponent. Estuve intentando y tampoco entiendo por qué no funciona lo siguiente:

Lector:

Código Delphi [-]
type
{...Declaración de la clase form y los procedimientos...}
var
  F:Finanzas;
  S:TFileStream;
  R:TReader;
  W:TWriter;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
  F := finanzas.Create(self);
  s := TFileStream.Create('C:\archivo',fmOpenRead);
  s.Position := 0;
  r := Treader.Create(s,4);
  r.Position := 0;
  r.Root := self;
  r.ReadComponent(F);
  r.free;
end;

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

begin
  F := finanzas.Create(self);
  s := TFileStream.Create('C:\archivo',fmOpenRead);
  s.Position := 0;
  r := Treader.Create(s,4);
  r.Position := 0;
  r.Root := self;
  r.ReadComponent(F);
  r.free;
end;

(Por si es útil saberlo: el error surge en la parte de lectura, donde me dice que hubo un problema al leer el stream)

Otra vez me gustaría saber que estoy haciedno mal... también aceptaría un "no, realmente no hay una forma mucho más simple que la que escribió rounin en http://www.clubdelphi.com/foros/showthread.php?t=25835&highlight=writecomponent" (ya sé que es una forma genérica, pero armar algo más o menos con esa estructura sigue siendo... embrollado). También está la posibilidad de pasar de binnary a texito, de texto a archivo, y viceversa; pero prefería saber que no había otra más simple antes de rendirme por ella.


Gracias de nuevo.

jachguate 29-09-2006 16:29:21

Si ya tenes componentes, por que no llamar directamente a los métodos WriteComponente y ReadComponent del stream?

Código Delphi [-]
begin
  Conta := TConta.Create;
  Conta.Propiedad := Valor;
  Conta.OtraPropiedad := OtroValor;
  s := TFileStream.Create('c:\conta.dat', fmCreate);
  try
    s.WriteComponent(Conta);
  finally
    s.Free;
  end;

A mi me parece mucho mas limpio.

Ahora, ayer a partir de la charla, como me quedé algo picado con el tema, busqué un par de referencias y me encontré con la biblioteca RTTI Library, que creo te será de utilidad, con la ventaja que tus clases no tienen por que ser componentes.

No la he probado, pero tiene buena pinta y ya tiene procedimientos como SaveObjToIniFile que pueden serte de utilidad.

Hasta luego.

;)

Uoha 30-09-2006 05:04:34

Problema newbie, resuelto
 
Cita:

Empezado por jachguate
Si ya tenes componentes, por que no llamar directamente a los métodos WriteComponente y ReadComponent del stream?

Gracias :D, había probado con ese método y no lograba hacerlo andar.... hasta que vi que pusiste el ejemplo con propiedades y caí en que estaba usando fields, y que solo puedo exportar propiedades published (que poseen RTTI). Cambié todo a propiedades 'publicadas' y anduvo perfecto.

Voy a hecharle una ojeada al link.

Gracias!

juangiron 14-05-2007 20:25:24

pregunta
 
hola... necesito guardar un objeto en algun tipo de archivo, la respuesta que diste no funciona por que existe una incompatibilidad de tipos Tcopmponent y Tobjeto (que es mi clase)... toca hacer algun tipo de casteo o algo asi?? si es asi como lo hago??:confused::confused::confused::confused::eek::eek::eek::eek:

dec 14-05-2007 20:30:15

Hola,

En un "TObject" contarás con determinados que estarán también en la clase "TComponent". Porque "TComponent" hereda en última instancia de "TObject". Pero los métodos implementados por "TComponent" no están disponibles en "TObject" y clases derivadas de "TObject" que no hereden de "TComponent", claro.

La cuestión es que tal vez podrías heredar tu clase de "TComponent", en lugar de "TObject". De este modo ya podrías utilizar los métodos "LoadComponent" y "WriteComponent". No podrás hacerlo mientras tu clase no herede de "TComponent", a no ser que tú mismo te encarges de implementar métodos similares.

juangiron 14-05-2007 22:44:01

PRegunra
 
hola logre guardar mis objetos que estan almacenados en un array asi:

Código Delphi [-]
procedure TFrmPrincipal.ToolButton14Click(Sender: TObject);
var
  FS: TFileStream;
  I:Integer;
begin
SaveDialog1.Filter:='Archivo XML(*.dat|*.DAT';
if SaveDialog1.Execute then
begin
   try
  FS := nil;
  try
    FS := TFileStream.Create(SaveDialog1.FileName, fmCreate);
    for I := 0 to High(ArrayObjetos) do
       FS.WriteComponent(ArrayObjetos[i].getObjeto);
  finally
    FS.Free;
  end;
  finally
   ShowMessage('Archivo Guardado');
  end;
  end;
end;

pero al hacer la funcion de cargar?

cual seria el Tobjet?

Código Delphi [-]
procedure TFrmPrincipal.ToolButton3Click(Sender: TObject);
var
  FS: TFileStream;
  newO:TObjeto;
  I:Integer;
begin
OpenDialog1.Filter:='Archivo dat(*.dat|*.DAT';
if OpenDialog1.Execute then
begin
   try
  FS := nil;
  try
    FS := TFileStream.Create( OpenDialog1.FileName, fmOpenRead );

   //  for I := 0 to   High(FS) do --> NEcesito hacer un FOR???
     FS.ReadComponent(TObjeto.create);
  finally
    FS.Free;
  end;
   finally

   end;
end;
end;

lo que quiero hacer es leer el archivo y meter estos datos en un array de objetos, debo hacer un for del FS?? como asigno el objeto a mi array para poder acceder a los metodos SET y GET de mi objeto (Tobjeto es mi clase de Objetos, no es igual a TObject)

gracias :confused::confused::confused::confused::eek::eek::eek::eek:


La franja horaria es GMT +2. Ahora son las 08:22:39.

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