Недостаток настройки Form.KeyPreview = true? - PullRequest
24 голосов
/ 05 марта 2010

Интересно, для чего на самом деле подходит свойство Form.KeyPreview?Почему он существует и чем я «рискую», устанавливая его в true?Я предполагаю, что он должен иметь некоторый отрицательный эффект - иначе он не должен существовать вообще (или, по крайней мере, быть истинным по умолчанию)?

РЕДАКТИРОВАТЬ : я прекрасно знаюхорошо что это делает.Я спрашиваю почему .Почему я должен установить его в значение true, чтобы вызвать события клавиатуры?Почему события клавиатуры не всегда запускаются для формы.Что не только в этом стандартном поведении?

Конкретная причина, по которой я спрашиваю: я только что установил KeyPreview = true в базовой форме моего приложения, от которой наследуются все другие формы.Я готовлюсь к неприятному сюрпризу?

Ответы [ 4 ]

64 голосов
/ 05 марта 2010

Form.KeyPreview - это анахронизм, унаследованный от объектной модели Visual Basic для проектирования форм. Еще в дни VB6 вам нужно было KeyPreview, чтобы иметь возможность осуществлять сочетания клавиш. Это больше не требуется в Windows Forms, лучше переопределить ProcessCmdKey():

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    DoSomething();   // Implement the Ctrl+F short-cut keystroke
    return true;     // This keystroke was handled, don't pass to the control with the focus
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

Но KeyPreview был поддержан, чтобы помочь легиону программистов VB6 перейти на .NET еще в начале 2000-х. Смысл KeyPreview или ProcessCmdKey() заключается в том, чтобы позволить вашему пользовательскому интерфейсу реагировать на нажатия клавиш. Сообщения с клавиатуры обычно отправляются на элемент управления, который имеет фокус. Цикл сообщений Windows Forms позволяет коду взглянуть на это сообщение до того, как его увидит элемент управления. Это важно для сочетаний клавиш, реализация события KeyDown для каждого элемента управления , который может привлечь внимание к их обнаружению, очень непрактична.

Установка KeyPreview в True не вызывает проблем. Событие формы KeyDown будет запущено, оно будет иметь влияние, только если у него есть код, который что-то делает с нажатием клавиши. Но имейте в виду, что он внимательно следит за использованием VB6, вы не можете увидеть, какие нажатия клавиш используются для навигации. Как и клавиши курсора и Tab, Escape и Enter для диалога. Не проблема с ProcessCmdKey().

4 голосов
/ 05 марта 2010

С MSDN

Когда для этого свойства установлено значение true, Форма получит все KeyPress, События KeyDown и KeyUp. После обработчики событий формы завершены обрабатывая нажатие клавиш, нажатие клавиши затем назначается управление с фокусом. Например, если свойство KeyPreview установлено в true и текущий выбранный элемент управления TextBox, после нажатия клавиши обрабатывается обработчиками событий форма элемента управления TextBox получит ключ, который был нажат. Обрабатывать события клавиатуры только на уровне формы и не позволять элементам управления получать события клавиатуры, установите KeyPressEventArgs.Handled свойство в обработчик событий KeyPress вашей формы для правда.

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

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

E.G Пользователь нажимает клавишу K, вызываются обработчики событий форм (Key Down, Key Up, Key Pressed), а затем вызываются обработчики событий в текущем активном элементе управления.

РЕДАКТИРОВАТЬ : Нет, нет никаких недостатков или неприятных сюрпризов. Единственное, о чем я могу думать, это очень небольшое снижение производительности, так как нужно проверять дескрипторы событий в форме для каждого KeyDown, KeyUp, KeyPressed. Кроме того, если вы не добавляете обработчики событий в форму и делаете что-то, что может вызвать проблемы. ты в порядке. Если вам не нужно глобально обрабатывать ключевые события, кроме элементов управления, я бы посоветовал вам оставить это значение false, чтобы предотвратить дополнительные проверки. На современных ПК это не имеет видимой разницы.

2 голосов
/ 23 марта 2015

Стандартная модель событий Windows состоит в том, что окно с фокусом клавиатуры получает все события клавиатуры. Помните, что в Windows все является окном - «элемент управления» - это просто окно, являющееся дочерним элементом другого окна. Это окно должно отправлять сообщения своему родителю, если оно решит сделать это, когда нажимаются определенные клавиши.

Для стандартизации навигации между элементами управления в диалоговом окне Windows также предоставляет «диспетчер диалогов». В нативном коде для модальных диалогов это обрабатывается модальным циклом сообщений внутри функции DialogBox. Для немодальных диалогов вы должны вызывать IsDialogMessage в вашем собственном цикле сообщений. Вот как он крадет клавиши Tab и курсора, чтобы перемещаться между элементами управления, и Enter, чтобы нажать кнопку по умолчанию. Это имеет противоположный эффект - не позволяет элементам управления обрабатывать Enter по умолчанию, что обычно обрабатывается многострочными элементами управления. Чтобы выяснить, хочет ли элемент управления обрабатывать ключ, код диспетчера диалогов посылает сфокусированному элементу управления сообщение WM_GETDLGCODE; если элемент управления отвечает соответствующим образом, менеджер диалога возвращает FALSE, позволяя DispatchMessage фактически доставить его в оконную процедуру, в противном случае менеджер диалога делает свое дело.

Windows Forms в основном просто оборачивает старые нативные элементы управления, поэтому он должен соответствовать модели событий Win32. Он реализует тот же подход диспетчера диалогов - следовательно, по умолчанию он не позволяет видеть Tab, Return и клавиши курсора.

Рекомендуемый подход, если вы хотите обработать один из этих ключей, это переопределить PreviewKeyDown и установить для свойства PreviewKeyDownEventArgs IsInputKey значение true.

1 голос
/ 16 мая 2019

Простая и тривиальная, хотя и практическая причина:

В такой игре, как Space Invaders https://www.mooict.com/c-tutorial-create-a-full-space-invaders-game-using-visual-studio/, пользователь неоднократно стучит пробелом, чтобы испарить инопланетян. Когда последний захватчик ушел, всплывающее текстовое поле, чтобы сказать, «хорошая работа». Пользователь все еще дергается большим пальцем, нажимая пробел (или, может быть, только освобождение буфера клавиатуры?), И поздравляющий MessageBox исчезает, прежде чем его можно прочитать. Я не мог видеть обходной путь из-за того, как формы обрабатывают нажатия кнопок / пробела.

Мой пользовательский диалог использует предварительный просмотр клавиш для предварительной обработки нажатий клавиш, отправленных GameOverDialog, чтобы игнорировать любые нажатия пробела. Пользователь должен закрыть с помощью мыши или Enter. Это просто FixedDialog с меткой «Вы выиграли» и кнопкой [OK].

public partial class GameOverDialog : Form
{
    public GameOverDialog()
    {
        InitializeComponent();
        this.MaximizeBox = false;
        this.MinimizeBox = false;
    }

    // keyhandler keypreview = true
    private void SpaceDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space)
        {
            e.Handled = true;
            return;
        }
    }

    private void SpaceUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space)
        {
            e.Handled = true;
            return;
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}

Кроме того, интересный вариант, который я не тестировал: если вы подумаете об этом, это был бы отличный способ встроить читы, скрытые сообщения и т. Д. В безобидные диалоги [OK] или любую форму, которая позволяет просматривать ключи.

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