PDA

Ver la Versión Completa : Problemas con DB + ListView


mightydragonlor
05-10-2008, 22:10:46
Hola a todos, espero me puedan ayudar, mi problema es el siguiente:
Estoy intentando cargar datos desde una DB a un TListView a travez de un Query, el problema radica en que tengo muchos registros en la tabla de la DB y el proceso se ralentiza enormemente, les dejo un fragmento del código para que me ayuden a arreglar este problema.

procedure TMaetro.FormCreate(Sender: TObject);
var
AItem: TListItem;
begin
If UnitStart.ClienteNQ.Consultar(CronosDB,ClienteQR,'SP_CLIENTE_SELECT') then
begin
ListView1.Clear;
ClienteQR.First;
While not ClienteQR.Eof do
begin
AItem := ListView1.Items.Add;
AItem.Caption := ClienteQR.Fields[0].AsString;
AItem.SubItems.Add(ClienteQR.Fields[1].AsString);
AItem.SubItems.Add(ClienteQR.Fields[2].AsString);
ClienteQR.Next
end;
end
else
MessageBox(Application.Handle,
PChar('No es posible consultar a la Base de Datos'),
PChar('Error de Conexion'),
MB_OK + MB_ICONSTOP + MB_DEFBUTTON1 + MB_APPLMODAL);
end;

mightydragonlor
06-10-2008, 23:04:36
Hola a todos, aquí dejo el código que he logrado optimizar, pero aún me anda muy lento, en este momento tengo 1000 registros en la tabla que estoy consultando, les agradezco cualquier ayuda.

procedure TMaster.ListarTabla( DB: TIBDatabase; sTabla: String; Listado: TListView );
var
Campos: TStringList; i: Integer; Consulta: TIBQuery;
begin
if DB = nil then Exit;
Campos := TStringList.Create;
DB.GetFieldNames( sTabla, Campos );
Consulta := TIBQuery.Create( nil );
Consulta.Transaction := CronosTR;
Consulta.SQL.Add( 'SELECT * FROM ' + sTabla );
try
Consulta.Open;
except
CronosTR.Rollback;
raise;
end;
Listado.Columns.Clear;
Listado.Columns.Add;
Listado.Columns[0].Width := 0;
for i := 0 to Campos.Count - 1 do
begin
Listado.Columns.Add;
Listado.Columns[i+1].Caption := Campos[i];
Listado.Columns[i+1].Width := 100;
end;
Listado.Clear;
Listado.AllocBy := Consulta.RecordCount;
Listado.Items.BeginUpdate;
Consulta.DisableControls;
while not Consulta.Eof do
begin
Listado.Items.Add;
for i := 0 to Campos.Count - 1 do
Listado.Items[Listado.Items.Count-1].SubItems.Add(Consulta.FieldByName(Campos[i]).AsString);
Consulta.Next;
end;
Consulta.EnableControls;
Listado.Items.EndUpdate;
FreeAndNil( Campos );
FreeAndNil( Consulta );
end;

enecumene
06-10-2008, 23:09:26
Hola, a ver, no creo que vaya a cargarse más rápidos con tanto registros, mi consejo sería que pusieras una especie de progressbar o un Gauge mientras se carga la lista.

Saludos.

mightydragonlor
06-10-2008, 23:52:25
Gracias enecumene por responder tan rápido, ps ojalá se pueda cargar mas rápido, por que acabo de testear la conexion para saber cuanto tiempo se demora en ejecutarse y estos son los datos:

64 ms para consultar 1000 registros
19902 ms para cargar los 1000 registros en el listview


Como podemos ver, el problema se origina en el algoritmo de carga en el TListview, alguien conoce un método mejor para la carga de estos datos?

roman
07-10-2008, 00:40:40
alguien conoce un método mejor para la carga de estos datos?

Sí, yo :)

En tu caso particular yo usaría el ListView en modo virtual. En este modo, el ListView no carga todos los datos sino sólo los que se requiere mostrar en un momento dado.

Los pasos para ello son muy sencillos:


Pones la propiedad OwnerData del ListView en true.


Al momento de leer los datos, en lugar de cargar los elementos del ListView como hasta ahora, simplemente le indicas cuántos elementos hay:


ListView.Items.Count := DataSet.RecordCount;


Los elementos en sí, los cargas en el evento OnData del ListView


DataSet.RecNo := Item.Index; // Item es el parámetro del evento
Item.Caption := DataSet.FieldByName(...).AsString;
Item.SubItems(0) := DataSet.FieldByName(...).AsString;
Item.SubItems(1) := DataSet.FieldByName(...).AsString;

...



Aquí DataSet es el data set que estés usando, query, table, etc. Eso sí, es necesario que este data set pueda recorrerse aleatoriamente (que estén implementadas las propiedades RecordCount y RecNo). De no ser así, puedes factorizar por un ClientDataSet:


TuDataSet -> DataSetProvider -> ClientDataSet -> ListView


// Saludos

mightydragonlor
07-10-2008, 01:00:48
Hola roman, gracias por tu aporte, pero hay un problema, ¡¡No entendí!!:eek:, lamento no haberte entendido muy bien, en este momento lo estoy intentando, pero no logro agregar los datos del TIBQuery al TListview, agradeceria me pudieras dar mas detalles.

mightydragonlor
09-10-2008, 01:30:47
Hola a todos, les cuento que por mas que he tratado, no he podido cargar mas de 1 registro en el listview, no se en donde tengo el error, agradecería si alguien me muestra cual es la solución a mi torpeza.;)

enecumene
09-10-2008, 02:01:56
Creo que Roman se refería a esto:

procedure TMaetro.FormCreate(Sender: TObject);
var
AItem: TListItem;
begin
If UnitStart.ClienteNQ.Consultar(CronosDB,ClienteQR,'SP_CLIENTE_SELECT') then
begin
ListView1.Clear;
ClienteQR.First;
While not ClienteQR.Eof do
begin
ClienteQR.RecNo := AItem.Index;
AItem.Caption := ClienteQR.Fields[0].AsString;
AItem.SubItems(0) := ClienteQR.Fields[1].AsString;
AItem.SubItems(1) := ClienteQR.Fields[2].AsString;
ClienteQR.Next
end;
end
else
MessageBox(Application.Handle,
PChar('No es posible consultar a la Base de Datos'),
PChar('Error de Conexion'),
MB_OK + MB_ICONSTOP + MB_DEFBUTTON1 + MB_APPLMODAL);
end;

Saludos.

PD. Creo :D

roman
09-10-2008, 06:59:21
PD. Creo :D

Pues no :p

Si lo haces así, queda igual que como lo estaba haciendo el compañero. El chiste es no cargar todos los datos de un sólo golpe, sino solo conforme se necesiten, esto es, conforme el usuario se va desplazando por el ListView.

Aquí les pongo un ejemplo que funciona de ambos modos: normal o virtual. En modo normal, el ListView carga los datos (+/- 4000) tal como lo hacen ustedes.

Para usar el modo virtual basta que pongan la propiedad OwnerData del ListView en true. Háganlo y verán la diferencia.

roman
09-10-2008, 07:06:40
Aquí (http://www.clubdelphi.com/foros/showpost.php?p=185386&postcount=6) hay otro ejemplo, pero en ese caso lo que se muestra son los archivos de un directorio. Una mitad del ejemplo (SysIcons) carga en modo normal y la otra (VirtualSysIcons) en modo virtual. Pruébenlos abriendo un directorio grande (como C:\Windows\System32) y verán la diferencia.

// Saludos

enecumene
09-10-2008, 16:36:51
¡Vaya!, cada día se aprende algo nuevo :D

Saludos.

mightydragonlor
10-10-2008, 16:23:30
muchas gracias roman, te agradezco enormemente tu colaboración, la verdad es que me ha quedado muy claro tu ejemplo, de nuevo gracias por ayudarme.