Newsgroup: it.comp.lang.delphi
Titolo: Non mi è chiaro

Questa domanda rivela che non capisco un gran che di come funziona Delphi, 
ma la faccio lo stesso sperando che qualcuno mi chiarisca le idee.
Una proc (Estrai) estrae alcuni dati con una query e ne restituisce il 
resultset al chiamante MyProc, circa cosě:
 
procedure MyProc;
var Q: TQuery;
begin
  .....
  Q:= Estrai(aSelect);
  .....
end;
 
procedure Estrai(aSelect: string): TQuery
begin
   result:= TQuery.Create(nil);
   ......
end;
 
Originariamente, la proc MyProc aveva la Q dentro un costrutto try finally e 
quindi c'era Q.Free.
Adesso, ho scoperto di avere bisogno di Q al di fuori di MyProc per 
visualizzare il risultato in un DBGrid Inoltre, uso MyProc per eseguire un 
certo numero di diverse query che poi mostro in diversi DBGrid  e quindi ho 
rimosso il costrutto try finally e faccio il free quando chiudo il form.
Quindi mi domando: ma io ho in memoria diverse istanze di Q, oppure piů 
probabilmente non sono istanze diverse ma la var Q ha il riferimento solo 
all'ultima query eseguita ?
In questo caso capirei che č giusto il free al close del form e non mi 
lascerei niente in memoria, ma non sono sicuro di capire bene.
Se mi avete capito, potete dirmi come stanno effettivamente le cose ?
 

 Se mi avete capito, potete dirmi come stanno effettivamente le cose ?
 
Potresti passare al costruttore di TQuery la form e a quel punto sarebbe 
lei a preoccuparsi di liberare la memoria di tutte le TQuery che hai creato. 
 
Spero di essere stato chiaro e di esserti stato di aiuto.
 
David
 
 

Sei stato chiarissimo. Quindi io mi tenevo in memoria un bel pò di roba. La 
soluzione mi sembra oltremodo semplice: basta che io quando creo la istanza 
della Query indichi il form tra parentesi? Cioè
Q:= TQuery.Create(Form1);    anzichè  Q:= TQuery.Create(nil);
 
Ma allora perchè si usa anche  Q:= TQuery.Create(nil) ?
 
 
Poi l'istruzione ReportMemoryLeaksOnShutdown := True non la conoscevo 
proprio. Chissà quante <altre cose mi trova..
Grazie davvero per l'aiuto
 
 

Ciao,
  mi permetto di risponderti sebbene hai avuto una risposta ben argomentata 
(letta al volo).
 
Scusami, non capisco perche' ti devi complicare la vita (gia' di per se 
complicata).
 
Per esempio potresti mettere nella unit dove inizializzi i vari db un bel 
TQuery.
Alla inizializzazione viene creato il TQuery che poi puoi usare in tutte le 
form che vuoi indicando nelle uses quella unit.
 
Poi, se invece vuoi fare tutto a mano (qui il tuo codice)
 
procedure MyProc;
var Q: TQuery;
begin
  .....
  Q:= Estrai(aSelect);
  .....
end;
 
procedure Estrai(aSelect: string): TQuery
begin
   result:= TQuery.Create(nil);
   ......
end;
 
Nella Myproc manca una riga essenziale.
Tutto cio' che allochi devi liberare.
Quindi modificala in
 
 
procedure MyProc;
var Q: TQuery;
begin
  .....
  Q:= Estrai(aSelect);
  .....
 
  FreeAndNil(Q)
 
end;
 
Ciao,
 
Daniele
 

 Grazie davvero per l'aiuto
 
Prego figurati,
 
David
 
 

 Tutto cio' che allochi devi liberare.
 
Vero! Ma ti ha premesso che ha bisogno di quel componente al di fuori del 
metodo... La soluzione è un po' più complicata.
 
David
 
 

 metodo... La soluzione č un po' piů complicata.
 
La vedo un po dura utilizzare la variabile Q all'esterno della procedura 
MyProc.
Se vuole continuare, a mio avviso sbagliando, ad usare questa strada Q va 
liberata prima di uscire da MyProc perche', in teoria ... ma anche in 
pratica, se e' definita variabile LOCALE se esci la locale non serve piu'.
Se non la libera prima di uscire avra' una perdirta di memoria (se chiama la 
procedura 50 volte ha 50 variabili non deallocate !!!).
Se invece Q serve anche da altri parti, diventa variabile "generale" 
(globale) che va definita in altra posizione dove diventa accessibile ad 
altre unit/procedure ..... ma allora siamo all'inizio di questa risposta!!!!
 
Evidentemente la risposta e' per Stark.
 
Ciao e alla prossima
 
Daniele
 
 
 
 
 

Ciao,
credo che il suggerimento dato sia più che esauriente.
 
Credo però che indipendentemente dai sistemi di auto pulizia degli oggetti/memoria, ogni programmatore dovrebbe creare e liberare quello che utilizza.
 
In una situazione del genere, io avrei creato l'oggetto nella procedura di lancio (Estrai) e passato per variabile il puntatore alla procedura di elaborazione (MyProc)
 

e ovviamente avrei provveduto a liberarlo quando non mi serviva più

 che utilizza.
 
Concordo!
 
David
 
 

"Daniele"  ha scritto nel messaggio news:p3i6h0$7ag$1...@gioia.aioe.org...
Per esempio potresti mettere nella unit dove inizializzi i vari db un bel
TQuery.
Alla inizializzazione viene creato il TQuery che poi puoi usare in tutte le
form che vuoi indicando nelle uses quella unit.
Daniele
 
Ma vuoi dire un DataModule ? Ho un DataModule dove ho i miei Dataset e un 
sacco di proc inerenti questi dataset, ma alcune volte non voglio 
trascinarmelo dietro perchè c'è troppa roba che in un'altra unit non serve..
E comunque, non mi sarebbe sufficiente un TQuery. La Form in questione 
esegue parecchie estrazioni di dati che ha bisogno di mostrare 
contemporaneamente. Questa esigenza come la concili con un TQuery solo ? E 
se lo creo e dopo esecuzione lo distruggo, come mostro i risultati ?
 
Immagina una lista di conti contabili. Ad ogni conto puntato dal cursore 
posso aprire da uno a sei pannelli dove vengono mostrati i dettagli 
(Redditi, Spese, Investimenti, Disinvestimenti, etc.). Quindi non mi servono 
sei diverse estrazioni con sei diversi TQuery ? 
 

Io nella mia gestione ho dovuto abbandonare l'utilizzo del DataModule.
 
In pratica devo gestire un accesso a record in concorrenza anche con la mia applicazione stessa.
 
Quindi, invece che appoggiarmi ad un datamodule ho creato una lista di oggetti DB, collegata ad un singolo form.
 
Quindi posso aprire due form (identici) che sono in concorrenza tra di loro, ognuno con le proprie query di accesso ai dati indipendenti
 

"alessandrob"  ha scritto nel messaggio 
news:f0cf9a73-1d04-474b...@googlegroups.com...

Non so se ho capito bene, ma mi sembra di fare proprio così: La function 
Estrai fa il create di Q, che restituisce al chiamante (nel mio primo 
messaggio l'ho erroneamente chiamata procedure, ma è una function). MyProc 
ha la sua dichiarativa. Non posso fare il free, perchè mostro il risultato 
della query in un DBGrid, quindi facevo il free a chiusura form. 
 

Cerco di spiegarlo con un paio di casi:
 
a) utilizzo la query per dei calcoli, non necessariamente all'interno di un form
 
procedure MyProc( var FQry: TQuery );
begin
  ....
end;
 
procedure Estrai;
var FQry: TQuery;
begin
 // creazione
  FQry := TQuery.Create(Nil);
 
 // chiamata a MyProc
  MyProc( FQry );
 
 // utilizzo il risultato ...
  ... 
 
 // Libera
  FreeAndNil( FQry );
end;
 
 
b) utilizzo la query per visualizzazioni che termineranno con la chiusura del form
 
type
  TForm1 = class(TForm)
  private
    FQry: TQuery;
  end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 // Creazione
  FQry := TQuery.Create(Self);
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
 // Libera
  FreeAndNil( FQry );
end;
 
procedure TForm1.Estrai;
begin
 // Creazione alternativa, se non già fatto in precedenza
 if FQry = Nil
   then FQry := TQuery.Create(Self);
 
 // chiamata a MyProc
  MyProc( FQry );
 
 // utilizzo il risultato ...
  ... 
end;
 
 
In questo secondo caso, la query è create associata al form, quindi verrebbe comunque liberata alla chiusura del form.
Io comunque sono sempre per a liberarla deve provvedere il programmatore
 
 
P.S. di solito il mio "libera" è scritto in modo leggermente diverso... per evitare visualizzazioni di errori
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
 // Libera
 try
  FreeAndNil( FQry );
 except
 end;
end;
 
 
 
 

... per inciso non sarebbe neppure necessario passare la query per "var"
 
procedure MyProc( var FQry: TQuery ); 
begin 
  .... 
end; 
 
visto che è un oggetto!
 
procedure MyProc( FQry: TQuery ); 
begin 
  .... 
end; 
 

 servono sei diverse estrazioni con sei diversi TQuery ?
Detto sopra ...
 
Fai sapere come procede !!!
 
Ciao
 
Daniele
 
PS: Hai preso in considerazione l'idea di utilizzare i FRAME ?
 
 

Sto leggendoti...  vedo di capire bene e poi ci rifletto, ma nel frattempo 
volevo ringraziarti 
 

 
 
"alessandrob"  ha scritto nel messaggio 
news:1fb2e61e-aae5-43e5...@googlegroups.com...
 
Cerco di spiegarlo con un paio di casi:
 
a) utilizzo la query per dei calcoli, non necessariamente all'interno di un 
form
 
procedure MyProc( var FQry: TQuery );
begin
  ....
end;
 
procedure Estrai;
var FQry: TQuery;
begin
// creazione
  FQry := TQuery.Create(Nil);
 
// chiamata a MyProc
  MyProc( FQry );
 
// utilizzo il risultato ...
  ...
 
// Libera
  FreeAndNil( FQry );
end;
........................
OK. Dove tu hai scritto 'utilizzo il risultato in effetti la mia proc fa dei 
calcoli sui risultati e carica una StringGrid per mostrare i dettagli. 
Adesso però volevo implementare la possibilità di mostrare l'intero 
risultato della query,oltre che nella StrinGrid che riporta solo i dati più 
significativi, in un DBGrid dove mostro tutto il contenuto di tutti i campi. 
In questo caso, non posso liberare FQry.. è così no?
Quindi è la seconda soluzione che dovrei adottare.
 

 caso, non posso liberare FQry
Esatto non puoi ... altrimenti perdi tutto.
Fai come ti e' stato suggerito ovvero, per toglierti tutto dal pensirero:
Se nella form metti 6 dbgrid (anche se imposti visible:=False) allora metti 
anche 6 datasource e 6 datataset.
Non importa se poi non li usi ... per adesso va bene cosi' (piu' avanti li 
farai dinamici ...)
Ogni griglia ha il suo set personalizzato, ovvero la sua query e il suo 
risultato indipendente dalle altre.
 
In questo modo, quando chiudi la form, ci pensa lei a distruggere il tutto.
 
Parti con calma da qui e piani piano esplora come si puo' fare in modo 
dinamico ....
Pero' devi avere le idee un piu' chiare, per esempio ogni componente che 
crei DEVE avere un nome !
 
Come ti suggerivo prima, considera i FRAME.
Il FRAME e' una "specie" di form che crei come tu vuoi; nel tuo caso una 
grigla, un dataset, un data source, una label, un bottone ecc...
Nel FRAME scrivi il codice che ti serve.
 
Lato FORM
Ti crei un contenitore (per esempio uno scrollbox, pannello o altro) vuoto 
che riempi al bisogno con FRAME
Al bisogno, non necessariamente nel formcreate, metti il tuo frame.
Come lo metti?
Cosi'
 
Procedure AddFRame
Var MyFrame : TMyFrame;
Begin
    MyFrame:=TMyFrame.Create;
    MyFrame.Name:=Un_Nome + IntTostr(INDICE DEI FRAME CREATI);
    MyFrame.Parent:=IlPanello o il tscroll box o quello che decidi tu
    Ora hai un frame funzionante nella form ...
End;
 
A te la gestione del frame ...
 
Ciao
 
Daniele
 

 Quindi è la seconda soluzione che dovrei adottare.
 
Ti confermo che se vuoi che il contenuto della query sia visualizzato in una griglia per tutta l'esistenza del form devi seguire la seconda soluzione.
 
Inoltre, se non ho capito male, cerchi di copiare il contenuto della query in StringGrid... Credo tu possa farlo perché hai a che fare con un numero contenuto di record
 
Normalmente si cerca di sfruttare al meglio la sintassi SQL per estrarre direttamente il risultato da visualizzare e la visualizzazione della DbGrid è sicuramente più ottimizzata come prestazioni rispetto a un insieme di stringhe per visualizzare anche un numero elevato di righe