By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,273 Members | 1,037 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,273 IT Pros & Developers. It's quick & easy.

C# Timer tick inaccurate with progressbar

P: 6
Hi

I'm fairly new to .Net programming so I'll try to explain my problem as easy as I can, and in advanced sorry for my poor english.

I've got some spare hours where I work, so I've decided to spend them learning C# .Net.
I've done some smaller programming assignments and decided now to try a larger program.

I'm trying to create a basic game where you the "hero" meets "villains" and monsters in an arena. I want the fighting to be like final fantasy (for those of you who have played it), after each attack you have to wait some seconds before you can attack again(depending on the speed of your weapon).
Here is where my problem lies, I can't get the timer to be accurate. I'll try to explain.

-I got this windows form: Arena, which loads in the player and monster when certain buttons are pressed.

- When all is set, you press the "Fight" button.
Expand|Select|Wrap|Line Numbers
  1. private void FightBtn_Click(object sender, EventArgs e)
  2. {
  3.             Thread playerAttack = new Thread(new ThreadStart(startPlayer));
  4.             Thread monsterAttack = new Thread(new ThreadStart(startMonster));
  5.             playerAttack.Start();
  6.             monsterAttack.Start();
  7. }
  8.  
I want the player and monster to run in threads, so they run independent of each other.

-The monster thread is not importent right now, so I'll just follow the player thread.
Expand|Select|Wrap|Line Numbers
  1. public delegate void new_startPlayer_delegate();
  2.  
  3. private void startPlayer()
  4. {
  5.     Invoke(new new_startPlayer_delegate(new_startPlayer));
  6. }
  7.  
  8. public void new_startPlayer()
  9. {
  10.    playerAttackPnl.Visible = true;            
  11.    PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);
  12. }
  13.  
I'll explain the PlayerTimer.Tick later.
playerAttackPnl is a panel which contains a button called playerattackBtn.
Expand|Select|Wrap|Line Numbers
  1. private void playerattackBtn_Click(object sender, EventArgs e)
  2. {
  3. playerattackBtn.Visible = false;
  4. PlayerTimer.Interval = 100;
  5. playerProgressbar.Maximum = 50;
  6. startTime = DateTime.Now;
  7. PlayerTimer.Enabled = true;
  8. PlayerTimer.Start()
  9. }
  10.  
I have a Windows.Form.Timer called PlayerTimer and a progressbar called playerProgressbar.
So I set the timer interval to 100 and progressbar maximum to 50.
startTime is a datetime and I use it to measure the time.
I also set the button visible to false, so you cant press it again.

-Then we have the PlayerTimer_Tick method.
Expand|Select|Wrap|Line Numbers
  1. private void PlayerTimer_Tick(object sender, EventArgs e)
  2. {
  3.             playerProgressbar.Increment(1);
  4.             if (playerProgressbar.Value >= playerProgressbar.Maximum)
  5.             {
  6.                 PlayerTimer.Stop();
  7.                 PlayerTimer.Enabled = false;
  8.                 playerProgressbar.Value = 0;
  9.                 playerattackBtn.Visible = true;
  10.                 stopTime = DateTime.Now;
  11.                 TimeSpan time = stopTime.Subtract(startTime);
  12.                 MessageBox.Show(Convert.ToString(time));
  13.             }
  14. }
  15.  
So each time the tick fires, I increase the progressbar value with 1 and check if it has reached maximum. If it has, I stop the timer, disable it, set progressbarvalue to 0, show the attack button again and calculate the time this has taken.

The reason I added this "PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);" in the "public void new_startPlayer()" method is because I experienced if I had it in the button click method, the runtime got faster and faster and faster for each run. This I don't know why, maybe some of you know?

But anyhow, now we have a timer with interval 100, and a progress bar who counts to 50, correct me if I'm wrong, but shoulnt this take 5 second?
When I run this, it takes: 2,73455 sec.

If I change the interval to 1000 and max to 10 it takes 5 sec.
Interval 50 and max 100 = 3,1252 sec.

Where am I doing wrong?
I've also tried with System.Timers.Timer, and still not accurate.

Ask if something is unclear.

Thanks in advanced :)

Marius
Mar 4 '08 #1
Share this Question
Share on Google+
9 Replies


shweta123
Expert 100+
P: 692
Hi,

Before the progressbar you should first set the following properties of the progressbar :

1) progressBar1.Maximum
2) progressBar1.Minimum
3) progressBar1.Step
4) progressBar1.Value

Now in your code , you should set the above properties to the following values:

private void playerattackBtn_Click(object sender, EventArgs e)
{
playerattackBtn.Visible = false;
PlayerTimer.Interval = 100;
playerProgressbar.Maximum = 50;
playerProgressbar.Minimum= 0;
playerProgressbar.Value= 0;

startTime = DateTime.Now;
PlayerTimer.Enabled = true;
PlayerTimer.Start()
}

To increment the value of the progressbar you can use one of the following methods :
1) Use increment() method.
e.g. progressbar1.increment(1);
2) Increment the value of progressbar using its Value property.
e.g. progressBar1.Value += 1;

So , in your code you may try it like this :

private void PlayerTimer_Tick(object sender, EventArgs e)
{
playerProgressbar.value +=1;
.................
}





Hi

I'm fairly new to .Net programming so I'll try to explain my problem as easy as I can, and in advanced sorry for my poor english.

I've got some spare hours where I work, so I've decided to spend them learning C# .Net.
I've done some smaller programming assignments and decided now to try a larger program.

I'm trying to create a basic game where you the "hero" meets "villains" and monsters in an arena. I want the fighting to be like final fantasy (for those of you who have played it), after each attack you have to wait some seconds before you can attack again(depending on the speed of your weapon).
Here is where my problem lies, I can't get the timer to be accurate. I'll try to explain.

-I got this windows form: Arena, which loads in the player and monster when certain buttons are pressed.

- When all is set, you press the "Fight" button.
Expand|Select|Wrap|Line Numbers
  1. private void FightBtn_Click(object sender, EventArgs e)
  2. {
  3.             Thread playerAttack = new Thread(new ThreadStart(startPlayer));
  4.             Thread monsterAttack = new Thread(new ThreadStart(startMonster));
  5.             playerAttack.Start();
  6.             monsterAttack.Start();
  7. }
  8.  
I want the player and monster to run in threads, so they run independent of each other.

-The monster thread is not importent right now, so I'll just follow the player thread.
Expand|Select|Wrap|Line Numbers
  1. public delegate void new_startPlayer_delegate();
  2.  
  3. private void startPlayer()
  4. {
  5.     Invoke(new new_startPlayer_delegate(new_startPlayer));
  6. }
  7.  
  8. public void new_startPlayer()
  9. {
  10.    playerAttackPnl.Visible = true;            
  11.    PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);
  12. }
  13.  
I'll explain the PlayerTimer.Tick later.
playerAttackPnl is a panel which contains a button called playerattackBtn.
Expand|Select|Wrap|Line Numbers
  1. private void playerattackBtn_Click(object sender, EventArgs e)
  2. {
  3. playerattackBtn.Visible = false;
  4. PlayerTimer.Interval = 100;
  5. playerProgressbar.Maximum = 50;
  6. startTime = DateTime.Now;
  7. PlayerTimer.Enabled = true;
  8. PlayerTimer.Start()
  9. }
  10.  
I have a Windows.Form.Timer called PlayerTimer and a progressbar called playerProgressbar.
So I set the timer interval to 100 and progressbar maximum to 50.
startTime is a datetime and I use it to measure the time.
I also set the button visible to false, so you cant press it again.

-Then we have the PlayerTimer_Tick method.
Expand|Select|Wrap|Line Numbers
  1. private void PlayerTimer_Tick(object sender, EventArgs e)
  2. {
  3.             playerProgressbar.Increment(1);
  4.             if (playerProgressbar.Value >= playerProgressbar.Maximum)
  5.             {
  6.                 PlayerTimer.Stop();
  7.                 PlayerTimer.Enabled = false;
  8.                 playerProgressbar.Value = 0;
  9.                 playerattackBtn.Visible = true;
  10.                 stopTime = DateTime.Now;
  11.                 TimeSpan time = stopTime.Subtract(startTime);
  12.                 MessageBox.Show(Convert.ToString(time));
  13.             }
  14. }
  15.  
So each time the tick fires, I increase the progressbar value with 1 and check if it has reached maximum. If it has, I stop the timer, disable it, set progressbarvalue to 0, show the attack button again and calculate the time this has taken.

The reason I added this "PlayerTimer.Tick += new EventHandler(PlayerTimer_Tick);" in the "public void new_startPlayer()" method is because I experienced if I had it in the button click method, the runtime got faster and faster and faster for each run. This I don't know why, maybe some of you know?

But anyhow, now we have a timer with interval 100, and a progress bar who counts to 50, correct me if I'm wrong, but shoulnt this take 5 second?
When I run this, it takes: 2,73455 sec.

If I change the interval to 1000 and max to 10 it takes 5 sec.
Interval 50 and max 100 = 3,1252 sec.

Where am I doing wrong?
I've also tried with System.Timers.Timer, and still not accurate.

Ask if something is unclear.

Thanks in advanced :)

Marius
Mar 4 '08 #2

P: 6
Hi

Thanks for quick response.

I've done what you said, but it still doesnt work.


I've tried both: playerProgressbar.increment(1); and
playerProgressbar.Value += 1;
playerProgressbar.step is 1.

But still returns the same value: 2, 7343 sec when interval is 100 and maximum is 50.

Regards
Marius

Hi,

Before the progressbar you should first set the following properties of the progressbar :

1) progressBar1.Maximum
2) progressBar1.Minimum
3) progressBar1.Step
4) progressBar1.Value

Now in your code , you should set the above properties to the following values:

private void playerattackBtn_Click(object sender, EventArgs e)
{
playerattackBtn.Visible = false;
PlayerTimer.Interval = 100;
playerProgressbar.Maximum = 50;
playerProgressbar.Minimum= 0;
playerProgressbar.Value= 0;

startTime = DateTime.Now;
PlayerTimer.Enabled = true;
PlayerTimer.Start()
}

To increment the value of the progressbar you can use one of the following methods :
1) Use increment() method.
e.g. progressbar1.increment(1);
2) Increment the value of progressbar using its Value property.
e.g. progressBar1.Value += 1;

So , in your code you may try it like this :

private void PlayerTimer_Tick(object sender, EventArgs e)
{
playerProgressbar.value +=1;
.................
}
Mar 4 '08 #3

shweta123
Expert 100+
P: 692
Hi,

I think the difference in the no of seconds is coming because
you are calculating startTime in the procedure playerattackBtn_Click(). Instead of this if you calculate startTime in PlayerTimer_Tick() procedure you might get the correct result.

e.g.

private void PlayerTimer_Tick(object sender, EventArgs e)
{
if(startTime == "")
{
//set the startTime value here when timer starts
startTime = DateTime.Now;
}
playerProgressbar.Increment(1);
if (playerProgressbar.Value >= playerProgressbar.Maximum)
{
PlayerTimer.Stop();
PlayerTimer.Enabled = false;
playerProgressbar.Value = 0;
playerattackBtn.Visible = true;
stopTime = DateTime.Now;
TimeSpan time = stopTime.Subtract(startTime);
MessageBox.Show(Convert.ToString(time));
}
}




Hi

Thanks for quick response.

I've done what you said, but it still doesnt work.


I've tried both: playerProgressbar.increment(1); and
playerProgressbar.Value += 1;
playerProgressbar.step is 1.

But still returns the same value: 2, 7343 sec when interval is 100 and maximum is 50.

Regards
Marius
Mar 4 '08 #4

P: 6
Nope, still didnt work, got the same value: 2,73.
Correct me if I'm wrong but when you have interval = 100 and maximum = 50, you go one step each tick, shouldnt the time running this be 5 sec?
Then 2,73 is pretty far off. Cant be a minor code delay, I must have typed something wrong somewhere.
The problem is to find out where.

Regards
Marius

Hi,

I think the difference in the no of seconds is coming because
you are calculating startTime in the procedure playerattackBtn_Click(). Instead of this if you calculate startTime in PlayerTimer_Tick() procedure you might get the correct result.

e.g.

private void PlayerTimer_Tick(object sender, EventArgs e)
{
if(startTime == "")
{
//set the startTime value here when timer starts
startTime = DateTime.Now;
}
playerProgressbar.Increment(1);
if (playerProgressbar.Value >= playerProgressbar.Maximum)
{
PlayerTimer.Stop();
PlayerTimer.Enabled = false;
playerProgressbar.Value = 0;
playerattackBtn.Visible = true;
stopTime = DateTime.Now;
TimeSpan time = stopTime.Subtract(startTime);
MessageBox.Show(Convert.ToString(time));
}
}
Mar 4 '08 #5

Plater
Expert 5K+
P: 7,872
Everytime you add an event handler, it will do just that ADD ANOTHER event handler, so the first run with get a single eventhandler, the 2nd run will get two and so on and so.
Meaning the speed is cut in half each time.
An interval of 100 is 1/10 of a second, so you should be getting a 5second total wait time.

Only add the event handler ONCE and don't do it again, unless you remove it (which i think is almost identical commands except instead of += you say -=)
Mar 4 '08 #6

P: 6
Thanks alot :)

The event got created in the background when the form loaded, so I just had to remove the event in my code.
The time is still of by 0,4 but I'm sure it just has something to do with where I start and stop my timecount.

Regards
Marius

Everytime you add an event handler, it will do just that ADD ANOTHER event handler, so the first run with get a single eventhandler, the 2nd run will get two and so on and so.
Meaning the speed is cut in half each time.
An interval of 100 is 1/10 of a second, so you should be getting a 5second total wait time.

Only add the event handler ONCE and don't do it again, unless you remove it (which i think is almost identical commands except instead of += you say -=)
Mar 4 '08 #7

shweta123
Expert 100+
P: 692
Hi,

I have two suggestions :

1) You can try DateDiff function for calculating the difference in time.
e.g. DateDiff("s", startTime, stopTime) .

2) Also , in your code you are checking for progressbar value >= progressbar.maximum. Instead of this you can compare it using progressbar value = progressbar.maximum

Nope, still didnt work, got the same value: 2,73.
Correct me if I'm wrong but when you have interval = 100 and maximum = 50, you go one step each tick, shouldnt the time running this be 5 sec?
Then 2,73 is pretty far off. Cant be a minor code delay, I must have typed something wrong somewhere.
The problem is to find out where.

Regards
Marius
Mar 4 '08 #8

P: 6
I think I've figured out why the time is so off.

When I use long intervals and small progressbar.max I get an accurate time.
e.g. interval = 1000 and max = 5 equals 5,000067 sec
but when I use interval 100 and max = 50 I get 5,75

So the more steps you have, the more the "left over" time 000067 gets accumulated into a bigger off time.

Which brings me to my next question, If I use longer intervals and smaller max values, the progressbar jumps 1/3 for each tick, this does not look very nice. Is there a way to get it to go smooth?
I've tried using the style=continuous on the progressbar properties with no luck.

Regards
Marius

Hi,

I have two suggestions :

1) You can try DateDiff function for calculating the difference in time.
e.g. DateDiff("s", startTime, stopTime) .

2) Also , in your code you are checking for progressbar value >= progressbar.maximum. Instead of this you can compare it using progressbar value = progressbar.maximum
Mar 5 '08 #9

P: 6
I was wrong, I found out that the program ran an extra tick.

So interval 1000 and max 5 became 6 sec

So thats why the time is so off when using large max values, another tick is fired after the code is supposed to be finished.


I think I've figured out why the time is so off.

When I use long intervals and small progressbar.max I get an accurate time.
e.g. interval = 1000 and max = 5 equals 5,000067 sec
but when I use interval 100 and max = 50 I get 5,75

So the more steps you have, the more the "left over" time 000067 gets accumulated into a bigger off time.

Which brings me to my next question, If I use longer intervals and smaller max values, the progressbar jumps 1/3 for each tick, this does not look very nice. Is there a way to get it to go smooth?
I've tried using the style=continuous on the progressbar properties with no luck.

Regards
Marius
Mar 5 '08 #10

Post your reply

Sign in to post your reply or Sign up for a free account.