I am doing a simple high score add-in for a game. For this, I need a precise timer from which I can display the elapsed time in a Label. I have so far tried the following:
Windows.Forms.Timer: does not keep high resolution intervals, some are slower, some are faster.
System.Diagnostics.Stopwatch: no tick event.
I also thought of implementing a low-resolution Forms.Timer. Then, when the timer starts and stops I would store the system time and just subtract them to get the elapsed time. But I don't want to over-complicate things. Any ideas?
I don't think it would be overcomplicated to use a combination of a Stopwatch (for its high resolution) and the low-resolution Windows.Forms.Timer.
The Stopwatch is extremely straightforward to use, so it adds very little complexity to using a Timer too.
(This assumes you are ok with high-resolution elapsed time display but with a lower-resolution update interval.)
Use elapsed time since some moment. Than either:
Pick any timer, set it for 15ms and display elapsed time on each tick (should be ok if you are dealing with WinForm/WPF controls)
On every frame refresh display new value (if your code get notified/invoked on every frame refresh)
If you're willing to take the dependency, you could use Reactive Extensions (Rx) to get a timer:
var timer = Observable.Interval(TimeSpan.FromMilliseconds(15))
.Subscribe(() => /* handler */ );
Rx will make sure that the handler is called on the same thread the subscription was created on, and under the covers it uses System.Threading.Timer so it has pretty high and consistent resolution.
Related
I need to capture 10 frames per second of a live camera for 15 min. I used dispatcherTimer class but seems it doesn't work accurately. How to make it accurate? I even don't save the image because it is time consuming and i just keep it in the memory but still it doesn't work correctly.
should I use another library?
counter01 = new DispatcherTimer();
counter01.Tick += new EventHandler(counter01_Tick);
counter01.Interval = new TimeSpan(0, 0, 0,100); // every 100 milliseconds == 10 frames per seconds
MSDN states that:
Timers are not guaranteed to execute exactly when the time interval occurs,
but they are guaranteed to not execute before the time interval occurs.
You can check StopWatch, it might help you.
It is as accurate as it can be. Which requires your UI thread to be responsive, quickly dispatching any messages it gets. Including the "time is up" notifications that DispatcherTimer generates, the ones that generate the Tick event.
The usual hangup with seeing DispatcherTimer triggering the Tick event handler late is that you have a firehose problem. In other words, the amount of time required by the event handler is longer than the timer's Interval property value. This takes care of itself in the manner you expect, whenever you try to do more than the machine can handle then whatever you are trying to do just runs later.
No lack of firehose problems with video, one frame can contain a lot of data. A typical hidef video stream runs at 25 frames per second with each frame containing 1920x1080 pixels. That's 25 x 1920 x 1080 x 3 = 148 megabytes/second. Short from decompressing overhead, you can't even write the data to a disk at that rate. Most consumer-level disk drives top out at 30 megabytes/second, give or take a factor of 2. Lowering the frame rate to 10/sec is not enough to solve it, that's still 60 MB/sec, you have to take more drastic measures like reducing the frame size. Or use a good video encoder that can compress video real-time.
This is a systemic problem, not a DispatcherTimer problem. Use a profiler to get more insight, it helps you identify the true bottle-neck.
You actually can get the DispatcherTimer to execute the DispatcherTimer.Tick event every 100 milliseconds on a good PC, but you have to address 2 problems first (see below). However, as others wrote here correctly, the processing of a frame will take some time too and the fastest reliable tick frequency might only be 5 ticks per second, if the frame processing itself takes about 100 milliseconds.
1) Choose higher DispatcherTimer.Priority
The DispatcherTimer runs on the WPF GUI thread. The advantage of this is that the code of DispatcherTimer.Tick can access any WPF control. The WPF GUI thread is controlled by a Dispatcher, which has a priority queue for activities the WPF GUI thread wants to execute. Rendering related activities have a higher priority than the DispatcherTimer has per default. The default priority of the DispatcherTimer is DispatcherPriority.Background. With this priority, the Tick can execute on my PC not faster than every 100..300 milliseconds. However, create the timer like this: new DispatcherTimer (DispatcherPriority.Input) and it will fire about 100..200 milliseconds. Rendering will still have a higher priority, so the user does not get a frozen GUI.
2) Improve Tick regularity
One problem with the DispatcherTimer is that if the Tick event gets delayed by x milliseconds because the WPF GUI thread is busy with other activities, the next Tick will still wait for 100+ milliseconds. However, if you shorten DispatcherTimer.Interval by x milliseconds, you will get a more regular firing of the tick event.
For more details see my article on CodeProject: Improving the WPF DispatcherTimer Precision
Final Consideration
Why do you want to process the frames on the WPF GUI thread ? Use a DispatcherTimer only if the Tick event has little to do and needs access to the WPF controls. However, if you need to execute quite some code every 100 milliseconds, better use an additional thread. Your CPU has different cores and it is a good idea to distribute the workload over 2 cores.
I'm pretty frustrated about this one ..
I have a timer called timer1 and a text box called TimeElapsedTextBox and a double variable called TimeTakenToFinish
the timer ticks every 1 second (1000 millisecond)
in the text box, I want it to display the time in this format:
Seconds.PartsOfSecond
Here is the Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
TimeTakenToFinish += (double)timer1.Interval / 10000;
TimeElapsedTextBox.Text = TimeTakenToFinish;
}
it is actually displaying it in the text box the way i want it,
but it's not counting properly ..
I mean, it's counting less than a real second..
could you please tell me how to fix this ..
Your problem here is a misunderstanding of the way your OS works. Sure, you can set the interval to 1000ms, but you cannot expect it to actually tick every second. You are running code on Windows, not a hard (or soft) real time operating system.
As an aside, you should also know that the resolution of your timer is finite, and as of today, limited to the accuracy of your system timer, which is probably about 15ms.
You cannot expect your code to perform that deterministically in that sort of environment. At any point the OS can preemptively kick you out of the CPU and start working on another task.
You simply cannot get the accuracy you desire, though I would ask; is it actually required? Probably not, but you haven't told us what you are actually trying to accomplish here, so who knows?
Also, this is wrong:
TimeTakenToFinish += (double)timer1.Interval / 10000;
Interval is a property which is used to tell the timer roughly how often it should fire the Tick event. You are not actually measuring anything, you may as well just be adding 1000.0 / 10000 to your counter every time.
If you need more precision use the StopWatch class which uses your CPU's high performance timer if available. You can still use a timer to periodically update the UI based on the current elapsed value of the Stopwatch, i.e.,
void timer1_Tick(...)
{
var totalSeconds = _someStopwatch.ElapsedMilliseconds / 1000.0;
TimeElapsedTextBox.Text = totalSeconds.ToString();
}
Instead of using a timer, record the start time using DateTime.Now and then subtract the current time (DateTime.Now) from the start time. This will give you a more accurate timer as it uses the system clock instead which isn't affected so much by CPU performance.
Alternatively you can use System.Diagnostics.Stopwatch which does this for you.
You can still use an ordinary timer with an interval of less than a second to refresh the label displaying the time.
I am making a small typing test in C# in which the program asks you to type a word and then shows you your time.
I was using the c# timer class (drag and drop a timer from the toolbox), with a Tick time of 1ms, however it wasn't giving me accurate results, so I substituted it for a StopWatch , so now the timing is super accurate, but the problem is that it seems that you cannot assign event handlers to a StopWatch so although I can show the user his time when he FINISHES the word, I cannot actually show hum the time WHILE he is typing.
Thoughts?
Use a StopWatch to accurately measure time; and use a Timer to periodically fire a UI update, displaying the time measured by the StopWatch. For UI, you don't need 1 ms resolution (The screen update time is likely to be larger than 1 ms, and, the human eye won't be able to perceive updates that fast anyways).
Try having updates each 40 - 100 ms, I think that will be adequate.
Use another Timer that fires events every 10th of a second or so and polls for the Stopwatch value. It won't be nearly as accurate as the Stopwatch since there will be a lag but humans can't really react to anything faster than a 10th of a second.
Use the System.Timers.Stopwatch class, and check if high resolution is available by checking the field IsHighResolution (System.Timers.Stopwatch.IsHighResolution == true).
Then, whenever you need something fired, fire it through another timer at the lowest interval possible, which checks the value of your Stopwatch. Though this won't be perfect (you don't even need close to perfect), it'll work.
I am using timer to scroll the list. Every millisecond interval i am initiating the Tick event. Event though the animation looks very slow.
repeatTimer_Tick(this, new EventArgs());
repeatLeftTimer.Interval = TimeSpan.FromMilliseconds(1);
repeatLeftTimer.Tick += new EventHandler(repeatTimer_Tick);
The timers in windows have a resolution of several milliseconds, IIRC, something between 10 and 50 ms. You can't get the normal timer to tick every millisecond.
I would try to use an animation for what you're doing.
The .NET timer classes generally have a minimum interval of 15.6 ms. If you need a faster increment (down to 1ms) Windows provides a multimedia timer in the unmanaged API. You could import this timer and use it -- I've done it and it works.
I based my code off of this: http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx
Should be most of what you need; I added some code to look at the high resolution timer and observe the time between ticks -- I was able to get it to 1ms, += 0.10 ms
You have two good and (relatively) easy options:
Use an animation - WPF has a very versatile animation system that is likely to be able to do what you need.
Use the CompositionTarget.Rendering Event, those are called as fast as possible (each frame) and you are responsible in each call to set the current status based on the current time (that is how the built in animations work)
If you need a high resolution then I would suggest looking into the Stopwatch class. Use the Frequency field and the ElapsedTicks property to get the resolution you are looking for. Note though that the resolution of the stopwatch will change depending on the hardware. Read the link to the msdn documentation for more information.
I have a timer. But it starts a second late.I mean, i am clocking a time according to the timer. But the time in the clock, which updates through timer, is one second less then the actual time elapsed. The timer starts off a second late. How to set my timer to start at right time to show actual time? this is the code inside tick event:
if (currentState == play)
{
m_StatusLabel.Text = String.Format("Playing {0} ", format(timeCounter));
timeCounter++;
}
Here timeCounter is updating with each second.
Standard System.Windows.Forms timers give no guarantees about 'metronome quality'. For that, you would need either a Systems.Threading.Timer or a System.Timer.
Ref: Comparing the Timer Classes in the .NET Framework Class Library
There are no timers available that will gaurantee true-time accuracy, not even System.Threading.Timer can do that. For example, when you ask Threading.Timer to fire in 30ms, it might actually take 40ms or 200ms. Or if you ask for 1 second, it might fire in 1.01 seconds. In won't take long before your time is inaccurate.
The reason for this is that the timer makes the callback thread schedulable, but it still takes time for the thread scheduler to actually call the thread. Various operations the system is performing can delay that callback.
A Windows timer makes only one guarantee: it won't fire before the timeout interval elapses. Specifically, a thread will never receive a timer event while there are messages in its message queue.
Consequently you can't use timers to implement a clock. If you want to update a status message to show how long something has been playing, then you could try this: record the start time, and when your timer ticks get the current time, subtract the start time, and dislay the difference. Your status message won't be updated exactly every second, but when it is updated it will be correct.
Show a number 1 greater:
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format(++timeCounter) );
NOTE
Please consider the reason of those who suggested displaying the elapsed time as current time - start time. That is the way this is usually done. It is more accurate; a timer can be irregular on a busy system. It is still possible to update the displayed value every second. Pseudo code here for now(). This requires acquiring current time and performing a time difference.
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format( (now() - start)/1000 );
See Also:
1. DateTime.Subtraction
2. DateTime.Now