![]() |
FMX + UI aktualisieren
Danke für Euer Schwarmwissen :- )
Ich habe einen FMX Form, rufe eine Operation auf, die länger dauert und möchte währenddessen eine Statusinformation ausgeben. Ich habe mehrere Möglichkeiten zur Auswahl: TTaks.Run() und Synchronize() TEvent benutzen. Dann schickt der Task Nachrichten und das UI wertet mit einem Timer diese aus. TTask und ThreadedQueue<string> benutzen und auch mit einem Timer aus dem UI auslesen. Fehlt was? Wie macht Ihr das am elegantesten? |
AW: FMX + UI aktualisieren
Zitat:
@TigerLilly Wie häufig willst Du Updates senden, wie lange dauert das entsprechende Update der UI? Viele Events, längere UI-Updates, dann TEvent-Ansatz, veraltete Informationen verwerfen und aktuelle darstellen. Einfaches Update und nur wenige Update-Quellen (Threads), dann ggf. über Synchronize, aber bitte bedenken, dass der Thread pausiert wird, bis das UI-Update durch ist. ...:cat:... |
AW: FMX + UI aktualisieren
Also...
Du startest einen Thread und in diesem Thread willst Du die UI aktualisieren... Die richtige Antwort hängt von Deiner intention ab... 1.) Willst Du unbedingt alle UI Updates zeigen: Synchronize 2.) Ist es Dir egal, ob die UI alle Zwischenwerte anzeigt: Queue Ist Deine Statusupdate sehr schnell: Werte nur dann aktualisieren, wenn seit dem letzten update wenigsten z.B. 500ms vergangen sind prüfen und dann wieder genau wie unter 1 und 2. Jedenfalls keinen Timer! Mavarik |
AW: FMX + UI aktualisieren
Warum keinen Timer? Sonst brauche ich eine Schleife.
|
AW: FMX + UI aktualisieren
Ich starte die Verarbeitung in einem Thread und habe in der UI einen Timer, der alle x ms prüft, ob in der Queue für UI-Updates etwas drinnen steht. Der Thread befüllt dann diese Queue.
|
AW: FMX + UI aktualisieren
Du hast TMessageManager vergessen.
Ich schicke (publish) gerne eine TMessage die mit TThread.Queue abgesichert an mein UI. Dann braucht können sich ein oder mehrere UI's subscriben, ohne sich drum zu kümmern woher die Message kommt. |
AW: FMX + UI aktualisieren
Zitat:
Zitat:
Delphi-Quellcode:
TThread.Queue(NIL,Procedure...
Zitat:
Aber warum nicht einfach so:
Delphi-Quellcode:
procedure TForm319.UpdateUI(aNewValue : Integer);
begin TThread.Queue(NIL,Procedure begin if Assigned(Button1) then // Form Closed? Button1.Text := aNewValue.ToString; end); end; procedure TForm319.Button1Click(Sender: TObject); begin Button1.Enabled := false; TTask.Run(Procedure var LastOut : TDateTime; i : Integer; begin LastOut := NOW; for i:=0 to 600 do // 1 Min. begin sleep(100); if MilliSecondsBetween(LastOut,Now) > 500 then begin if not(Assigned(Button1)) then // Form Closed? exit; UpdateUI(i); LastOut := Now; end; end; if Assigned(Button1) then Button1.Enabled := true; end); end; |
AW: FMX + UI aktualisieren
Ich habe auch noch nicht verstanden was gegen einen Timer spricht.
Einfacher kann ich nicht kontrollieren dass auf der Oberfläche nicht 100 mal neu gepinselt wird und sich in Wirklichkeit die Progressbar nur 2 Millimeter weiterbewegt. Wenn ich die Klasse ändere will ich mir keine Gedanken machen müssen wer wohl an den OnChange-Events dranhängen könnte und ob ich auf den Rücksicht nehmen muss nicht "zu oft" oder "zu viele Infos" zu liefern. Und einen Timer versteht jeder. Der muss ja auch nur nachschauen ob es was neues gibt, und das kostet keine Zeit. Und nur wenn es etwas neues gibt, dann muss ich in meiner Oberfläche etwas pinseln. |
AW: FMX + UI aktualisieren
Zitat:
Ich will auch nicht für jedes Update aus einen Thread nen dummen Timer habe, den ich jeden smal vorher starten und nach der Verarbeitung wieder anhalten muss. ggf. Habe ich 10 Thread die etwas machen - soll ich dafür 10 Timer nehmen, 10 Queues erzeugen und alles per TMonitor sperren? Mein Form/View ist Dumm und hat so wenig code wie möglich den ich pflegen muss... Ich will das mein UI schneller aktualisiert wird - kein Thema dann mache ich die Einstellungen da wo ich weis was Sache ist und nicht in der View(Form). Klar ist mein Beispiel in einem Button-Click aber das war auch nur dafür, dass man es schnell mal testen kann... Sowas kommt in einen andere Unit. Mavarik :coder: |
AW: FMX + UI aktualisieren
Zitat:
Nehmen wir als Beispiel einen Download-Manager der zehn Dateien gleichzeitig herunterlädt. Da ändere ich doch nicht den Code für das Herunterladen um anzupassen wie schnell die Anzeige auf einem Formular aktualisiert werden soll indem ich weniger Status-Updates triggere. Klar gehört in die Anzeige keine Logik. Aber du wirst ja auf dem Formular auch nicht mit irgendwelchen Sperr/Synchronisations-Mechanismen hantieren sondern da sitzt doch sicher irgendeinen Mittelsmann dazwischen die nur die Aufgabe hat zu sagen was grade abgearbeitet wird und wie der Fortschritt ist.
Delphi-Quellcode:
->
Timer
Delphi-Quellcode:
->
OnTimer
Delphi-Quellcode:
.
viewModel.updateProgress();
|
AW: FMX + UI aktualisieren
In meiner Anwendung läuft eine Uhr mit, daher habe ich eh einen Timer am Laufen und dieser updated bei Bedarf dann auch weitere Elemente der Anzeige. Wenn man so etwas wie diese Uhr nicht hat, mag der Timer ineffektiv sein. So ist es die einfachste und übersichtlichste Lösung.
|
AW: FMX + UI aktualisieren
Zitat:
Der Timer kann zu ungenau sein für eine Uhr. Für eine Uhr würde ich immer die Systemzeit nehmen, z.B. mit Now();, und diese dann z.B. mit dem Timer (oder anders) aktualisiert anzeigen. |
AW: FMX + UI aktualisieren
Zitat:
Dann ggf. noch eine Uhr, eine Statusanzeige die anzeigt, dass die Datenbank sich mit der Cloud synchronisiert. Die Aktien chart, die upgedatet werden muss, uvm. Und warum soll ich permanent einen Timer laufen lassen der immer wieder in einer Queue nachschaut, wenn es (wie mein Beispiel (#8) gezeigt habe) viel einfacher geht? Ich möchte keinen Timer haben der immer läuft - schon gar nicht, wenn er permanent in einer Queue nachschauen muss die jedes mal hierfür ein locking durchführen muss. Auf einem 5GHz PC mag das egal sein, aber sicherlich nicht in einer App die auf Batteriestrom läuft (z.B. Mobil-Device/Smartwatch). Zitat:
|
AW: FMX + UI aktualisieren
Ja, so war es mit dem Timer gemeint. Ich prüfe alle x Millisekunden, ob ich die Zeit, welche ich über NOW vergleiche, hochzählen muss. Und prüfe dann parallel, ob es sonst noch was in meiner Anwendung zu tun gibt (und das ist reichlich: UI-Updates, aktuell abgespieltes Musik/Video anpassen, …). Und drum herum passiert einiges in Threads.
Und meine Queue ist eine einfache TObjectList oder ein Dictionary (je nach Anwendungsfall), ich vermeide Locks und verhinderte auch, dass das gleiche Objekt mehrfach in der UI aktualisiert wird. Geht sicherlich eleganter, aber funktioniert und ich vermeide synchronized und Locks, wo es nur geht. |
AW: FMX + UI aktualisieren
Zitat:
|
AW: FMX + UI aktualisieren
Sowohl beim Auslesen als auch beim Hinzufügen/Updaten von Einträgen gibt es ein try/catch, damit Fehler gefangen werden und in dem Fall bleibt dann mal ein Update der UI-Info aus. Das ist bei mir okay und spart Synchronisierungen.
|
AW: FMX + UI aktualisieren
Zitat:
|
AW: FMX + UI aktualisieren
War wie gesagt ("das ist bei mir okay") eine bewusste Entscheidung. Mit ein paar Zeilen zusätzlichen Code würde ich es threadsafe bekommen, aber da sich die Anzeige eh alle 500ms ändert, kann ich auf einige Updates dort auch verzichten, dafür laufen die Videos in der Anzeige flüssiger. Da muss man aber die jeweilige Anwendung genauer kennen, um zu wissen, ob dies geht oder nicht.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:46 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