Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   FMX + UI aktualisieren (https://www.delphipraxis.net/202388-fmx-ui-aktualisieren.html)

TigerLilly 29. Okt 2019 13:19

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?

sakura 29. Okt 2019 14:08

AW: FMX + UI aktualisieren
 
Zitat:

Zitat von Frühlingsrolle (Beitrag 1450427)
Das hier wäre eine Möglichkeit.

Die Lösung wäre aber nicht threadsicher, da das Notify-Event direkt an die verarbeitenden Objekte innerhalb des Threads übergeben werden würde.

@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:...

Mavarik 29. Okt 2019 14:19

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

TigerLilly 29. Okt 2019 14:43

AW: FMX + UI aktualisieren
 
Warum keinen Timer? Sonst brauche ich eine Schleife.

philipp.hofmann 29. Okt 2019 15:05

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.

Rollo62 29. Okt 2019 15:28

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.

Mavarik 29. Okt 2019 15:56

AW: FMX + UI aktualisieren
 
Zitat:

Zitat von TigerLilly (Beitrag 1450434)
Warum keinen Timer? Sonst brauche ich eine Schleife.

Wofür eine Schleife?

Zitat:

Zitat von philipp.hofmann (Beitrag 1450435)
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.

Und warum willst Du die UI Task damit nerven per Timer etwas auszulesen? Du hast doch den
Delphi-Quellcode:
TThread.Queue(NIL,Procedure...

Zitat:

Zitat von Rollo62 (Beitrag 1450437)
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.

Das geht sicherlich auch - verwende ich auch gerne, wenn ich ein Multicast benötige.

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;

Der schöne Günther 29. Okt 2019 16:26

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.

Mavarik 29. Okt 2019 16:54

AW: FMX + UI aktualisieren
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1450442)
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.

Ich will nicht, das meine UI permanent nachschauen muss... Abgesehen davon muss ich dann eine Queue nehmen die das Threadsafe Locking macht - wofür?

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:

Der schöne Günther 29. Okt 2019 20:08

AW: FMX + UI aktualisieren
 
Zitat:

Zitat von Mavarik (Beitrag 1450445)
ggf. Habe ich 10 Thread die etwas machen - soll ich dafür 10 Timer nehmen, 10 Queues erzeugen und alles per TMonitor sperren?

Nein, wenn du ein Anzeige-Element hast das den Fortschritt aus 10 Threads anzeigt sitzt darauf ein Timer. Und den musst du auch nicht starten und stoppen, der kann ruhig immer laufen. Das kostet doch nichts.

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();
.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:37 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz