I need to store the piano duration with Ticks as so then make the music note show according to that duration (Music players would know).
I'm using an interval of 100, but for some testing I used it at 1000.
The problem is this. When I'm invoking the method (I'm taking the 1000 millisecond interval one) the timer starts.. if I DO NOT manage to get the 1000 milliseconds it shows Duration 0: but then if I do for example 2 seconds, it shows 3 seconds, if I try to press it for another second (a different key) it would show 4 seconds instead of 1.
It's like it keeps on recurring. Same happened with the 100 interval one. It went mad. sometimes 40 sometimes 23 and so on. Any idea how to fix (resetting the timer)
N.B I'm using System.Windows.Forms.Timer as library
part of a method which invokes the methods further below
for (int i = 0; i < 15; i++)
{
WhiteKey wk = new WhiteKey(wKeys[i], wPos[i]-35,0); //create a new white Key with [i] Pitch, at that x position and at y =0 position
wk.MouseDown += onRightClick; //holds the Duration on Right Click
wk.MouseUp += onMouseUp;
wk.Click += new EventHandler(KeyClick); //Go to KeyClick Method whenever a key is pressed
this.panel1.Controls.Add(wk); //Give it control (to play and edit)
}
Methods controlling the time
private void onRightClick(object sender, MouseEventArgs e)
{
wk = sender as WhiteKey;
duration = 0;
t1.Enabled = true;
t1.Tick += timeTick;
t1.Interval = 100;
}
private void timeTick(object sender, EventArgs e)
{
duration++;
}
private void onMouseUp (object sender, MouseEventArgs e)
{
t1.Enabled = false;
String time = "Key: " + pitch + "\nDuration: " +duration ; //Test purposes to see if timer works
MessageBox.Show(time);
}
You are trying to measure time, don't use Timer, use Stopwatch.
You can find C# Stopwatch Exmples at dotnetpearls.com.
In abstract this is what you would want to do is something like this:
private void onRightClick(object sender, MouseEventArgs e)
{
stopwatch.Reset();
stopwatch.Start();
}
private void onMouseUp (object sender, MouseEventArgs e)
{
stopwatch.Stop();
String msg = "Duration in seconds: " + (stopwatch.ElapsedMilliseconds / 1000.0).ToString("0.00");
MessageBox.Show(msg);
}
Note: you may want to change the units or the string format.
Notes on using timer:
1) System.Windows.Forms.Timer uses the message loop of your window, this means that it may get delayed because the window is busy handling other events (such as click). For a better behaviour use System.Threading.Timer.
2) If using System.Windows.Forms.Timer don't set the Tick event handler each click. The event handler will execute once for each time you add it.
That is:
private void onRightClick(object sender, MouseEventArgs e)
{
wk = sender as WhiteKey;
duration = 0;
t1.Enabled = true;
//t1.Tick += timeTick; you should add this only once not each click
t1.Interval = 100;
}
3) If you use System.Threading.Timer you may want to make the variable duration volatile.
t1.Tick += timeTick;
By the way in your code sample you subscribe to the 'Tick' timer event each time on Right mouse click.
So if you click 2 times the
private void timeTick(object sender, EventArgs e)
method will be called twice, and 'duration++' will be executed twice. Your event subscription code should be executed only once for the timer.
P.S. If you need to measure duration, Timer is not the best way to do it.
Related
I have a little problem. There is something like chess timer. When i press button, current timer stops and second starts, but after 1 second. How can i start second one immediately?
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1 {
public partial class Form1 : Form {
byte sec1;
byte sec2;
public Form1() {
InitializeComponent();
sec1 = 0;
sec2 = 0;
}
private void button1_Click(object sender , EventArgs e) {
timer1.Start();
timer2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
timer2.Start();
timer1.Stop();
}
private void timer1_Tick(object sender , EventArgs e) {
label1.Text = sec1.ToString();
sec1++;
}
private void timer2_Tick(object sender , EventArgs e) {
label2.Text = sec2.ToString();
sec2++;
}
}
}
Edit
I know your question is "how to start the timers immediately", but in your code they are starting immediately. When you call start the timer starts. I believe the effect you are seeing is related to the delay associated with the tick event, which from the description I am assuming is set to a 1 second interval. Since you have said that you are trying to simulate something similar to a chess timer (although in your case counting up as opposed to down), then using something like a stop watch which can start, stop and show elapsed time would be a closer model. Since there is a Stopwatch class that provides exactly this behavior, I think it would be easier to implement it using two of those and just have a single background thread that updates the UI as frequently as needed. You could even add an update call into each button push to ensure the text boxes are up to date.
===============================
Maybe instead of the timers you should use two instances of the Stopwatch class. This will remove the need for your two variables that you are using to keep track of the seconds as the Stopwatch class will be holding the elapsed time for each counter.
Then in your button methods you could just do this:
private Stopwatch sw1 = new Stopwatch();
private Stopwatch sw2 = new Stopwatch();
private void button1_Click(object sender , EventArgs e) {
sw1.Start();
sw2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
sw2.Start();
sw1.Stop();
}
And then you can use a Background worker or some other background thread that runs and updates your text boxes with the elapsed time from the timers you just need to grab the elapsed time.
// This will give you the total number of seconds elapsed.
var timer1Seconds = Math.Floor(sw1.Elapsed.TotalSeconds);
Here is an example of how you can make this update the UI:
private bool _stop = false;
public Form1()
{
InitializeComponent();
Task.Run(() =>
{
while(!_stop)
{
UpdateElapsedTimes();
Thread.Sleep(1000);
}
}
}
private void UpdateElapsedTimes()
{
if (InvokeRequired)
{
Invoke(UpdateElapsedTimes());
return;
}
label1.Text = Math.Floor(sw1.Elapsed.TotalSeconds).ToString();
label2.Text = Math.Floor(sw2.Elapsed.TotalSeconds).ToString();
}
Note - in a production program I would not use a boolean as my loop checker, you would use an event handle, and probably a couple of event handles if you wanted to allow pausing the updates, this is just to show an idea of how to do it. You could invoke directly from the thread method and drop the InvokeRequired check, but I added that for additional safety and since it was there I skipped it in the loop.
The timer does start immediately. The problem is that you are not reporting fractions of seconds, so the display will show 0 until a full second has elapsed, which is accurate, technically.
If you want to show 1 immediately, just initialize your variables that way.
public Form1() {
InitializeComponent();
sec1 = 1;
sec2 = 1;
}
How can i measure time between click in the way that if the time between button clicks is lets say >=1000 ms (1 sec) something happends, eg. Msgbox pops out.
private void button1_Click(object sender, EventArgs e)
{
Stopwatch sw = new Stopwatch();
double duration = sw.ElapsedMilliseconds;
double tt = 2000;
sw.Start();
if (duration >= tt)
{
textBox1.Text = "Speed reached!";
}
else
{
sw.Stop();
duration = 0;
}
}
You can do it like this:
On first click start the timer with time interval of 1000 ms
On second click stop the timer, or reset it back to zero
If the timer finishes without interruption, its event handler displays the message box.
As you have specifically tried to code using the Stopwatch class then I will provide a solution using that.
The problem with your attempt is that you need to declare your Stopwatch instance as a global variable, so you can access the same instance on different click events.
Stopwatch sw = new Stopwatch();
private void button1_Click(object sender, EventArgs e)
{
// First we need to know if it's the first click or the second.
// We can do this by checking if the timer is running (i.e. starts on first click, stops on second.
if(sw.IsRunning) // Is running, second click.
{
// Stop the timer and compare the elapsed time.
sw.Stop();
if(sw.ElapsedMilliseconds > 1000)
{
textBox1.Text = "Speed reached!";
}
}
else // Not running, first click.
{
// Start the timer from 0.
sw.Restart();
}
}
My program is some kind of test. The time of passing test is limited(20 minutes). When the time is out, the test must be finished and MessageBox appears with results of test. In Form_Load :
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = (1000) * (1);
timer1.Enabled = true;
timer1.Start();
private void timer1_Tick(object sender, EventArgs e)
{
timer_label.Text = Convert.ToString(time);
--time;
}
How to finish test when time == 0? And why time in timer_label changes with step 2?(e.g. 1999, 1997, 1995...)
How to finish test when time == 0?
Timer just raises even on some interval. You should start timer for that. If you don't want events to be raised anymore, you should stop timer. You can do it directly in Tick event handler:
private void timer1_Tick(object sender, EventArgs e)
{
timer_label.Text = Convert.ToString(time);
time--;
if (time == 0)
timer1.Stop();
}
Second question:
And why time in timer_label changes with step 2?(e.g. 1999, 1997,
1995...)
From your code there is no reason for such behavior. Looks like you have subscribed to two timers, or you have two event handlers of same timer Tick event. Also make sure you don't have decrement operator when displaying time, something like this:
timer_label.Text = Convert.ToString(--time);
--time;
i want timer to run a counter from 0 to 3. i added the timer from the toolbox in visual basics 2008 (instead of creating an object and using properties) you can see the Timer at the bottom of the winform..
int timerCounter;
private void animationTimer_Tick(object sender, EventArgs e)
{
//timer should go 0,1,2,3..and then reset
while (true)
{
timerCounter++;
if (timerCounter > 3)
{
timerCounter = 0;
}
game.Twinkle();
//screen gets repainted.
Refresh();
}
}
will the timer work?
(i enabled it and set it to 33 milliseconds)
Set the timer's interval to 1000 (which is 1000ms or 1 second). Then when you enable it, it'll go on and on and on, firing the timer1_tick event every time it goes through the interval.
Here's an example on how to do it:
int count = 0;
private void timer1_Tick(object sender, EventArgs e)
{
count++;
if (count == 3)
{
//Do something here, because it's the third toll of the bell.
//But also reset the counter after you're done.
count = 0;
}
}
Don't forget to .Enable the timer!
I want to display current time on a label using C# but time will continuously change as system time changes. How can I do this?
Add a new Timer control to your form, called Timer1, set interval to 1000 (ms), then double click on the Timer control to edit the code-behind for Timer1_Tick and add this code:
this.label1.Text = DateTime.Now.ToString();
You can Add a timer control and specify it for 1000 millisecond interval
private void timer1_Tick(object sender, EventArgs e)
{
lblTime.Text = DateTime.Now.ToString("dd-MMM-yyyy hh:mm:ss tt");
}
Add a Timer control that is set to fire once every second (1000 ms). In that timer's Tick event, you can update your label with the current time.
You can get the current time using something like DateTime.Now.
Try the following code:
private void timer1_Tick(object sender, EventArgs e)
{
lblTime.Text = DateTime.Now.ToString("hh:mm:ss");
}
You must set the timer to be enabled also, either in code, or in the properties window.
in code, please type the following in the form load section:
myTimer.Enabled = true;
myTimer.Interval = 1000;
After that, make sure your timer event is similar to this:
private void myTimer_Tick(object sender, EventArgs e)
{
timeLabel.Text = DateTime.Now.ToString("hh:mm:ss");
}
Since the timer interval is not exact your update could be in bad sync and will be drifting with respect to the actual seconds transition. At some events you will lag behind or before the transition and miss updates in your time display
Instead of polling att high frequency to fire the update at the change of the seconds this method may grant you some respect.
If you like regulators you can adjust your time update to be safely located 100 ms after the actual second transition by adjusting the 1000 ms timer using the Millisecond property of the timestamp you want to display.
In the timer event code do something like this:
//Read time
DateTime time = DateTime.Now;
//Get current ms offset from prefered readout position
int diffms = time.Millisecond-100;
//Set a new timer interval with half the error applied
timer.Interval = 1000 - diffms/2;
//Update your time output here..
Next timer interval should then trigger closer to the selected point 100 ms after the seconds transition. When at the Transition+100ms the error will toggle +/- keeping your readout position in time.
private int hr, min, sec;
public Form2()
{
InitializeComponent();
hr = DateTime.UtcNow.Hour;
min = DateTime.UtcNow.Minute;
sec = DateTime.UtcNow.Second;
}
//Time_tick click
private void timer1_Tick(object sender, EventArgs e)
{
hr = DateTime.UtcNow.Hour;
hr = hr + 5;
min = DateTime.UtcNow.Minute;
sec = DateTime.UtcNow.Second;
if (hr > 12)
hr -= 12;
if (sec % 2 == 0)
{
label1.Text = +hr + ":" + min + ":" + sec;
}
else
{
label1.Text = hr + ":" + min + ":" + sec;
}
}