Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Timer Reset ? (https://www.delphipraxis.net/86869-timer-reset.html)

BBoy 20. Feb 2007 19:54


Timer Reset ?
 
habe folgendes vor in meinem Programm:

Wenn nichts im Programm gemacht wird, z.b. die Maus für 1 Stunde nicht bewegt wird, soll das Programm sich beenden.

Eigentlich wäre da so eine art RESET für den timer angebracht, den ich bei application.mousemove einbauen würde. So dass der Timer immer auf 0 gestellt wird wenn die maus bewegt wird. Aber dieses RESET gibt es leider nicht, daher meine Frage:

wie kann ich dies realiseren?

und

ist es für das Programm nicht zuviel "arbeit" wenn bei JEDER mausbewegung ein Timer Resettet wird??

inherited 20. Feb 2007 19:59

Re: Timer Reset ?
 
Delphi-Quellcode:
Timer1.Enabled:=false;
Timer1.Enabled:=true;
Voila, er fängt von vorne an ;)

(:party: 1000. Beitrag :party:)

BBoy 20. Feb 2007 20:08

Re: Timer Reset ?
 
klingt logisch :)

Bleibt noch die 2. Frage offen: Ist es für das Programm nicht zuviel "arbeit", wenn bei jeder Mausbewegung der Timer zurückgesetzt wird? Weil die maus ja normalerweise ständig bewegt wird, was bedeutet das Programm müßte jede sekunde mehrmals den timer zurücksetzen.

marabu 20. Feb 2007 20:15

Re: Timer Reset ?
 
Hallo,

wozu den Timer? In der OnIdle-Routine der Application kann GetLastInputInfo() verwendet werden um den Zeitpunkt des letzten InputEvents abzufragen.

Grüße vom marabu

BBoy 20. Feb 2007 20:53

Re: Timer Reset ?
 
GetLastInputInfo gibt doch systemweit den Zeitpunkt des letzten InputEvents zurück, oder?
Es soll aber nur der inputevent von meinem Programm beachtet werden, denn an dem pc wird weitergearbeitet, aber nicht in meinem programm.

marabu 21. Feb 2007 06:51

Re: Timer Reset ?
 
Guten Morgen,

etwa so habe ich mir das vorgestellt:

Delphi-Quellcode:
type
  TDemoForm = class(TForm)
    ApplicationEvents: TApplicationEvents;
    procedure ApplicationEventsIdle(Sender: TObject; var Done: Boolean);
    procedure ApplicationEventsActivate(Sender: TObject);
  private
    LastInput: Cardinal;
  end;

{
  ...
}

const
  MAX_APPIDLE_TICKS = 5000;

procedure TDemoForm.ApplicationEventsActivate(Sender: TObject);
begin
  LastInput := GetTickCount;
end;

procedure TDemoForm.ApplicationEventsIdle(Sender: TObject;
  var Done: Boolean);
var
  lii: TLastInputInfo;
begin
  if Application.Active then
  begin
    lii.cbSize := SizeOf(TLastInputInfo);
    GetLastInputInfo(lii);
    LastInput := lii.dwTime;
  end;

  // show idle tickcount
  Caption := IntToStr(GetTickCount - LastInput);
  Invalidate;

  if LastInput + MAX_APPIDLE_TICKS < GetTickCount
    then Close
    else Done := True;
end;
Getippt und nicht getestet.

Freundliche Grüße

Codehunter 23. Feb 2017 13:06

AW: Re: Timer Reset ?
 
Zitat:

Zitat von inherited (Beitrag 591018)
Delphi-Quellcode:
Timer1.Enabled:=false;
Timer1.Enabled:=true;
Voila, er fängt von vorne an ;)

(:party: 1000. Beitrag :party:)

Ich fleddere mal wieder Leichen ^^ Grund: Ich habe grade festgestellt, dass das zumindest bei DXE4 nicht der Fall zu sein scheint. Der "Taktgeber" scheint hier intern weiter zu laufen. Es wird lediglich der Aufruf des Ereignisses "OnTimer" verhindert wenn Enabled auf False gesetzt ist.

himitsu 23. Feb 2017 17:38

AW: Re: Timer Reset ?
 
XE4: TTimer in VCL?

Das setzt auf MSDN-Library durchsuchenSetTimer auf.
und die TTimer-Komponente löscht den kompletten Timer, jedes mal, wenn man die Einstellungen ändert und erstellt ihn danach eventuell neu. (Interval oder Enabled)
Somit sollte das Intervall also eigentlich von vorne loszählen.

Windows ändert an dem Verhalten nichts und bei Embarcadero ändert sich eh nie was.
Aber wenn, dann sollte es nicht an Delphi, sondern an Windows liegen, aber die werden da hoffentlich nichts ändern.


Wenn es aber um FMX geht ... tja, wer weiß was da intern vom TTimer verwendet wird.

Codehunter 24. Feb 2017 07:35

AW: Timer Reset ?
 
Ja genau, TTimer in VCL. Das ist ganz merkwürdig. Hab ich so auch noch nie erlebt. Zur Reproduktion des Fehlers habe ich ein ganz einfaches Testprogramm gebastelt:
Delphi-Quellcode:
unit Unit5;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private-Deklarationen }
    FCounter: Integer;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FCounter:= 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Inc(FCounter);
  Timer1.Enabled:= TRUE;
  Timer1.Enabled:= FALSE;
  Timer1.Enabled:= TRUE;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Caption:= IntToStr(FCounter);
  Timer1.Enabled:= FALSE;
end;

end.
Die dreifache Wertänderung habe ich gemacht um sicher zu gehen, dass in jedem Fall eine Wertänderung eintritt, egal wie Timer1.Enabled im Moment des Buttonclicks besetzt ist. Das Intervall lasse ich auf den standardmäßigen 1000 ms.

Normalerweise müsste sich die Zahl im Fenstercaption immer exakt 1 Sekunde nach dem Buttonclick um 1 erhöhen. Tatsächlich aber scheint es ein Zufallswert zwischen 0 und 1000 ms zu sein.

Jetzt hatte ich auch zuerst Windows im Verdacht. Also virtuelle Maschine geöffnet, da ist ein Win 10 drauf (Host = Win 7). Gleicher Effekt. Jetzt kommts aber: Gehe ich mit der selben EXE auf einen anderen physischen Rechner, läuft es ganz normal.

Jetzt würde mich mal interessieren, wie Windows den Timer bzw. GetTickCount realisiert. Soweit ich weiß sollte das doch ein mehr oder weniger "geeichtes" Signal aus einem Quarz auf dem Mainboard sein, oder? Wenn der einen an der Marmelade hätte, müsste doch auch die Systemzeit aus dem Ruder laufen, und zwar auffallend stark. Die aber scheint keine Probleme zu haben. Selbst dann nicht, wenn ich ein Live-Linux von DVD starte.

hoika 24. Feb 2017 08:17

AW: Timer Reset ?
 
Hallo,

Zitat:

Normalerweise müsste sich die Zahl im Fenstercaption immer exakt 1 Sekunde nach dem Buttonclick um 1 erhöhen.
Wie kommst du denn auf die Idee?
Ein Windows-Standard-Timer ist sehr ungenau.

Eine Timer-Nachricht hat zusammen mit WM_PAINT eine geringere Priorität als andere Nachrichten.

Windows ist von Haus aus kein Echtzeit-Betriebssytem.

Codehunter 24. Feb 2017 08:55

AW: Timer Reset ?
 
Zitat:

Zitat von hoika (Beitrag 1362497)
Eine Timer-Nachricht hat zusammen mit WM_PAINT eine geringere Priorität als andere Nachrichten.

Exakt solltest du nicht im wörtlichen Sinne auffassen. Aber gerade wenn Timer-Nachrichten eine geringere Priorität hätte, müsste die Zeitspanne doch eher größer werden als kleiner. Hier habe ich aber den Effekt, dass es teils deutlich unter einer Sekunde ist.

Rollo62 24. Feb 2017 10:37

AW: Timer Reset ?
 
Zitat:

Ein Windows-Standard-Timer ist sehr ungenau.
Naja, aber 0 ... 1000ms sollte es nicht sein.
Ich würde mal sagen +/- 50ms könnten drin sein.

Aber du machst ja gar keine echte Messung, nur das Caption hochzählen.
Könnte auch sein dass das Neuzeichen des Captions so lange braucht.

- Das würde ich dan mit QueryPerformanceCounter oder TStopWatch mal genau nachmessen
- und Caption mit Repaint edtwas forcieren

Rollo

Codehunter 24. Feb 2017 12:25

AW: Timer Reset ?
 
Zitat:

Zitat von Rollo62 (Beitrag 1362507)
Zitat:

Ein Windows-Standard-Timer ist sehr ungenau.
Naja, aber 0 ... 1000ms sollte es nicht sein.
Ich würde mal sagen +/- 50ms könnten drin sein.

Aber du machst ja gar keine echte Messung, nur das Caption hochzählen.
Könnte auch sein dass das Neuzeichen des Captions so lange braucht.

Wie gesagt, es ist ein seeeehr einfaches Testprogramm. Ich habe lediglich eine ungefähre Testmethode gebraucht. Aber auch du liegst falsch: Der Timer kommt in zu kurzen Intervallen, insofern ist die Repaint-Zeit vom Caption irrelevant ^^

Erfahrungsgemäß läuft gerade das NCPaint aber sehr flott ab, wesentlich höher priorisiert als Paints in der ClientArea. Deswegen verwende ich das gerne für Quick-and-Dirty-Tests. Ich konnte das Timer-Intervall auch auf 10 Sekunden stellen und es kommt teilweise < 1 Sekunde.

Rollo62 24. Feb 2017 13:26

AW: Timer Reset ?
 
Mal blöde Frage, benutzt du VmWare oder VirtualBox, oder *würg* Parallels ?

Rollo

Codehunter 24. Feb 2017 14:29

AW: Timer Reset ?
 
Zitat:

Zitat von Rollo62 (Beitrag 1362544)
Mal blöde Frage, benutzt du VmWare oder VirtualBox, oder *würg* Parallels ?

VirtualBox. Aber bevor du dich jetzt zu sehr auf die Virtualisierung versteifst: Das Problem trat zuerst nicht-virtualisiert auf der Hostmaschine auf.

Rollo62 24. Feb 2017 14:36

AW: Timer Reset ?
 
Also solche Timer hatte ich zum Glück noch nicht.
Hat der Rechner denn sonst irgendwelche Macken ?

Also wenn vielleicht irgendwelche Tasks im Hintergrund extrem was verabeiten,
aber im Leerlauf sollte das nicht so extrem passieren.

Rollo

t.roller 24. Feb 2017 16:20

AW: Timer Reset ?
 
Man kann sich auch selbst einen Timer machen mit
WaitableTimer

Delphi-Quellcode:
procedure TForm1.ButtonClick(Sender: TObject);
var
AlarmTimer : THandle;
Zeit : Large_Integer;
start, ende : Cardinal;
begin
  Memo1.lines.add('SetWaitableTimer: 1 sec Running');
  start:= GetTickCount;
AlarmTimer := CreateWaitableTimer(nil, False, nil);
CancelWaitableTimer(AlarmTimer);  // goto Start
Zeit.QuadPart := 1 * (-10000000); // 1 Sekunde
SetWaitableTimer(AlarmTimer, Zeit.Quadpart, 0, nil, nil, False);
while WaitForSingleObject(AlarmTimer, 20) <> Wait_Object_0 do // Beispiel: 20msec
begin Application.ProcessMessages; end;
  end1:= GetTickCount;
  Memo1.lines.add(INTTOSTR(end1-start)+' msec');
  Memo1.lines.add('WaitableTimer: Ready');
end;
AUSGABE:
SetWaitableTimer: 1 sec Running
1000 msec
WaitableTimer: Ready

Alternative: 10 sec
Delphi-Quellcode:
var
  Form1: TForm1;
  start, end1 : Cardinal;

procedure TimerAPCProc (param: Pointer; dwTimerLowValue, dwTimerHighValue: CARDINAL); stdcall;
begin
  end1:= GetTickCount;
  Form1.Memo1.lines.add(INTTOSTR(end1-start)+' msec');
  Form1.Memo1.lines.add('WaitableTimer: Ready');
end;

procedure TForm1.Button9Click(Sender: TObject);
var
  HTimer: THandle;
  DueTime: Int64;
begin
  Memo1.lines.add('SetWaitableTimer: 10 sec Running');
  start:= GetTickCount;
  HTimer:= CreateWaitableTimer (nil, False, nil);
  if HTimer <> 0 then
    begin
      DueTime:= 10*(-10000000);//10 sec
      if SetWaitableTimer (HTimer, DueTime, 0,//once
                           @TimerAPCProc,
                           Pointer (HTimer), False) then
        BEGIN SleepEx (INFINITE, True); END;
      CloseHandle (HTimer);
    end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:25 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