PDA

Ver la Versión Completa : Almacenar y recuperar objetos en listas


santiago14
16-07-2014, 17:59:20
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.

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:


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,


...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:

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,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, [I]ejemplifica el uso del método AddObject en una variable TStringList.

Revisa esta información:

Delphi Basics : TStringList (http://www.delphibasics.co.uk/RTL.asp?Name=TStringList)

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.

...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.

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:

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.

...
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.

...
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
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.


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.




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... :)


...
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:

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
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,


...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:

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;
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, [I]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:

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;
PtrLista^.Objeto := A2;
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, [I]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 [I]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: