Delphi-PRAXiS

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/)
-   -   Timer wird Blockiert (https://www.delphipraxis.net/201162-timer-wird-blockiert.html)

Int3g3r 28. Jun 2019 09:05

Timer wird Blockiert
 
Guten Morgen,

Ich habe zwei VclFormulare : frmMain , frmProgress
frmProgress hat einen Timer,
frmMain muss warten bis der Timer abgelaufen ist und erst dann das frmProgress auf Hide setzen.

Mein Problem ist das das Timer-Event nicht ausgelöst wird.
Meine überlegung ist im frmMain mit einer While-Schleife zu warten bis das Timer-Event ausgelöst wir. Leider funktioniert das nicht. Er bleibt bei der While-Schleife stecken.

Wie kann man auf einen Timer "warten" ?
Ein Timer läuft doch im Hintergrund warum läuft dieser in der While-Schleife nicht weiter ?


Delphi-Quellcode:
//frmMain
while FormFtpprogress.canHide = false do
   begin
   if FormFtpprogress.canHide = true then
      FormFtpprogress.Hide;
   end;
Delphi-Quellcode:
//frmProgress   
procedure TFormFtpprogress.FormShow(Sender: TObject);
begin
   canHide := false;
   progressTimer.Enabled := true;
end;

procedure TFormFtpprogress.progressTimerTimer(Sender: TObject);
begin
   progressTimer.Enabled := false;
   canHide := true;
end;
Gruss Int3g3r

Schokohase 28. Jun 2019 09:35

AW: Timer wird Blockiert
 
Ein Timer "läuft" überhaupt nicht. Zu einem Zeitpunkt X wird der Timer ausgelöst ...

... aber
  • dieses "Auslösen" erfolgt über eine Nachricht vom Betriebssystem
  • diese Nachrichten werden von der VCL-/FMX-Anwendung abgearbeitet, wenn der UI-Thread dafür Zeit hat
  • wenn man diesen UI-Thread blockiert (z.B. mit so einer
    Delphi-Quellcode:
    while
    Schleife) dann schiesst man sich damit in das Knie, denn damit hat der UI-Thread ja eben keine Zeit diese Nachrichten zu bearbeiten

Int3g3r 28. Jun 2019 09:44

AW: Timer wird Blockiert
 
Zitat:

Zitat von Schokohase (Beitrag 1435536)
Ein Timer "läuft" überhaupt nicht. Zu einem Zeitpunkt X wird der Timer ausgelöst ...

... aber
  • dieses "Auslösen" erfolgt über eine Nachricht vom Betriebssystem
  • diese Nachrichten werden von der VCL-/FMX-Anwendung abgearbeitet, wenn der UI-Thread dafür Zeit hat
  • wenn man diesen UI-Thread blockiert (z.B. mit so einer
    Delphi-Quellcode:
    while
    Schleife) dann schiesst man sich damit in das Knie, denn damit hat der UI-Thread ja eben keine Zeit diese Nachrichten zu bearbeiten

Und wie kann ich dem Thread die Zeit geben ohne das er meinen Code weiter ausführt ?
Ein
Delphi-Quellcode:
Sleep()
bewirkt genau das geliche wie eine
Delphi-Quellcode:
while
Schleife also kann ich diesen Befehl auch nicht benutzen.

Gausi 28. Jun 2019 09:49

AW: Timer wird Blockiert
 
Wenn ich das richtig verstehe, dann soll die Progressform nach einer gewissen Zeit geschlossen werden, wenn eine Aktion im MainForm beendet ist. Aber nicht sofort nach Ende, sondern z.B. nach 2 Sekunden, um dem User noch Zeit zu geben, eine Nachricht "Fertig" zu lesen? Oder so ähnlich?

Das würde ich dann so machen:

Delphi-Quellcode:
TfrmMain.DoSomething;
begin
  // ...
  // ... operation finished ...
  FormFtpprogress.progressTimer.Enabled := True;
end;

procedure TFormFtpprogress.progressTimerTimer(Sender: TObject);
begin
   progressTimer.Enabled := false;
   Close; // ProgressForm schließen
end;

Moombas 28. Jun 2019 09:50

AW: Timer wird Blockiert
 
Warum startest du den Timer nicht im "neuen" Form, dann kannst du dieses auch direkt darüber verstecken.



grml Gausi war schneller :P

Int3g3r 28. Jun 2019 10:01

AW: Timer wird Blockiert
 
Zitat:

Zitat von Gausi (Beitrag 1435539)
Wenn ich das richtig verstehe, dann soll die Progressform nach einer gewissen Zeit geschlossen werden, wenn eine Aktion im MainForm beendet ist. Aber nicht sofort nach Ende, sondern z.B. nach 2 Sekunden, um dem User noch Zeit zu geben, eine Nachricht "Fertig" zu lesen? Oder so ähnlich?

Das würde ich dann so machen:

Delphi-Quellcode:
TfrmMain.DoSomething;
begin
  // ...
  // ... operation finished ...
  FormFtpprogress.progressTimer.Enabled := True;
end;

procedure TFormFtpprogress.progressTimerTimer(Sender: TObject);
begin
   progressTimer.Enabled := false;
   Close; // ProgressForm schließen
end;

Genau das Ziel hast du richtig verstanden.

Wenn möglich möchte ich aber eine Timer-Interaktion im DoSomething vermeiden.
Der Timer soll starten wenn das FormProgress angezeigt wird. Daher möchte ich den Timer auch im FormProgress plazieren. Alle Timer-Interaktionen sollten auch auf dem FormProgress stattfinden.

Im Prinzip möchte ich im DoSomething nur warten bis das FormProgress geschlossen/auf Hide gesetzt wurde. Danach den DoSomehting weiter ausführen.

Wie kann ich im DoSomething überprüfen ob frmProgress auf hide oder show gesetzt ist ?

Danke für die Hilfe.

Moombas 28. Jun 2019 10:09

AW: Timer wird Blockiert
 
Zitat:

Zitat von Int3g3r (Beitrag 1435541)
Im Prinzip möchte ich im DoSomething nur warten bis das FormProgress geschlossen wurde. Danach den DoSomehting weiter ausführen.

Danke für die Hilfe.

Warum fragst du im Timer dann nicht genau diesen Status ab?

Delphi-Quellcode:
//Nur als Beispiel!!
procedure TForm1.Button2Click(Sender: TObject);
begin
  Form2.show;
  Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if not Form2.Visible then
  begin
    //Es wurde geschlossen oder ausgeblendet
    Timer1.Enabled := False;
  end;
end;

Gausi 28. Jun 2019 10:22

AW: Timer wird Blockiert
 
Wenn die Ausführung der Aktion der MainForm unterbrochen werden soll/muss, bis der Timer abgelaufen ist bzw. die Progressform geschlossen wurde, dann könnte das mit ShowModal gehen.

Also so:

Delphi-Quellcode:
// in MainForm
procedure DoSomething;
begin
  foo; // machwas
  ProgressForm.ShowModal; // Anzeige der ProgressForm und warten
  bar; // mach noch was
end;

// ProgressForm
procedure TFormFtpprogress.FormShow(Sender: TObject);
begin  
   progressTimer.Enabled := true;
end;

procedure TFormFtpprogress.progressTimerTimer(Sender: TObject);
begin
   progressTimer.Enabled := false;
   // ggf. ModalResult := ... zur Rückgabe eines Wertes an MainForm
   Close; // ProgressForm schließen
end;
Alternativ in der Schleife in deinem ersten Posting ein Application.ProcessMessages einbauen. Aber dann wird es unter Umständen hakelig mit der GUI. Denn dann musst du sicherstellen, dass der User zwischendurch nichts "gefährliches" anklicken darf.

hoika 28. Jun 2019 10:46

AW: Timer wird Blockiert
 
Hallo,
was du nutzen könntest, ist semimodales Verhalten.
Such mal hier im Forum nach dem Wort.
Ich hatte da vor ein paar Jahren was dazu geschrieben.

Ansonsten verstehe die Frage nicht.
Wenn du willst, dass dein Programm erst nach einer gewissen Zeit schließt,
nimm ein modales Progressfenster (wie du schon geschrieben hattest),
dann deinen Timer und fange das Close in OnCloseQuery ab.
In der OnTimerTimer-Methode machst du dann deine ganzen Arbeiten.

Moombas 28. Jun 2019 11:19

AW: Timer wird Blockiert
 
Zitat:

Zitat von Gausi (Beitrag 1435545)
[/DELPHI]

Alternativ in der Schleife in deinem ersten Posting ein Application.ProcessMessages einbauen. Aber dann wird es unter Umständen hakelig mit der GUI. Denn dann musst du sicherstellen, dass der User zwischendurch nichts "gefährliches" anklicken darf.

Was relativ einfach wäre mit Form1.enabled := False bzw. Form1.enabled := True;

Int3g3r 28. Jun 2019 11:33

AW: Timer wird Blockiert
 
Vielen Dank für die Hilfe!

@Gausi
Delphi-Quellcode:
Application.ProcessMessages
Das habe ich gesucht vielen Dank!

Es funktioniert nun. Quelltext sieht wie folgt aus:

Delphi-Quellcode:
//frmMain

while FormFtpprogress.Visible = true do // Warte auf Timer
begin
   if FormFtpprogress.canHide = true then
         FormFtpprogress.Hide;
   Application.ProcessMessages;
end;
Delphi-Quellcode:
//frmProgress

procedure TFormFtpprogress.FormShow(Sender: TObject);
begin
   canHide := false; //public member
   progressTimer.Enabled := true;
end;

procedure TFormFtpprogress.progressTimerTimer(Sender: TObject);
begin
   canHide := true;
   progressTimer.Enabled := false;
end;

DieDolly 28. Jun 2019 12:26

AW: Timer wird Blockiert
 
Da das jetzt klappt, entferne bitte noch den Vergleich auf True. Sowas macht man nicht :thumb:

Delphi-Quellcode:
while FormFtpprogress.Visible = true do // Warte auf Timer

Int3g3r 28. Jun 2019 14:38

AW: Timer wird Blockiert
 
Zitat:

Zitat von DieDolly (Beitrag 1435552)
Da das jetzt klappt, entferne bitte noch den Vergleich auf True. Sowas macht man nicht :thumb:

Delphi-Quellcode:
while FormFtpprogress.Visible = true do // Warte auf Timer

Also für mich ist das Gegenteil der fall. für mich ist es nicht eindeutig wenn auf "nichts" geprüft wird.
Delphi-Quellcode:
while FormFtpprogress.Visible do
Aber Danke für den Tipp vielleicht sollte ich mich da mal umgewöhnen.

DieDolly 28. Jun 2019 14:41

AW: Timer wird Blockiert
 
https://www.delphipraxis.net/57121-u...t-boolean.html

https://softwareengineering.stackexc...al-out-of-true


mkinzler und Luckie können da bestimmt mehr drüber erzählen.

Delphi.Narium 28. Jun 2019 15:15

AW: Timer wird Blockiert
 
Zitat:

Zitat von Int3g3r (Beitrag 1435564)
Zitat:

Zitat von DieDolly (Beitrag 1435552)
Da das jetzt klappt, entferne bitte noch den Vergleich auf True. Sowas macht man nicht :thumb:

Delphi-Quellcode:
while FormFtpprogress.Visible = true do // Warte auf Timer

Also für mich ist das Gegenteil der fall. für mich ist es nicht eindeutig wenn auf "nichts" geprüft wird.
Delphi-Quellcode:
while FormFtpprogress.Visible do
Aber Danke für den Tipp vielleicht sollte ich mich da mal umgewöhnen.

Es wird aber nicht auf nichts geprüft.

Die Schleife läuft solange, solange alles zwischen while und do wahr ist.
FormFtpprogress.Visible ist entweder wahr (true) oder falsch (false). Das reicht für eine Abfrage vollkommen aus.

Bei Deiner Variante fragst Du immer sowas in der Art:
Delphi-Quellcode:
while true = true do
Weil true aber bereits true ist, muss Du es nicht noch mit true vergleichen.
Andersherum fragst Du sowas in der Art:
Delphi-Quellcode:
while false = true do
Da false aber nie true ist, erübrigt sich der Vergleich von false mit true.

Int3g3r 28. Jun 2019 15:28

AW: Timer wird Blockiert
 
Danke für die Links diese sind sehr Interessant.
Ich wusste nicht das dies zu Fehler führen kann.

Wenn ich mir das im Kopf vorstelle ist es für mich einfach unlogisch nur eine Variable mit "nichts" zu vergleichen. Dazu ist beim Ausdruck
Delphi-Quellcode:
if variable=true then
sofort sichtbar das es sich um einen Boolean handelt, sonst könnte die Variable ein x-beliebiger Datentyp sein. Für mich ist der Quelltext einfacher zu lesen.:shock:

Werde mich aber umgewöhnen.

Mfg Int3g3r

DieDolly 28. Jun 2019 15:30

AW: Timer wird Blockiert
 
Zitat:

Dazu ist beim Ausdruck if variable=true then sofort sichtbar das es sich um einen Boolean handelt, sonst könnte die Variable ein x-beliebiger Datentyp sein.
Mhh nee

Delphi-Quellcode:
if X then

if X = 1 then

if X = 1.25 then

if X = 'test' then

if X = TMyEnumTypes.X

Medium 28. Jun 2019 16:17

AW: Timer wird Blockiert
 
Zitat:

Zitat von Int3g3r (Beitrag 1435569)
sonst könnte die Variable ein x-beliebiger Datentyp sein.

Könnte, wird dir Delphi dank seiner Typsicherheit aber beim Kompilieren um die Ohren werfen ;)

In C sieht das anders aus. Da kann wirklich alles als Bedingung angesehen werden, ohne es explizit hinzuschreiben. In Delphi aber muss das Gesamtergebnis von allem zwischen "if & then", "while & do" und "repeat ... until & ;" ein Boolean werden. Das kann man durch einen expliziten Vergleich erreichen, aber wenn die Variable eh schon vom Typ Boolean ist, kann die einfach nackig da stehen - und es ist sofort klar, dass sie ein Bool sein muss.

p80286 29. Jun 2019 22:10

AW: Timer wird Blockiert
 
Zitat:

Zitat von Int3g3r (Beitrag 1435564)

Also für mich ist das Gegenteil der fall. für mich ist es nicht eindeutig wenn auf "nichts" geprüft wird.

In Delphi gibt es kein "nichts"! Im Gegensatz zu z.B. SQL, da ist "nichts" NULL. In Delphi könnte "nichts" durch einen Leerstring oder einen Nil-Pointer repräsentiert werden, wobei es sich in beiden Fällen um eine klare Definition handelt während "nichts" undefiniert ist. Es handelt sich also nur um eine schlechte Krücke.

Gruß
K-H

Mavarik 30. Jun 2019 13:37

AW: Timer wird Blockiert
 
Zitat:

Zitat von Int3g3r (Beitrag 1435550)
!

Es funktioniert nun. Quelltext sieht wie folgt aus:

Delphi-Quellcode:
//frmMain

while FormFtpprogress.Visible = true do // Warte auf Timer
begin
   if FormFtpprogress.canHide = true then
         FormFtpprogress.Hide;
   Application.ProcessMessages;
end;

Delphi-Quellcode:
Application.Processmessages
ist immer gruselig! Wenn es überschaubar ist, kann/funktioniert es erstmal, aber in komplexen Anwendungen sollte man darauf verzichten, da es ungewollte Seiteneffekte geben kann!

Macht dein FormFtpprogress wenn es angezeigt wird noch etwas "dynamisches"? Oder zeigt es nur eine statische Anzeige?

Mavarik :coder:

DeddyH 1. Jul 2019 06:45

AW: Timer wird Blockiert
 
Ich würde die Logik auf Ereignisse umstellen, dann entfällt das ganze Polling-Geraffel. Soll heißen: die Klasse TFormFtpprogress bekommt ein Ereignis OnCanHideChanged spendiert, das gefeuert wird, sobald sich die CanHide-Eigenschaft (oder Variable) ändert. Das Hauptformular kann diesem Ereignis dann einen Handler zuweisen, der beim Eintreten ausgeführt wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:12 Uhr.

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