Vorrei sapere se essite un metodo per selezionare tutti i record visibili in un oggetto DBGrid, che sia alternativo (e più veloce sopratutto) del solito ciclo:
First;
DisableControls;
while not EOF do
begin
DBDataGrid.SelectedRows.CurrentRowSelected := True;
Next;
end;
in breve,
si parte da una DBGrid con molte colonne, per ogni colonna l'utente ha la possibilità di definire un filtro, e ad ogni filtro la DBGrid si riduce... alla fine quando l'utente ha "scremato" la lista dovrebbe selezionare tutto (questo per evitare di fare Ctrl+click per ogni record) e dopo lanciare una comando che esegua altro su ognuno di questi records.
Questo tipo di selezione è necessaria perchè successivamente utilizzo il Bookmark per eseguire altre operazioni sui record.
Il loop ovviamente funziona, ma è parecchio lento, per darvi un'idea, sul mio PC un I7 con 16Gb di Ram e W11 la selezione di 3354 records impiega 2 minuti e 11 sec
Certo potrei intervenire sulla query ma non voglio perchè i filtri sono molti e così come è strutturata la lista e la gestione funzionano perfettamente.
L'applicativo dovrà alla fine essere eseguito in rete, è vero che anche se da rete, non eseguendo accessi al disco ma solo sul controllo, teoricamente non dovrei avere un incremento di tempo... però anche così mi sembra troppo lungo
mi domando, un semplice comando "seleziona tutto" non esiste ? ... o almeno io non l'ho trovato
grazie
M
sui tempi (lungi e ingiustificati) sono assolutamente d'accordo con te, posto il codice completo, facile che abbia fatto qualche cag...a,
procedure TSDSList.SpeedButtonSelectAllClick(Sender: TObject);
var
Duration : TDateTime;
begin
Duration := Now();
try
Screen.Cursor := crHourglass;
try
DBDataGrid.SelectedRows.Clear;
with DBDataGrid.Datasource.DataSet do
begin
First;
DisableControls;
while not EOF do
begin
DBDataGrid.SelectedRows.CurrentRowSelected := True;
Next;
end;
end;
except on E
: ESQLDatabaseError do MessageDlg( DB_OPENING_ERROR + Self.Caption, mtError, [mbOK], 0);
end;
finally
DBDataGrid.Datasource.DataSet.EnableControls;
Screen.Cursor:= crDefault;
end;
ShowMessage( TASK_COMPLETED + ' in: ' + TimeToStr( Now() - Duration));
end;
che dici ?
Sono convinto anche io che il PC non possa fare tutta questa differenza,
ad ogni modo;
Inserito l'istruzione BeginUpdate ed EndUpdate, in effetti la prestazione migliora del 50% da 2:41 minuti scenda a 1:24 minuti (vedi picture) grazie !
come componenti utilizzo quelli standard di Lazarus, :
TODBCConnection con TSQLTransaction, TSQLQuery e TDataSource per connessione e accesso ai dati
e come database, MSAccess, il tutto sullo stesso disco SSD dove lavora il programma
Lazarus è la versione 3.0
EDIT: Il fatto che la tabella abbia 52 colonne, non dovrebbe essere influente sulla "marcatura" del record, no?
Ciao,
rileggendo c'è una cosa che non capisco di quello che hai scritto: quando inizi a misurare il tempo.
Io credo di aver capito che fai partire il timer DOPO aver popolato la tabella, e prima di iniziare il ciclo che serve a selezionare le righe.
Se è così, ignora quello che sto per scrivere, se invece inizi prima di popolare la DBGrid, non so se la situazione è la stessa, ma qualche mese fa ho avuto problemi di lentezza estrema nello scaricare alcune tabelle in formato CSV.
Alla fine ero arrivato a questo link: https://wiki.freepascal.org/Working_With_TSQLQuery ed avevo risolto seguendo il consiglio in fondo, di mettere
MySQLQuery.UniDirectional:=True;
Ciao, Mario
Per misurare i tempi con precisione al millisecondo (ma anche meno se vuoi, fino ai 0,1 microsecondi), puoi usare questa unità dove vuoi.
L'istanza è un advanced record, quindi non devi neanche preoccuparti di fare il free o usare il create.
L'unità è quella orginale FREE (supporta Windows e Linux) con qualche mio adattamento, ed è compatibile con quella usata anche in Delphi (migliorata da Embarcadero per lavorare in tutti i suoi target come Mac, Android, Ios etc...).
E' comoda e puoi istanziare quanti timer indipendenti vuoi (io ne uso a decine).
Puoi eseguire lo StartNew sulla stessa variabile quante volte vuoi (è di fatto la sequenza di Reset e Start).
Si usa così:
var Tim1: TStopWatch;
begin
Tim1 := TStopWatch.StartNew;
.....
.....
.....
Tim1.Stop;
//La lettura PUO' ESSERE EFFETTUATA SOLO CON LO STOP.
//Poi puoi ad esempio:
//Tim1.Reset ---> Azzera il conteggio
//Tim1.Start ---> riparte il conteggio (si può usare anche prima di un Reset per continuare quello stoppato).
ShowMessage(Tim1.ElapsedMilliseconds.ToString+' - '+i.ToString);
end;