Задержка с таймером, когда нажата клавиша - PullRequest
0 голосов
/ 28 февраля 2019

У меня проблемы с использованием таймера в моей программе.Проблема возникает, когда клавиша, управляющая спрайтом, удерживается нажатой, поскольку при этом таймер приостанавливается до тех пор, пока пользователь не отпустит этот ключ.

Решение, которое сработало для меня, вызывает "Application.DoEvents ();"однако после способа нажатия клавиш программа использует 100% загрузку ЦП, что приводит к зависанию игры при удержании клавиши.

Есть ли другой способ предотвратить приостановку таймера, когда пользователь удерживает нажатой клавишуключ?Любая помощь будет оценена. Спасибо.

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;
    }
}

1 Ответ

0 голосов
/ 28 февраля 2019

Вам не нужен таймер, чтобы достичь того, что вы пытаетесь.Вы можете просто попробовать сделать это в другом потоке.

В приведенном ниже коде я создаю новый поток, запускаю бесконечный цикл в этом потоке (который не будет поддерживать процессор, только созданный нами поток).Я сплю новый поток в течение 0,1 секунды, генерирую новый текст метки.

Вы не можете обновить элементы пользовательского интерфейса ни на чем, кроме потока пользовательского интерфейса (в котором вы делали всю свою работу раньше).Поэтому мы должны использовать BeginInvoke, который обновляет метку, когда поток пользовательского интерфейса готов.

Вот еще немного информации о том, почему я использовал BeginInvoke, если вы хотите узнать больше: https://harriyott.com/2006/05/using-begininvoke-to-update-gui-safely

Я обновил String.Format, чтобы использовать более новую интерполяцию $ string.Это немного более читабельно.В любом случае компилятор заменяет его на String.Format в фоновом режиме, но с ним немного проще работать.

Для получения дополнительной информации см .: https://weblog.west -wind.com / posts / 2016 / Dec / 27 / Back-to-Basics-String-Interpolation-in-C

Наконец, нам нужно вызвать ваш новый поток, так что я делаю это при загрузке формы.

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";
}

Небольшой бонус:

Ваши операторы if в обработчике KeyDown были немного грязными, поэтому я заменил их на оператор switch.Я не уверен, что вы знаете об этом, но с ним гораздо удобнее читать и с ним легче работать:

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;
    }

}

Подробнее о выражении switch см. Здесь: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch

Надеюсь, это поможет, если вам понадобится дополнительная информация, обратитесь ко мне в разделе комментариев ниже.В противном случае, пожалуйста, не забудьте пометить это как принятый ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...