Newsgroup: it.comp.lang.delphi
Titolo: Riempire una TListView con i dati contenuti in database e OwnerData=True

Ciao a tutti,
ho trovato un argomento non molto documentato ma che mi interessa
approfondire.
Per riempire una TListView con una grande quantitą di dati e ridurre i tempi
dell'operazione č necessario, e di solito sufficiente, utilizzare i metodi
TListView1.Items.BeginUpdate
TListView1.Items.EndUpdate
per bloccare e sbloccare l'aggiornamento della TListView durante
l'operazione di riempimento.
Quando perņ i dati da caricare diventano veramente troppi (decine di
migliaia di Items !!) č il caso di lavorare con una TListView Virtuale,
ovvero settare la proprietą OwnerData della TListView = True e gestire il
caricamento delle items attraverso l'evento OnData.
L'operazione č molto semplice quando si vuole riempire la TListView con una
struttura dati caricata in memoria come un Array, una TStringList etc...
Perņ quando voglio caricare nella TListView i dati contenuti in un DataBase?
Vorrei evitare di caricare il  Dataset (una query o una tabella) in memoria
perchč l'operazione richiede molto tempo, ho fatto la prova con una tabella
con 100.000 records e ci ho messo 15 minuti (DB Access e Dataset=TAdoQuery).
Ora,
difficilmente si presenta la circostanza di dover visualizzare in una
TListView 100.000 items, ma in ogni caso quale č la strada da seguire?
Non č necessario scrivere l'evento OnData come segue:
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
    item.Caption := DM.ADOQuery1.fields[1].AsString;
end;
perchč da qualche parte va detto al dataset di passare al record successivo,
ma dove?
Ecco, ho impiegato 50 righe per porre la mia domanda: dove devo specificare
TAdoQuery1.Next ???  Sbaglio qualcosa nell'approccio e nell'analisi che ho
fatto?
Grazie per l'attenzione e Grazie in anticipo a chi vorrą spiegarmi qualcosa
che ancora non ho capito....
Buon Lavoro a Tutti
Alessandro
____________________
ilvcclx_!!!

 qualcosa che ancora non ho capito....
In effetti è una cosa a cui avevo pensato anch'io una volta (adoro le ListView
virtuali!! -- e ODIO le DBGrid) ma non ho mai provato a realizzare.
Domani mattina provo, ok?
--
Jax

Ehi Jax,
ho premuto F5 e la tua risposta era gia li!!
Grazie,
ci aggiorniamo a domani.
Alessandro
_____________________
ilvcclx_!!!
"Jax" <rispo...@newsgroup.grazie> ha scritto nel messaggio
news:E9pk9.12050$Eu.2...@twister1.libero.it...


 ci aggiorniamo a domani.
Eccoci... grazie al mitico Delphi ho già fatto tutto!!!
Dunque:
1) crea un ADOConnection e un ADOTable (va bene anche un ADOQuery
ovviamente), meglio se metti CursorLocation = clUseServer, in modo che
non ti copi tutta la tabella in memoria all'apertura.
2) crea una ListView con OwnerData = True;
3) nell'evento OnCreate (o dove caspita vuoi) della Form inserisci il
codice per la creazione delle colonne nella ListView:
var
 i: Integer;
begin
 for i := 0 to ADOTable1.FieldCount - 1 do
  with ListView1.Columns.Add do
  begin
   Caption := ADOTable1.FieldList.Fields[i].DisplayName;
   AutoSize := True;    // questo lo puoi anche evitare
  end;
 ListView1.Items.Count := ADOTable1.RecordCount;
end;
4) nell'evento OnData della ListView inserisci il codice per riempire
l'item voluto:
var
 i: Integer;
begin
 if Item.Index > ListView1.Items.Count then Exit;
 ADOTable1.First;
 ADOTable1.MoveBy(Item.Index);
 with Item do
 begin
  ImageIndex := -1;
  Caption := ADOTable1.Fields[0].AsString;
  for i := 1 to ADOTable1.FieldCount - 1 do
   SubItems.Add(ADOTable1.Fields[i].AsString);
 end;
end;
Et voilà, le jeux sont faites! Con una ventina di righe di codice!!! ;))
A dire il vero non è ottimizzatissimo, in particolare non mi piace
quella ADOTable1.First ogni volta che viene processato un Item, ma non
conosco un altro modo veloce per muoversi direttamente al n-esimo
record.
Comunque anche così com'è, sul mio P3 1000 è velocissimo.
Grazie per avermi dato lo spunto, mi sarà sicuramente utile in futuro :)
--
Jax

Si, così funziona, avevo dimenticato il metodo MoveBy( ).
Ma non trovi che sia lento? Gia 100 record si caricano lentamente, 1000 non
ti dico!
Che sia chiaro, non voglio realizzare un'applicazione che visualizza 100.000
record in una listview in questo modo, ma almeno qualche centinaio si.
Bisognerebbe caricare l'intero recordset in memoria per assegnarlo
istantaneamente alla listview ma è proprio l'operazione di "caricamento" in
memoria che risulta lenta. Che tecnica sarebbe possibile utilizzare per
accelerare i tempi?
O almeno capire se il problema ammette una soluzione.
Grazie per la dritta sul MoveBy( )!!!
Buon Lavoro
Alessandro C.
___________________
ilvcclx_!!!
"Jax" <rispo...@newsgroup.grazie> ha scritto nel messaggio
news:8hyk9.12827$e31.2...@twister2.libero.it...


 "caricamento" in memoria che risulta lenta.
Ah, ho capito adesso cosa intendevi.
Hai provato, come ti ho detto, a impostare CursorLocation = clUseServer ?
In questo modo, anche se la tua tabella ha 100.000 record, *dovrebbe* aprirtela
in una frazione di secondo.
Comunque, come al solito, domani mattina faccio qualche prova vera con una
tabella massiccia.
--
Jax

 Ci dev'essere qualcosa che mi/ti sfugge.
Sfuggiva a me.
Stamattina ho provato a farlo con una tabella da 40.000 record, e come
temevo i primi Item sono velocissimi, ma andando sempre piů in basso
diventa lentissimo a reperire i record.
Sto studiando un metodo alternativo al First... se qualcuno vuol darmi
una mano, volentieri :)
--
Jax