Как правильно перехватывать нажатия клавиш в Windows Forms (C++)?

183
26 июля 2018, 03:30

На Form есть DataGridView (в нём показывается одна строка) и WebBrowser.

У Form на Event keyDown есть обработчик, который срабатывает на нажатие F2, который записывает слово в определенную ячейку. Этот же обработчик привязан к DataGridView.

private: System::Void CSV_WViewForm_KeyDown(
    System::Object^  sender,
    System::Windows::Forms::KeyEventArgs^  e)
    {
        if (e->KeyCode == Keys::F2)
            /*Do something*/;           
    }

Необходимо, чтобы нажатие на F2 срабатывало всегда и сразу (с первого раза). Для этого я воспользовался свойством KeyPreview = false; (пробовал устанавливать его в true - не помогало).

protected:
    virtual bool ProcessCmdKey(Message% msg, Keys keyData) override
    {
        if (keyData == Keys::F2)
        {
            this->dataGridView1->Focus();
            return Form::ProcessCmdKey(msg, keyData);
        }
        return Form::ProcessCmdKey(msg, keyData);
    }

Но когда Focus находится в WebBrowser, F2 не всегда срабатывает (иногда приходится нажимать F2 дважды). Как это победить?

Проект Windows Forms (C++, Visual Studio 2015)

Answer 1

Если уж перехватываете ввод пользователя на уровне формы, то там его и обрабатывайте. Простой тестовый проект с эквивалентным кодом на C# показал следующее:

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

Что делать?

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

Изменить ваш код можно так:

virtual bool ProcessCmdKey(Message% msg, Keys keyData) override
    {
        if (keyData == Keys::F2)
        {
            this->dataGridView1->Focus();
            //do somthing for F2-key
            return true;
        }
        return Form::ProcessCmdKey(msg, keyData);
    }

или через switch - case если клавиш много. И не забываем удалить лишние обработчики или исключить из них обработку клавиш, перехватываемых на уровне формы.

Answer 2

Можно поступить следующим образом.

Добавляем на форму меню (если его ещё нет) - MenuStrip. Если меню само по себе не нужно в приложении, то скрываем его: Visible = false. Добавляем в меню пункт с любым названием, назначаем ему обработчик клика (в нём выполняются нужные вам действия) и главное - задаём свойству ShortcutKeys нужное значение: кнопку F2.

Теперь нажатие на F2 будет срабатывать в любом случае, какой-бы компонент ни был в фокусе.

Проверял в C#.

READ ALSO
C++ ошибка dependent name is not a type, prefix with 'typename' to indicate a type

C++ ошибка dependent name is not a type, prefix with 'typename' to indicate a type

пишу бинарное дерево и наткнулся на очень непонятную мне ошибку, вот пример:

208
Вывод кол-во раз char * какой-то int

Вывод кол-во раз char * какой-то int

Пытаюсь сделать следующие,

203
Qml fullscreen окно

Qml fullscreen окно

Необходимо отрисовать главное окно в фулскринеПодскажите как это сделать! Нагугли что можно выводить так :

198
Java не видит классы

Java не видит классы

Решил потренироваться на сборке LineageСам сервер поднимается нормально, но не грузиться ни один квест

167