![]() |
Label aktualisieren / TTask
Hallo,
ich bin ja aktuell dabei, mein Android Projekt von XE8 auf XE 10.3.3 umzustellen. Während in der 8 noch intensiv mit Application.Processmessages gearbeitet wurde (ja, war und ist böse, aber der Zweck heiligt die Mittel) funktioniert das ja in 10.3.3 nicht so wie bisher. Ich habe zB TAniIndicator. Wenn nun in der App etwas Rechenintensives passiert oder die App einfach mal auf was warten muss, dann wurde der TAniIndicator bisher mit Processmessages erfolgreich aktualisiert. Das klappt nun nicht mehr und sieht blöd aus, so als wenn alles hängt. Also versuche ich es so:
Code:
Habe dann versucht, über einen HG-Thread die Proc dauernd zu aktualisieren:
procedure ...UpdateComponents;
begin ... If (progPlsWait) then progPlsWait.Repaint; ... end;
Code:
... und, wenn die Berechnung durch ist, das ganze freizugeben
CompUpdateTask := TTask.Create(
procedure begin Sleep(50); TThread.Synchronize(TThread.Current, procedure begin UpdateComponents; end); end); CompUpdateTask.Start;
Code:
So, der Profi lacht, aber das funktioniert nicht, TAniIndicator wird nicht aktualisiert. Was mache ich falsch? Durchläuft CompUpdateTask nur einmal und ist danach tot, wie ein Thread auch?
CompUpdateTask.Cancel;
FreeAndNil(CompUpdateTask); |
AW: Label aktualisieren / TTask
Zitat:
Stelle dir einfach vor, die anonyme Funktion wäre das Execute einer klassischen TThread-Instanz. Dann startet der Thread, wartet 50 Millisekunden und ruft einmal (!) TThread.Synchronize auf. |
AW: Label aktualisieren / TTask
Ah, ok, quasi "while not terminated"? Wenn ich es recht verstehe, muss ich "CheckCanceled" aufrufen, das wirft eine Exception, wenn abgebrochen werden soll.
Passt das so? Die While Bedingung ist echt dumm.
Code:
CompUpdateTask := TTask.Create(
procedure begin While (1=1) do begin CompUpdateTask.CheckCanceled; Sleep(500); TThread.Synchronize(TThread.Current, procedure begin UpdateComponents; end); End; end); CompUpdateTask.Start; |
AW: Label aktualisieren / TTask
Und "eventuell" aufpassen, dass
Delphi-Quellcode:
nicht im Hauptthread ausgeführt werden (vor allem niemals innerhalb von UpdateComponents),
CompUpdateTask.Cancel;
FreeAndNil(CompUpdateTask); denn wenn Cancel oder Free warten, während das Synchronize hängt, dann hast einen Deadlock. Tipp: Auch in das Synchronize am Anfang ein CheckCanceled rein. |
AW: Label aktualisieren / TTask
Zitat:
FreeAndNil war übrigens auch blöd, ein := NIL besser. Nachtrag: Funktioniert übrigens nicht, TAniIndicator wird, genau wie Labels, nicht aktualisiert; repaint reicht wohl nicht. Die 'Arbeit' kann ich auch nicht auslagern, ich muss zB einen Browser aufrufen und der läuft im Hauptthread. Während ich auf den Warte, tut sich unter 10.3.3 dann mal nix, auch kein drehendes 'Bitte warten' Icon. Irgendwie war das mit Processmessages einfacher. Zumindest hat sich was getan für den User. |
AW: Label aktualisieren / TTask
Ich verzweifel noch. Ich benötige ein funktionierendes Delay, also um etwas bei Bedarf künstlich zu verzögern. Nehmen wir als Beispiel eine Testversion: Wenn es sich bei der App um eine Testversion handelt, dann soll 10 Sekunden gewartet werden (Delay 10), ansonsten direkt weitergemacht werden. Ich bekomme es einfach nicht hin. Es wird zwar gewartet, in der Wartezeit werden aber keine Nachrichten verarbeitet, ich kann also kein Warte-Progress anzeigen.
Unter Windows ganz einfach:
Code:
Im Android funktioniert zwar die Wartezeit (klar, was soll auch passieren), es wird aber nichts verarbeitet, da Processmessages nicht funktioniert. Habe es auch schon mit einem Thread versucht in der Hoffnung, dass während 'WaitFor' Nachrichten wie Repaint verarbeitet werden ... Geht aber auch nicht. Obwohl ich Label.Repaint aufrufe, sehe ich die Änderungen auf dem Handy nicht. Beispiel:
Ende := GetTickCount+mSek;
While (Ende>GetTickCount) do begin Sleep(5); Application.ProcessMessages; end;
Code:
Ist ein nonsens Code. Im Ergebnis ist entweder nichts sichtbar. Oder nur 'Fertig', selbst wenn ich im Delay "Label1.Repaint" aufrufe. Mache ich das unter Windows, dann steht dort im Sekundentakt 'Hallo' / 'Welt' / 'Bin' / 'Fertig'. Selbst mit einem Timer kann ich es nicht lösen, weil ich ja auch auf seine Beendigung warten muss.
Label1.Text := 'Hallo';
Delay(1000); Label1.Text := 'Welt'; Delay(1000); Label1.Text := 'Bin'; Delay(1000); Label1.Text := 'Fertig'; Bin ich wirklich der einzige, der sowas braucht? |
AW: Label aktualisieren / TTask
Ich hab so ein ähnliches Problem mit einem Timer gelöst. Der Timer feuert jede Sekunde, dann kanst du eine Bedingung testen und dann zB eine Bedingung umschalten.
|
AW: Label aktualisieren / TTask
Wenn das System grundsätzlich nicht mit "derartigen" Messages arbeitet, dann bringt es auch nicht viel die Messages verarbeiten zu wollen, welche es nicht gibt.
Hier mal der Pfad für Android: Thread.Synchronize und Application.OnIdle :zwinker:
Delphi-Quellcode:
Ich weiß nicht wie Android seine "Events" verwaltet und ob es in Delphi, bzw. im ADK eine API gibt, womit man anstehende Events jetzt verarbeiten kann ... wenn ja, dann sollte Emba Dieses aber besser mal ins ProcessMessages/HandleMessage einfügen.
procedure TApplication.ProcessMessages; // das aus FMX.Forms.pas
var AppService: IFMXApplicationService; begin if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationService, AppService) then while AppService.HandleMessage do { loop }; end; function TPlatformAndroid.HandleMessage: Boolean; begin InternalProcessMessages; Result := False; end; procedure TPlatformAndroid.InternalProcessMessages; begin CheckSynchronize; ProcessOnIdleEvent; end; |
AW: Label aktualisieren / TTask
Zitat:
|
AW: Label aktualisieren / TTask
@greenmile: Ich glaube, du musst umdenken. Sowas wie "warten" funktioniert nicht. Du kannst "nachschauen", ob dein Thread schon fertig ist. Dein "Nag-Screen" wäre vielleicht so zu implementieren:
- MainForm anzeigen - Thread starten + am Mainform ein Panel mit Infos anzeigen - gleichzeitig einen Timer starten, der jede Sekunde nachschaut, ob der Thread schon fertig ist - wenn ja, das Panel verstecken und den mainform "freigeben" und den Timer beenden Hat für mich das Problem "Form schließen wenn Task noch läuft" gut gelöst. Aber ich bin offen für Fortbildung. :-) |
AW: Label aktualisieren / TTask
Die Logik habe ich inzwischen (zähneknirschend) verstanden. Nur ... Wenn ich zwischen zwei Funktionen den Text von einen Label ändere, dann sehe ich die Aktualisierung nicht. Es muss doch irgendwie möglich sein, den Label zu aktualisieren. Also, versteh mich nicht falsch und ich bin wirklich dankbar für jede Hilfe. Aber irgendwie muss FMX die ja auch aktualisieren. Oder muss ich mich wirklich blind drauf verlassen, dass FMX die Änderung in eine Art Cache schreibt und Android entscheidet, wann der Bildschirm neu gezeichnet wird?
|
AW: Label aktualisieren / TTask
Schau mal, da ist ein Beispiel:
Code:
Hilft das?
fTask := TTask.Run(procedure()
var i:integer; begin for i:=1 to 1000 do begin if TTask.CurrentTask.Status = TTaskStatus.Canceled then break; Sleep(10); // damit zeit vergeht ... TThread.Synchronize(nil, procedure() begin Button1.Text := DateTimeToStr(Now); end); end; TThread.Synchronize(nil, procedure() begin Button1.Enabled := true; Button1.Text := 'Start Task'; // beschriftung wiederherstellen end); end); |
AW: Label aktualisieren / TTask
gelöscht. Bin mir unsicher ob das hilfreich war.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz