2015-07-15 6 views
5

Ich verwende Delphi anonymen Thread, um Code auszuführen. In der Mitte des Threads, ein paar GUI-Updates müssen stattfinden, ein paar Etiketten ändern etc.Wie GUI von Thread mit Delphi zu aktualisieren

Wenn ich dies innerhalb des Threads tun, die Änderungen stattfinden, aber sobald der Thread stoppt . sie verschwinden, und dann die Anwendung gibt mir das alte Fehlerfenster Handler ... (was zu erwarten ist)

System Error. Code:1400. Invalid window handle

ich die Syncronize(updateui); Methode versucht, mit den Änderungen auszuführen (bewegte sie in eine separaten Funktion), aber ich bekomme einen Fehler auf der E2066 Missing operator or semicolon Syncronize, die für mich überhaupt keinen Sinn macht ...

Ich habe Seite für Seite durchsucht, und sie alle scheinen es so zu nennen, aber wenn ich es tue, Ich bekomme den obigen Fehler ...

Rufe ich es falsch?

Code:

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

Sie ** darf nicht ** Zugriff auf die Kontrollen von einem anderen Thread bei ** alle **. Kein Schreiben und kein Lesen! –

+0

@SirRufo Ich muss ... Es gibt viele Änderungen zwischen den Datenbankaktionen. Jede Datenbankaktion benötigt etwas Zeit, und die Haupt-GUI sieht genauso aus, wie wenn sie nicht in einem Thread ausgeführt wird. Also muss ich alles oder nichts fädeln ... – Marcel

+0

Ich habe nicht gesagt "Benutze keinen Thread". Ich sage nur: "Greife nicht auf die Steuerelemente eines anderen Threads zu als auf den MainThread" ( –

Antwort

10

Verwenden TThread.Synchronize und andere anonyme Funktion es passieren. Dann können Sie updateUI in der anonymen Funktion aufrufen:

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

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

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

Synchronisationen im Allgemeinen teuer sind (in Bezug auf die Leistung). Tue sie nur, wenn sie wirklich nötig sind. Sie können die Leistung erhöhen, wenn Sie die updateui -Methode erweitern, um Paint-Operationen zu reduzieren.

Dies ist möglich, einen Anruf zu SendMessage mit 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; 

einen Aufruf an StopDrawing Add() an der Spitze des updateUI() und einen Aufruf von ContinueDrawing() bei das Ende updateui(). Der Aufruf an ContinueDrawing() sollte in einem finally-block sein. Dadurch wird sichergestellt, dass das Fenster auch dann gezeichnet wird, wenn während der Ausführung von updateui eine Ausnahme aufgetreten ist.

Beispiel:

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

) Fantastic you gold star :), Vielen Dank, dass es wie ein Zauber funktioniert hat. – Marcel

+0

Marcel Wenn Sie die Kommentare Ihrer vorherigen Frage gelesen haben, ist diese Antwort genau das, was wir Ihnen gesagt haben .... – whosrdaddy

+1

Ich glaube, cnStartDrawing = 0; sollte cnStartDrawing = 1 sein; –

Verwandte Themen