2013-06-04 19 views
5

próbuję umieścić indy TIdHttp w wątku, Próbowałem to:Odczekaj wątku bez zamrażania aplikacji

type 
    TSendThread = class(TThread) 
    private 
    { Private declarations } 
    protected 
    procedure Execute; override; 
    public 
    http : TIdHTTP; 
    URL : String; 
    Method : String; 
    property ReturnValue; 
    end; 

procedure TSendThread.Execute; 
begin 
    form1.Memo1.lines.Add(http.Get(URL)); 
    ReturnValue := 1; 
end; 

A w głównym:

procedure TForm1.Button1Click(Sender: TObject); 
var t : TSendThread; 
begin 
    t := TSendThread.Create(true); 
    t.URL := 'http://www.url.com/'; 
    t.http := http; 
    t.Start; 
    showmessage(IntToStr(t.ReturnValue)); 
end; 

Mój problem o to, że następna instrukcja zostanie wykonana (showmessage) bez czekania na wykonanie nici, spróbowałem użyć "WaitFor", ale to zamroziło aplikację.

Czy istnieje inne obejście problemu?

Dziękuję.

+3

Jeśli „czeka na to”, aby zakończyć, nie ma potrzeby, aby umieścić go w wątku w pierwszej kolejności. Wątki są wykonywane w tle, więc interfejs użytkownika * nie musi czekać. –

+0

@Benjamin: Jeśli musisz użyć 'ProcessMessages', dodałeś teraz nowy problem. To ** nigdy ** właściwe rozwiązanie. –

+0

'ProcessMessages' jest OK, gdy jest używany ostrożnie – OnTheFly

Odpowiedz

9

Użyj zdarzenie TThread.OnTerminate wiedzieć, kiedy wątek zakończył:

type 
    TSendThread = class(TThread) 
    private 
    http : TIdHTTP; 
    Line: string; 
    procedure AddLine; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create; reintroduce; 
    destructor Destroy; override; 
    URL : String; 
    Method : String; 
    property ReturnValue; 
    end; 

constructor TSendThread.Create; 
begin 
    inherited Create(True); 
    FreeOnTerminate := True; 
    http := TIdHTTP.Create; 
end; 

destructor TSendThread.Destroy; 
begin 
    http.Free; 
    inherited; 
end; 

procedure TSendThread.Execute; 
begin 
    Line := http.Get(URL); 
    Synchronize(AddLine); 
    ReturnValue := 1; 
end; 

procedure TSendThread.AddLine; 
begin 
    Form1.Memo1.Lines.Add(Line); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    t : TSendThread; 
begin 
    t := TSendThread.Create; 
    t.URL := 'http://www.url.com/'; 
    t.OnTerminate := ThreadTerminated; 
    t.Start; 
end; 

procedure TForm1.ThreadTerminated(Sender: TObject); 
begin 
    ShowMessage(IntToStr(TSendThread(Sender).ReturnValue)); 
end; 

Jeśli chcesz użyć pętli czekać na wątek zakończyć, bez blokowania interfejsu użytkownika, możesz to zrobić tak:

constructor TSendThread.Create; 
begin 
    inherited Create(True); 
    //FreeOnTerminate := True; // <-- remove this 
    http := TIdHTTP.Create; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    t : TSendThread; 
    h : THandle; 
begin 
    t := TSendThread.Create; 
    try 
    t.URL := 'http://www.url.com/'; 
    t.Start; 
    h := t.Handle; 
    repeat 
     case MsgWaitForMultipleObjects(1, h, 0, INFINITE, QS_ALLINPUT) of 
     WAIT_OBJECT_0: Break; 
     WAIT_OBJECT_0+1: Application.ProcessMessages; 
     WAIT_FAILED:  RaiseLastOSError; 
     else 
     Break; 
     end; 
    until False; 
    ShowMessage(IntToStr(t.ReturnValue)); 
    finally 
    t.Free; 
    end; 
end; 
+1

Benjamin Weeiss ma rację. Odpowiednio zaktualizowałem swoją odpowiedź. –

+0

yep thats co ja też zrobiłem :). Dziękuję bardzo, szukałem tego przez 2 dni –

Powiązane problemy