How can I pause TTimer in Delphi with keeping interval? So, for instance, I have TTimer that has 10 seconds interval and when I set timer to pause after first 7 seconds of working, it will save its state, and then when I resume timer it will fire after remaining 3 seconds.
Thanks a lot guys!
Timer.interval :=1000;
ICount:integer;
In create procedure set icount to 0
Procedure timerevent(sender:tobject);
Begin
If icount=10 then
Begin
// do proccess
Icount = 0;
End;
Inc(icount);
End;
Now you can stop the timer anywhere
You cannot do that with a TTimer which is a loose wrapper around the SetTimer API.
In order to do this you would need to keep track of when the timer started and when you paused it. Then you would know how much time was left. When you need to pause, set the timer Enabled property to False and set the interval to be the amount of time remaining. Don't forget that after the timer fires for the first time you need to reset its interval to the true interval.
As you can see from the above, a TTimer is not the best fit for your problem. But, having said that it would not be terribly difficult, and quite fun, to produce a TTimer variant that supported pausing the way you desire.
That's not how the Windows timer facility works, and that's not how the Delphi wrapper works, either.
When you disable the timer, keep note of how much time was remaining before it was due to fire again. Before you re-enable it, set the Interval property to that value. The next time the timer fires, reset Interval to the original value.
TTimer does not support what you are asking for. As others have already commented, you would have to stop the timer, reset its Interval to whatever time is remaining, start it, then stop and reset its Interval back to 10 seconds when the next OnTimer event is triggered.
A simpler solution is to just let the TTimer keep running normally, and have a separate flag that tells the OnTimer event handler whether it can do its work or not whenever it is triggered, eg:
var
Boolean: Paused = False;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if not Paused then
begin
// do proccess
end;
end;
procedure TForm1.PauseButtonClick(Sender: TObject);
begin
Paused := True;
end;
procedure TForm1.ResumeButtonClick(Sender: TObject);
begin
Paused := False;
end;
Related
how do I start Ttimer?
timer.interval := 5000;
lbl.caption:='1'
*wait 5 sec*
lbl.caption:='2'
I have ttimer in my form and it is enabled.
Set the timer's Interval property to 5000. That is the interval in milli-seconds.
Declare a private field of the form, FCount of type Integer.
Attach on OnTimer event handler to the timer:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
inc(FCount);
lbl.Caption := IntToStr(FCount);
end;
When you want to start the timer, initialise FCount and set Timer1.Enabled to True. Set Timer1.Enabled to False when you want to stop the timer.
I am assuming, based on your now deleted earlier question, that you want the counter to keep ticking.
Timers work by calling their OnTimer event every time they tick. Because each tick is a distinct call to the event handler, you have to store any persistent state somewhere other than local variables. That's because local variables only endure for the duration of their owning method. Hence the use of a private field of the form to maintain the count.
Note that a timer does not make the program wait. Timers are asynchronous. The program will still be responsive to user input while the timer is active. When the timer expires, the system synthesises a timer message in your message queue. The program does not block on the timer. So your UI elements will, unless you take action otherwise, still be enabled and responsive.
I am trying to program a "cough button" in a communications program that does not always have focus. I have the code working to mute and unmute the mic (MMDevApi) and it works perfect. I set up a global hot key and this works perfect to set the mute. Now the problem. How do I tell when the Hotkey is released ? I tried a timer as shown in the code but it has an odd behavior. I Hold down my hotkey and the mic mutes immediately then after the interval of the timer it unmutes for a what appears to be half the interval of the timer and then it mutes and stays muted. Without the timer it mutes and stays muted perfectly. I really don't want ( or think it would be any good ) to have to hit a second key to unmute the mic.
//here is my register hot key code !
CoughKeyWnd := AllocateHwnd(CoughKeyWndProc);
CoughKey := GlobalAddAtom('CoughKey');
if CoughKey <> 0 then
RegisterHotKey(CoughKeyWnd, CoughKey, MOD_CONTROL, VK_OEM_3);
//the procedure
procedure TForm1.CoughKeyWndProc(var Message: TMessage);
begin
if Message.Msg = WM_HOTKEY then
begin // to prevent recalling mute
if CoughOn = FALSE then
begin
CoughOn := True;
CoughOff.SetMute(1,#GUID_NULL);
end;
Timer1.Enabled := FALSE;
Timer1.Enabled := True;
end
else
begin
Message.Result := DefWindowProc(CoughKeyWnd, Message.Msg, Message.WParam, Message.LParam);
end;
//and finally the ontimer !
procedure TForm1.JvTimer1Timer(Sender: TObject);
begin
CoughOff.SetMute(0,#GUID_NULL);
Timer1.Enabled := False;
CoughOn := False;
end;
You'll see that kind of behavior if your timer expires before the second WM_HOTKEY is retrieved but does not expire retrieving consecutive messages. The time frame between the first and second message is greater than the time frame between consecutive messages. This is because keyboard delay is greater (~250ms typical) than keyboard repeat interval.
To make your approach work, increase your timer interval, something like twice the keyboard delay for instance. You can use SystemParametersInfo to get an approximation for keyboard delay. Or employ a minimum time frame for the microphone to stay in muted state, and only after then start watching for repeated hotkey messages to re-enable your timer. Still, this method will be somewhat unreliable, hotkey messages might be delayed for whatever reason. Better use GetKeyState in your timer handler to test if the keys are still down.
You can install a keyboard hook or register for raw input when the hotkey is hit if you don't want to use the timer.
I need to show a message say "Hi" everyday at 9 AM. Do I require Timer for this? How can I check whether its 9 AM or not. What should be the interval of timer at which OnTimer event run?
procedure Form1.TimerTimer1(Sender: TObject);
begin
ShowMessage("Hi");
end;
If I run this event in after 24 hours, I fear it might pass 9 AM and will not fire.
Unless you have other valid reasons, it's far more easier to
write a simple application that shows the message and quits
schedule it to run using the task scheduler of Windows
You can use CRON like solutions for Delphi: http://www.cromis.net/blog/downloads/cron-scheduler/
As the answerers before me said, there are better and easier ways. Suppose you want to do this your way, in Delphi, then yes, you need a timer. The needed steps are:
Put the timer on your form;
Set the "interval" property to 1000 (one second) or less. For greater precision, you can set the interval property to 1, and the program will do the checking each milisecond
Write the handler for OnTimer:
procedure Form1.TimerTimer1(Sender: TObject);
var x:TDateTime
begin
x:=Now;
if {the hour read is 9 and minute is 0} then
ShowMessage("Hi");
end;
Hope it helps.
Is it possible to determine when a TTimer in Delphi will trigger? I know how to calculate this based upon the timer's last run and the timers interval. Unfortunately, the code I am working with has many states and the interval can change in many ways. I would prefer to not have to keep track of when the timer was last enabled and the interval changed, but instead directly access this information from the timer.
Scenario: A timer has a 2 minute interval, 30 seconds have elapsed since it was last enabled, how do I find out in code that in 90 seconds the timer event will trigger again?
Is it possible to get this information from the timer directly? Or perhaps the OS? The timer component must "know" when it will be triggered next. How does it know? Is this information I can access?
There's absolutely no way to query a Windows timer for information of this nature. You will simply have to keep track of this yourself.
I would do this by wrapping up the TTimer with composition and not inheritance. You can then be sure that you will capture all modifications to the timer state.
In this case I recommend you switch from a TTimer which uses Windows timers, to a thread based TTimer-style component. Then you can query the time until the next event.
Alternative; If you want a simple ugly hack, then change your Timer interval to 1 second instead of 120 seconds, and do a countdown yourself:
const
CounterPreset = 120;
...
procedure TForm1.FormCreate(Sender:TObject);
begin
FCounter := CounterPreset;
Timer1.Interval := 1000;
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender);
begin
Dec(FCounter);
if (FCounter<=0) then
begin
DoRealTimerCodeHere;
FCounter := CounterPreset;
end;
end;
function TForm1.TimeLeft:Integer;
begin
result := FCounter;
end;
This will be inaccurate subject to the limitations of the WM_TIMER message, documented only vaguely at MSDN here. Real experience shows that WM_TIMER should only be used for things that don't need to happen at all, and should be used as a convenience, not as a hard-timing system.
Consider the following code
Timer1 .Enabled := False;
Timer1.Interval : = 300;
For I := 1 to NumberOfTimesNeed do
Begin
Timer1 .Enabled := False; //
Timer1 .Enabled := True; // reset the timer to 0.30 seconds
TakesToLong := False;
DoSomethingThatTakesTime; // Application.ProcessMessages is called in the procedure
If TakesToLong = True then
TakeAction;
End;
procedure Timer1Timer(Sender: TObject);
begin
TakesToLong:= True;
end;
Question :
When I disable and then enable the Timer1 with
Timer1.Enabled := False;
Timer1.Enabled := True;
Does this reset the timer ?
i.e. will it always wait 0.30 Seconds before timing out.
Yes, it will. Setting Enabled to False will call the Windows API function KillTimer() if the timer was enabled before. Setting Enabled to True will call the Windows API function SetTimer() if the timer was not enabled before.
It's a standard idiom, which has been working since the times of Delphi 1.
I would however implement your code in a different way:
Start := GetSystemTicks;
DoSomethingThatTakesTime;
Duration := GetSystemTicks - Start;
if Duration > 300 then
TakeAction;
which would work without a timer, and without the need to call ProcessMessages() in the long-taking method. GetSystemTicks() is a function I have in a library, which does call timeGetTime() in Windows, and which was implemented differently for Kylix (don't remember how, I purged that code long ago).
One further thing to be aware of is that timers are the lowest priority notification on the system. So if the computer is busy, which may include the app here doing its work, the timer may not trigger for quite a while. So it could be several seconds before the TakesToLong variable gets set to true, even though the timer is set to 300 milliseconds.
I would suggest reading up on threads. Long actions (I'm not saying 300 ms is long but it sounds like that it could obviously go longer than that) tend to freeze the GUI and lead to choppy applications. Now, you can throw application.processmessages in there to keep the GUI going, but it can easily throw off your intended procedural coding style.
I'm from the side of the aisle that believes Application.ProcessMessages should be banned unless you are a VB programmer trying to use Delphi to mimic DoEvents and you still haven't gotten out of the VB mindset.
Spawn a thread and do your work in that thread. If want to update the GUI side when you are done, call Synchronize to 'safely' do so. Communicating the ongoing status back and forth with the thread brings in a whole new conversation that is quite a leap from using the timer control though.