Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Almacenar y recuperar objetos en listas (https://www.clubdelphi.com/foros/showthread.php?t=86298)

santiago14 16-07-2014 17:59:20

Almacenar y recuperar objetos en listas
 
Buenas, resulta que tengo un StringList y quiero ponerle un valor y un objeto, hasta ahí no tengo drama (creo)
A los datos los recupero desde una query. Guardo en la parte del objeto, un string.
Código Delphi [-]
while not qryTiposServicios.Eof do
  begin
    tipo:=qryTiposServicios.FieldAsString('tipo'); //clave
    valor:=qryTiposServicios.FieldAsString('descripcion'); //valor
  //Ver la parte del Object. No puedo visualizar correctamente lo que se puso ahí.
    tipos_servicio.AddObject(valor, TObject(string(tipo)));
    qryTiposServicios.Next;
  end;;

Esto no me dá ningún error, pero a la hora de visualizarlo hago lo siguiente:

Código Delphi [-]
s:=CellByName['clTipoServicio', i].AsString;
p:=self.tipos_servicio.IndexOf(s);
p2:=string(TObject(Self.tipos_servicio.Objects[p]));
//.....

En p2 devuelve basura. ¿Qué estoy haciendo mal?

Gracias.

nlsgarcia 16-07-2014 20:53:45

santiago14,

Cita:

...tengo un StringList y quiero ponerle un valor y un objeto...pero a la hora de visualizarlo..devuelve basura...¿Qué estoy haciendo mal?...
:rolleyes:

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
const
   A1 : Array[0..3] of String = ('Item-1', 'Item-2', 'Item-3', 'Item-4');
   A2 : Array[0..3] of String = ('Object-1', 'Object-2', 'Object-3', 'Object-4');

var
   SL : TStringList;
   i : Integer;
   S1, S2 : String;

begin

   SL := TStringList.Create;

   for i := 0 to 3 do
      SL.AddObject(A1[i],TObject(A2[i]));

   for i := 0 to 3 do
   begin
      S1 := SL.Strings[i];
      S2 := String(SL.Objects[i]);
      ShowMessage(S1 + ',' + S2);
   end;

   SL.Free;

end;

end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, ejemplifica el uso del método AddObject en una variable TStringList.

Revisa esta información:
Espero sea útil :)

Nelson

santiago14 17-07-2014 01:00:49

Gracias Nelson, es muy útil.
Lo raro es que al principio hice algo parecido a lo que indicas y no tuve suerte.

Bueno, voy a afinar el lápiz y les cuento.

Santiago.

ecfisa 17-07-2014 04:46:02

Hola Santiago.

Cita:

Empezado por santiago14 (Mensaje 479052)
...En p2 devuelve basura. ¿Qué estoy haciendo mal?

Lo que sucede es que estas asignando a todos los apuntadores la misma dirección de memoria (variable "tipo") y cambiando su contenido antes de cada nueva asignación, cuando lo que necesitas es que los apuntadores hagan lo suyo a distintas posiciones de memoria (variables).

Tenes varias maneras de lograr lo que buscas:

Usando un TStrings y un arreglo, como en el ejemplo que te puso Nelson.
Código Delphi [-]
var
  TipServ: TStrings;
  StrVec: array of string;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TipServ:= TStringList.Create;

  with qryTiposServicios do
  begin
    Open;
    while not eof do
    begin
      SetLength(StrVec, Length(StrVec) + 1);
      StrVec[High(StrVec)]:= FieldByName('CAPITAL').AsString;
      TipServ.AddObject(FieldByName('NAME').AsString, Pointer(StrVec[High(StrVec)]));
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  Memo1.Clear;
  for i:= 0 to TipServ.Count-1 do
    Memo1.Lines.Add(Format('%s, %s',[TipServ[i],
      string(TipServ.Objects[i])]));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  TipServ.Free;
  Finalize(StrVec);
end;

Usando una clase:
Código Delphi [-]
type
  TMiStr = class
    s1: string;
  end;

var
  TipServ: TStrings;

procedure TForm1.FormCreate(Sender: TObject);
var
  MiStr: TMiStr;
begin
  TipServ:= TStringList.Create;
  with qryTiposServicios do
  begin
    Open;
    while not eof do
    begin
      MiStr:= TMiStr.Create;
      MiStr.s1:= FieldByName('DESCRIPCION').AsString;
      TipServ.AddObject(FieldByName('TIPO').AsString, TObject(MiStr));
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  Memo1.Clear;
  for i:= 0 to TipServ.Count-1 do
    Memo1.Lines.Add(Format('%s, %s',[TipServ[i], TMiStr(TipServ.Objects[i]).s1]));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  i: Integer;
begin
  for i:= 0 to Pred(TipServ.Count) do
    TipServ.Objects[i].Free;
  TipServ.Free;
end;

Con dos TStrings.
Código Delphi [-]
...
var
  s1: TStrings;
  s2: TStrings;

procedure TForm1.FormCreate(Sender: TObject);
begin
  s1:= TStringList.Create;
  s2:= TStringList.Create;
  with qryTiposServicios do
  begin
    Open;
    while not eof do
    begin
      s1.Add(FieldByName('TIPO').AsString);
      s2.Add(FieldByName('DESCRIPCION').AsString);
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  Memo1.Clear;
  for i:= 0 to s1.Count-1 do
    Memo1.Lines.Add(Format('%s, %s',[s1[i],s2[i]]));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  s1.Free;
  s2.Free;
end;

Mediante un array dinámico.
Código Delphi [-]
...
type
  TRecStr = record
    s1: string;
    s2: string;
  end;

var
  VecStr: array of TRecStr;

procedure TForm1.FormCreate(Sender: TObject);
begin
  with qryTiposServicios do
  begin
    Open;
    while not eof do
    begin
      SetLength(VecStr, Length(VecStr)+1);
      VecStr[High(VecStr)].s1:= FieldByName('TIPO').AsString;
      VecStr[High(VecStr)].s2:= FieldByName('DESCRIPCION').AsString;
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  Memo1.Clear;
  for i:= Low(VecStr) to High(VecStr) do
    Memo1.Lines.Add(Format('%s, %s',[VecStr[i].s1, VecStr[i].s2]));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Finalize(VecStr);
end;
Particularmente considero los dós últimos códigos mas naturales, sin necesidad de forzar tipos através del uso de moldeos.

Saludos :)

Casimiro Notevi 17-07-2014 10:02:11

Vaya monstruos delphi estáis hechos... yo seguiré con lo mio: aconsejar leer la guía de estilo, con ese cumplo :rolleyes:

Neftali [Germán.Estévez] 17-07-2014 10:41:24

Cita:

Empezado por Casimiro Notevi (Mensaje 479082)
Vaya monstruos delphi estáis hechos... yo seguiré con lo mio: aconsejar leer la guía de estilo, con ese cumplo :rolleyes:

:D:D:D:D No nos engañes...

Un par más a las que ya ha añadido ecfisa (he tomado su código como base):

(1) Es usando sólo el TStringList y utilizar el "formato" de Name=Value.
Pare ello están las propiedades Names y Values de TStrings.

Seguramente no es el más adecuado si tienes miles de registros.


Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
var
  str:string;
begin
  TipServ:= TStringList.Create;
  with qryTiposServicios do
  begin
    Open;
    while not eof do begin
       TipServ.Add(FieldByName('TIPO').AsString + '=' + FieldByName('DESCRIPCION').AsString);
      Next;
    end;
  end;

end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
  str:string;
begin
  Memo1.Clear;
  for i:= 0 to TipServ.Count-1 do begin
    Str := TipServ.Names[i];
    Memo1.Lines.Add(Str + ' --> ' + TipServ.Values[Str]);
  end;
end;

procedure TForm1.btnDestroyClick(Sender: TObject);
begin

  TipServ.Free;

end;

(2) La segunda es utilizando un Record. En este caso el Record tendría solo la descripción, ya que el Tipo lo añadimos como cadena en el TStringList, pero sería útil si en el record hubiera que almacenar más datos.


Código Delphi [-]

type

   // Añado los dos, qun que sólo haría falta 1, pero es ilustrativo por si
  // tuvieramos que almecenar más datos en el record
  RecordDesc = record
    Tipo:string;
    Descripcion:string;
  end;

  PRecordDesc = ^RecordDesc;
  
  procedure TForm1.FormCreate(Sender: TObject);
var
  MiStr:PRecordDesc;
begin
  TipServ:= TStringList.Create;
  with qryTiposServicios do
  begin
    Open;
    while not eof do begin
      New(MiStr);
      MiStr.Tipo := FieldByName('TIPO').AsString;
      MiStr.Descripcion := FieldByName('DESCRIPCION').AsString;

      // Añadirlo
      TipServ.AddObject(MiStr.Tipo, TObject(MiStr));
      // Siguiente
      Next;
    end;
  end;

end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  MiStr:PRecordDesc;
  i:integer;
begin
  Memo1.Clear;
  for i:= 0 to TipServ.Count-1 do begin
    MiStr := PRecordDesc(TipServ.Objects[i]);
    Memo1.Lines.Add(TipServ[i] + ' --> ' + MiStr.Descripcion);
  end;
end;

procedure TForm1.btnDestroyClick(Sender: TObject);
var
  i: Integer;
  MiStr:PRecordDesc;
begin
  for i:= 0 to Pred(TipServ.Count) do begin
    MiStr := PRecordDesc(TipServ.Objects[i]);
    Dispose(MiStr);
  end;
  TipServ.Free;

end;

Casimiro Notevi 17-07-2014 10:51:02

Lo dicho, monstruos :p

Este hilo puede que esté bien "adherirlo" arriba (ponerle la chincheta o como se le llame), cambiándole el título a algo más... académico.
A ver si algún moderador lee esto y lo hace :)



pd: es que no se me ocurre un título descriptivo y no quiero enviarme un mensaje diciendo que escriba un título descriptivo porque entraría en un bucle sin fin :eek:

ecfisa 17-07-2014 12:01:41

Vamos por otro... :)

Código Delphi [-]
...
uses contnrs;

type
  TRecStr = record
    s1,s2: string;
  end;

var
  List: TList;

procedure TForm1.FormCreate(Sender: TObject);
var
  PR: ^TRecStr;
begin
  List:= TList.Create;
  with qryTiposServicios do
  begin
    Open;
    while not Eof do
    begin
      New(PR);
      PR.s1:= FieldByName('TIPO').AsString;
      PR.s2:= FieldByName('DESCRIPCION').AsString;
      List.Add(PR);
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  for i:= 0 to List.Count-1 do
    ListBox1.Items.Add(Format('%s - %s',
      [TRecStr(List[i]^).s1,TRecStr(List[i]^).s2]));
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  i: Integer;
begin
  for i:= 0 to List.Count-1 do
    Dispose(List.Items[i]);
  List.Free;
end;

Y otro:
Código Delphi [-]
uses contnrs;

type
  PRecStr = ^TRecStr;
  TRecStr = record
    s1, s2: string;
  end;

var
  Queue: TQueue;

procedure TForm1.FormCreate(Sender: TObject);
var
   PR: PRecStr;
begin
  Queue:= TQueue.Create;
  with qryTiposServicios do
  begin
    Open;
    while not Eof do
    begin
      New(PR);
      PR.s1:= FieldByName('TIPO').AsString;
      PR.s2:= FieldByName('DESCRIPCION').AsString;
      Queue.Push(PR);
      Next;
    end;
  end;
end;

procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
  R: PRecStr;
begin
  while Queue.Count > 0 do
  begin
    R:= Queue.Pop;
    ListBox1.Items.Add(Format('%s - %s', [R^.s1, R^.s2]));
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Queue.Free;
end;

...

Saludos :)

Casimiro Notevi 17-07-2014 12:39:45

Buen y descriptivo título :)

Neftali [Germán.Estévez] 17-07-2014 13:14:20

Cita:

Empezado por Casimiro Notevi (Mensaje 479089)
pd: es que no se me ocurre un título descriptivo y no quiero enviarme un mensaje diciendo que escriba un título descriptivo porque entraría en un bucle sin fin :eek:

:D:D:D:D

Esto es programación pura y dura... Ponte un flag para evitar la reentrada. ;)

nlsgarcia 17-07-2014 22:32:12

santiago14,

Cita:

Empezado por santiago14
...tengo un StringList y quiero ponerle un valor y un objeto...pero a la hora de visualizarlo..devuelve basura...¿Qué estoy haciendo mal?...

:rolleyes:

Revisa estas variantes al código propuesto en el Msg #2 y que siguen la línea de diversas opciones propuestas en este hilo a tu requerimiento:
Código Delphi [-]
 unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TData = Class(TObject)
    Item : String;
    Objeto : string;
  end;

  TReg = Record
    Item : String;
    Objeto : string;
  End;

const
   A1 : Array[0..3] of String = ('Item-1', 'Item-2', 'Item-3', 'Item-4');
   A2 : Array[0..3] of String = ('Objeto-1', 'Objeto-2', 'Objeto-3', 'Objeto-4');

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Gestión de Listas de Datos por medio de TList y Objetos
procedure TForm1.Button1Click(Sender: TObject);
var
   List : TList;
   i : Integer;
   S1, S2 : String;
   Data : TData;

begin

   List := TList.Create;

   for i := 0 to 3 do
   begin
      Data := TData.Create;
      Data.Item := A1[i];
      Data.Objeto := A2[i];
      List.Add(Data)
   end;

   for i := 0 to List.Count - 1 do
   begin
      S1 := TData(List.Items[i]).Item;
      S2 := TData(List.Items[i]).Objeto;
      ShowMessage( S1 + ',' + S2);
   end;

   for i := 0 to List.Count - 1 do
      TData(List.Items[i]).Free;

   List.Free;

end;

// Gestión de Listas de Datos por medio de TStringList (Name = Value)
procedure TForm1.Button2Click(Sender: TObject);
var
   SL : TStringList;
   i : Integer;
   S1, S2 : String;

begin

   SL := TStringList.Create;

   for i := 0 to 3 do
      SL.Add(A1[i] + '=' + A2[i]);

   for i := 0 to 3 do
   begin
      S1 := SL.Names[i];
      S2 := SL.ValueFromIndex[i];
      ShowMessage( S1 + ',' + S2);
   end;

   SL.Free;

end;

// Gestión de Listas de Datos por medio de Arreglos Dinámicos y Registros
procedure TForm1.Button3Click(Sender: TObject);
var
   A3 : Array of TReg;
   i : Integer;
   S1, S2 : String;

begin

   for i := 0 to 3 do
   begin
      SetLength(A3,Length(A3)+1);
      A3[High(A3)].Item := A1[i];
      A3[High(A3)].Objeto := A2[i];
   end;

   for i := Low(A3) to High(A3) do
   begin
      S1 := A3[i].Item;
      S2 := A3[i].Objeto;
      ShowMessage( S1 + ',' + S2);
   end;

   Finalize(A3);

end;

end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, ejemplifica diferentes métodos para el manejo de listas de datos.

Nota: La entrada de datos es simulada con los arreglos de constantes A1 y A2 para facilitar las pruebas del código propuesto.

Espero sea útil :)

Nelson.

nlsgarcia 18-07-2014 07:19:02

santiago14,

Continuación del Msg #11 :rolleyes:

Revisa estas variantes complementarias al código propuesto en el Msg #2 y que siguen la línea de diversas opciones propuestas en este hilo a tu requerimiento:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Contnrs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TReg = Record
    Item : String;
    Objeto : String;
  End;

  TPtrLista = ^TLista;

  TLista = Record
    Item : String;
    Objeto : String;
    Next : TPtrLista;
  End;

const
   A1 : Array[0..3] of String = ('Item-1', 'Item-2', 'Item-3', 'Item-4');
   A2 : Array[0..3] of String = ('Objeto-1', 'Objeto-2', 'Objeto-3', 'Objeto-4');

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Gestión de Listas de Datos por medio de Punteros
procedure TForm1.Button1Click(Sender: TObject);
var
   PtrLista, PriLista, UltLista, AuxLista : TPtrLista;
   S1, S2 : String;
   FirstPtr : Boolean;
   i : Integer;

begin

   FirstPtr := True;

   for i := 0 to 3 do
   begin

      New(PtrLista);
      PtrLista^.Item := A1[i];
      PtrLista^.Objeto := A2[i];
      PtrLista^.Next := nil;

      if FirstPtr then
      begin
         PriLista := PtrLista;
         FirstPtr := False;
      end
      else
         UltLista^.Next := PtrLista;

      UltLista := PtrLista;

   end;

   PtrLista := PriLista;

   while PtrLista <> nil do
   begin
      S1 := PtrLista^.Item;
      S2 := PtrLista^.Objeto;
      ShowMessage( S1 + ',' + S2);
      PtrLista := PtrLista^.Next;
   end;

   PtrLista := PriLista;

   while PtrLista <> nil do
   begin
      AuxLista := PtrLista^.Next;
      Dispose(PtrLista);
      PtrLista := AuxLista;
   end;

end;

// Gestión de Listas de Datos por medio de TList y Punteros
procedure TForm1.Button2Click(Sender: TObject);
var
   List : TList;
   i : Integer;
   S1, S2 : String;
   PReg : ^TReg;

begin

   List := TList.Create;

   for i := 0 to 3 do
   begin
      New(PReg);
      PReg^.Item := A1[i];
      PReg^.Objeto := A2[i];
      List.Add(PReg)
   end;

   for i := 0 to List.Count - 1 do
   begin
      S1 := TReg(List.Items[i]^).Item;
      S2 := TReg(List.Items[i]^).Objeto;
      ShowMessage( S1 + ',' + S2);
   end;

   for i := 0 to List.Count - 1 do
      Dispose(List.Items[i]);

   List.Free;

end;

// Gestión de Listas de Datos por medio de TQueue
procedure TForm1.Button3Click(Sender: TObject);
var
   Queue: TQueue;
   i : Integer;
   S1, S2 : String;
   PReg : ^TReg;

begin

   Queue:= TQueue.Create;

   for i := 0 to 3 do
   begin
      New(PReg);
      PReg^.Item := A1[i];
      PReg^.Objeto := A2[i];
      Queue.Push(PReg);
   end;

   for i := 0 to Queue.Count - 1 do
   begin
      PReg := Queue.Pop;
      S1 := PReg.Item;
      S2 := PReg.Objeto;
      ShowMessage( S1 + ',' + S2);
   end;

   Queue.Free;

end;

// Gestión de Listas de Datos por medio de TStack
procedure TForm1.Button4Click(Sender: TObject);
var
   Stack: TStack;
   i : Integer;
   S1, S2 : String;
   PReg : ^TReg;

begin

   Stack:= TStack.Create;

   for i := 0 to 3 do
   begin
      New(PReg);
      PReg^.Item := A1[i];
      PReg^.Objeto := A2[i];
      Stack.Push(PReg);
   end;

   for i := 0 to Stack.Count - 1 do
   begin
      PReg := Stack.Pop;
      S1 := PReg.Item;
      S2 := PReg.Objeto;
      ShowMessage( S1 + ',' + S2);
   end;

   Stack.Free;

end;

end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, ejemplifica diferentes métodos para el manejo de listas de datos.

Nota: El ejemplo basado en el tipo TStack no se adapta a tu requerimiento por ser una pila (LIFO-Last In First Out), fue puesto solo como complemento del ejemplo con el tipo TQueue (FIFO-First In First Out), el cual se adapta a lo solicitado.

Espero sea útil :)

Nelson.

Casimiro Notevi 18-07-2014 10:20:52

¡Qué completo y didáctico está resultando este hilo!
Incluso se podría preparar un sencillo tutorial explicando cada una de las propuestas planteadas, con sus ejemplos, código homogéneo, etc.
Pero eso para quien tenga tiempo y ganas :rolleyes:


La franja horaria es GMT +2. Ahora son las 20:43:15.

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