PDA

Visualizza la versione completa : [DELPHI] Bloccare/terminare un thread


VaLvOnAuTa
22-05-2006, 15:26
Ho creato un form che funge da "alert popup" (alla google desktop o msn messenger). All'evento OnShow, viene creato un Thread che dopo 10 secondi dovrebbe far chiudere la popup. E funge bene. Ora il problema è che, all'evento OnClose del popup bisognerebbe distruggere il thread. Il fatto è che se non lo distruggo, il thread continua ad eseguirsi (sballandomi i valori al successivo riavvio del popup), mentre se lo distruggo alla chiusura del popup mi si pianta l'applicazione.
procedure TThreadTimer.Dissolve;
var i : byte;
begin
Timer.Terminate;
for i:=255 downto 0 do
Popup.AlphaBlendValue := i; // effetto dissolvenza
Popup.Close;
end;


procedure TThreadTimer.Execute;
var i: integer;
begin
i := 0;
while true do
begin
sleep(1000);
i := i + 1000;
Popup.LblInfo.Caption := IntToStr(10-(i div 1000));
if i = 10000 then
Synchronize(Dissolve);
end;
end;

procedure TPopup.FormShow(Sender: TObject);
begin
AlphaBlendValue := 0;
Timer := TThreadTimer.Create(false);
Timer.FreeOnTerminate := true;
end;

procedure TPopup.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Timer.Destroy;
end;Cosa c'è che non va in questo codice? :bhò:

alka
22-05-2006, 17:18
Generalmente, il thread termina quando l'esecuzione del metodo Execute si conclude, ma nel tuo caso ciò non avviene mai perché hai inserito in sostanza un ciclo infinito.

Per consentire al thread di concludersi correttamente, modifica il tuo ciclo in questo modo:



while not Terminated do
begin
// istruzioni del thread
end;


Per determinare la conclusione dei lavori del thread, è sufficiente impostare la proprietà Terminated al valore True. Prendendo il tuo esempio:



procedure TThreadTimer.Dissolve;
var i : byte;
begin
for i:=255 downto 0 do
Popup.AlphaBlendValue := i; // effetto dissolvenza
Popup.Close;
Self.Terminated := True;
end;


Ciao! :ciauz:

VaLvOnAuTa
22-05-2006, 17:40
Sì in effetti avevo già fatto una modifica in tal senso.
(Anche se non è possibile impostare un valore alla proprietà Terminated; esiste la funzione apposta "Terminate" :D)
Il problema è che se riapro la popup, imponendo nuovamente un Thread.Execute, mi vede il thread sempre come "Terminated" infatti non comincia alcun countdown.
Avevo modificato così:

procedure TThreadTimer.Execute;
var i: integer;
begin
i := 0;
Popup.LblInfo.Caption := IntToStr(10-(i div 1000));
while not(Terminated) do
begin
sleep(1000); // un secondo
i := i + 1000;
Popup.LblInfo.Caption := IntToStr(10-(i div 1000)); // mostra i secondi che mancano
if i = 10000 then
begin
Timer.Terminate;
Synchronize(Dissolve);
end;
end;
end;

procedure TPopup.FormShow(Sender: TObject);
begin
AlphaBlendValue := 0;
if Timer.Terminated then
Timer.Execute;
end;
Però in questo modo, quando ricompare la popup, il counter è fermo a 10 e non entra mai nel ciclo while (probabilmente perchè Terminated è true ma non è possibile assegnare valori, dato che Terminated è read-only)

alka
22-05-2006, 17:47
Originariamente inviato da VaLvOnAuTa
Anche se non è possibile impostare un valore alla proprietà Terminated; esiste la funzione apposta "Terminate"

Sì, un lapsus, mi ricordavo male.


Originariamente inviato da VaLvOnAuTa
Il problema è che se riapro la popup, imponendo nuovamente un Thread.Execute, mi vede il thread sempre come "Terminated" infatti non comincia alcun countdown.

E' ovvio. Quel thread è già esaurito. Non puoi rilanciare lo stesso thread, o meglio puoi lanciarlo se non lo hai terminato, ma in questo caso è così.

Avendo impostato peraltro FreeOnTerminate a True, l'oggetto legato al thread viene pure distrutto.

Non ti rimane che creare semplicemente un nuovo thread ogni volta che ne hai bisogno.

Ciao! :ciauz:

VaLvOnAuTa
22-05-2006, 17:58
Hai ragione. Grazie. :ciauz:

Loading