简体   繁体   中英

A Delay with the Timer when a key is held down

Im having problems with using a Timer within my program. The problem occurs when a key which controls the sprite is held down, as doing this causes the timer to pause until the user releases that key.

A solution which worked for me is calling "Application.DoEvents();" after the keydown method, however by doing this the program utilizes 100% CPU usage causing the game to lag when a key is held down.

Is there another way I can prevent the timer from pausing when the user holds down a key? Any Help would be appreciated.Thanks.

private void timer1_Tick(object sender, EventArgs e)
{
    TimeElasped += 0.1F;
    TimeLabel.Text = String.Format("{0:0.0} Secs" , TimeElasped);
}

private void PlayMenu_KeyDown(object sender, KeyEventArgs e)
{
    //Application.DoEvents();
    if (e.KeyCode == Keys.Left)
    {
        Position.X -= 10;      
    }

    if (e.KeyCode == Keys.Right)
    {
        Position.X += 10;
    }

    if (e.KeyCode == Keys.Up)
    {
        Position.Y -= 10;
    }

    if (e.KeyCode == Keys.Down)
    {
        Position.Y += 10;
    }
}

You don't need a timer to achieve what you're attempting. You could just try doing it on another thread.

In the code below I create a new thread, run an infinite loop on that thread (which won't hold up the CPU, only the thread we created). I sleep the new thread for 0.1 seconds generate the new label text.

You can't update UI elements on anything but the UI thread (which is where you were doing all of your work before). Therefore we have to use the BeginInvoke which updates the label when the UI Thread is ready.

Here's some more info on why I used BeginInvoke if you want to know more: https://harriyott.com/2006/05/using-begininvoke-to-update-gui-safely

I updated the String.Format to use the newer $ string interpolation. It's a little more readable. The compiler replaces it with String.Format in the background anyway but it's a little easier to work with.

For more information on that see: https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C

Finally we need to call your new thread so I do that on form load.

private void PlayMenu_Load(object sender, EventArgs e)
{
    // call our new method that starts a new thread when the form loads.
    StartANewThread();
}

void StartANewThread()
{
    var task = Task.Run(() =>
    {
        /* if you're not used to threading an infinite while loop would look bad but
           it's actually okay because you're going to pause it for 100 milliseconds and 
           it's not going to hold up the rest of the CPU processes.
         */

        while (true)
        {
            // sleep this thread for 0.1 seconds. 
            Thread.Sleep(TimeSpan.FromMilliseconds(100));

            TimeElasped += 0.1F;

            // I would usually use begin invoke to switch back to the UI Thread and update the label
            // as you can't update UI Elements from a Non-UI thread.
            label1.BeginInvoke(new MethodInvoker(UpdateLabelOnUiThread));
        }
    });
}

private void UpdateLabelOnUiThread()
{
    // We're back on the UI thread here because of the BeginInvoke. 
    // We can now update the label.
    label1.Text = $"{TimeElasped:0.0} Secs";
}

A little bonus:

Your if statements in the KeyDown handler were a little messy so I replaced them with a switch statement. I'm not sure if you know about this but it's a lot more readable and easier to work with:

private void PlayMenu_KeyDown(object sender, KeyEventArgs e)
{
    // I also refactored your if statements into a switch. It's a lot cleaner.
    switch (e.KeyCode)
    {
        case Keys.Left:
            Position.X -= 10;
            break;
        case Keys.Right:
            Position.X += 10;
            break;
        case Keys.Up:
            Position.Y -= 10;
            break;
        case Keys.Down:
            Position.Y += 10;
            break;
    }

}

For more information on the switch statement see here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch

I hope this helps, if you need any more information reach out to me in the comments section below. Otherwise please don't forget to mark this as your accepted answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM