2015-07-15 14 views
5

Używam anonimowego wątku Delphi do wykonania kodu. W środku wątku musi się odbyć kilka aktualizacji GUI, zmiana etykiet itd.Jak zaktualizować GUI z wątku używając Delphi

Jeśli zrobię to z poziomu wątku, zmiany będą miały miejsce, ale jak tylko wątek się zatrzyma . znikają, a następnie aplikacja daje mi stare okno obsługi błędów ... (co jest do przewidzenia)

System Error. Code:1400. Invalid window handle

Próbowałem przy użyciu metody Syncronize(updateui); wykonać zmiany (przeniesiono je do osobnej funkcji), ale dostaję błąd w synchronizacji E2066 Missing operator or semicolon, który nie ma dla mnie żadnego sensu ...

Przeszukałem stronę po stronie i wszystkie one nazywają to w ten sposób, ale kiedy to robię, Otrzymałem powyższy błąd ...

Czy nazwałem to nieprawidłowo?

Kod:

TThread.CreateAnonymousThread(
procedure 
begin 
main.Enabled:=false; 
Loading.show; 
label52.caption:=getfieldvalue(datalive.users,'users','credit_amount','user_id',user_id); 
CoInitialize(nil); 
    if (length(maskedit1.Text)=maskedit1.MaxLength) and (pingip(serverip)=true) then 
    begin 
     if (strtofloat(label52.caption)>0) then 
     begin 
      ....do some work.... 

      Synchronize(updateui); 
     end 
     else Showmessage('Insufficient Funds. Please add funds to continue.'); 
    end 
    else if (length(maskedit1.Text)<>maskedit1.MaxLength) then 
    begin 
    Showmessage('ID Number not long enough.'); 
    end 
    else 
    begin 
    Showmessage('Could not connect to the server. Please check your internet connection and try again.'); 
    end; 
CoUnInitialize; 
loading.close; 
main.Enabled:=true; 
end).start; 

UpdateUI:

procedure TMain.updateui; 
var 
birthdate,deathdate:TDate; 
begin 
Panel3.Show; 

Label57.Caption := 'Change 1'; 
Label59.Caption := 'Change 2'; 
Label58.Caption := 'Change 3'; 
Label60.Caption := 'Change 4'; 
Label62.Caption := 'Change 5'; 
Label70.Caption := 'Change 6'; 


ScrollBox1.Color := clwhite; 
end; 
+3

Ty nie wolno ** ** dostęp kontrole z innego wątku w ogóle ** **. Bez pisania i bez czytania! –

+0

@SirRufo Muszę ... Istnieje wiele zmian między akcjami bazy danych. Każda operacja bazy danych zajmuje trochę czasu, a główny interfejs GUI wygląda tak, jakby nie działał w wątku. Muszę więc nić to wszystko albo nic ... – Marcel

+0

Nie powiedziałem "Nie używaj nici". Po prostu mówię "Nie otwieraj (czytaj/pisz) kontrolek z dowolnego wątku innego niż MainThread" –

Odpowiedz

10

Zastosowanie TThread.Synchronize i przekazać kolejną anonimową funkcję do niego. Następnie można wywołać updateui w funkcji anonimowej:

TThread.CreateAnonymousThread(
    procedure 
    begin 
    // do whatever you want 

    TThread.Synchronize(nil, 
     procedure 
     begin 
     updateui(); 
     end); 

    // do something more if you want 
    end 
).Start(); 

Synchronizacji są generalnie drogie (odnośnie wydajności). Wykonuj je tylko wtedy, gdy są naprawdę potrzebne. Możesz zwiększyć wydajność, jeśli rozszerzysz metodę updateui, aby zmniejszyć liczbę operacji malowania.

Jest to możliwe do wywołania SendMessage z WM_SETREDRAW:

procedure StopDrawing(const Handle: HWND); 
const 
    cnStopDrawing = 0; 
begin 
    SendMessage(Handle, WM_SETREDRAW, cnStopDrawing, 0); 
end; 

procedure ContinueDrawing(const Handle: HWND); 
const 
    cnStartDrawing = 0; 
begin 
    SendMessage(Handle, WM_SETREDRAW, cnStartDrawing, 0); 

    // manually trigger the first draw of the window 
    RedrawWindow(Handle, nil, 0, 
    RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN); 
end; 

dodać wywołanie do StopDrawing() na szczycie updateui() i wywołaniu ContinueDrawing() w koniec updateui(). Wywołanie do ContinueDrawing() powinno być w finally-block. Zapewni to, że okno będzie malowane nawet po wystąpieniu wyjątku podczas wykonywania aktualizacji.

Przykład:

procedure TMain.updateui; 
begin 
    try 
    StopDrawing(Handle); 

    Panel3.Show; 

    Label57.Caption := 'Change 1'; 
    Label59.Caption := 'Change 2'; 

    // ... 
    finally 
    // Code under finally gets executed even if there was an error 
    ContinueDrawing(Handle); 
    end; 
end; 
+0

Fantastyczna złota gwiazda :), Dziękuję bardzo, że działało jak czar. – Marcel

+0

Marcel, jeśli przeczytałeś komentarze poprzedniego pytania, ta odpowiedź jest dokładnie tym, co powiedzieliśmy ... – whosrdaddy

+1

Wierzę, że cnStartDrawing = 0; powinno być cnStartDrawing = 1; –

Powiązane problemy