Найкращий спосіб реалізувати комбінації клавіш у додатку Windows Forms?


280

Я шукаю найкращий спосіб реалізувати поширені комбінації клавіш для Windows (наприклад, Ctrl+ F, Ctrl+ N) у моєму додатку Windows Forms у C #.

У додатку є основна форма, в якій розміщено багато дитячих форм (по одній). Коли користувач натискає Ctrl+ F, я хотів би показати спеціальну форму пошуку. Форма пошуку залежатиме від поточної відкритої дочірньої форми у додатку.

Я думав використати щось подібне у події ChildForm_KeyDown :

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

Але це не працює. Подія навіть не спрацьовує, якщо натиснути клавішу. Яке рішення?


Це дуже дивно, що Winforms, схоже, не має для цього специфічної функціональності, як це робить рідний API Windows.
Стюарт

Відповіді:


460

Ви, мабуть, забули встановити властивість KeyPreview форми на True. Перевизначення методу ProcessCmdKey () є загальним рішенням:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

Це добре працює, але виявляє його лише для мене, якщо форма є активним вікном. Хтось знає, як це пов’язати так, у будь-якому вікні це можливо?
Gaʀʀʏ

У деяких ситуаціях KeyPreviewцілком незамінний. Наприклад, при натисканні ярлика потрібно придушити введення, але, тим не менш, щоб дозволити започаткувати окрему MenuStripподію. ProcessCmdKeyпідхід змусив би дублювати логіку стрільби подій.
Саул

1
Хм, ні, обробник подій KeyDown форми формально відрізняється від обробника подій клацання пункту меню. Ви все одно точно так само: або безпосередньо викликаєте метод обробника подій безпосередньо (не потрібно, щоб він викликався виключно події), або переробляв загальну логіку на окремий метод.
Ганс Пасант

14
"Що Ctrl + F?" ЛОЛ
кчад

73

На головному бланку

  1. Встановити KeyPreviewзначення True
  2. Додайте обробник подій KeyDown із наступним кодом

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }

4
+ for, встановіть KeyPreview на True .. цього не було
Usman Younas

20

Найкращим способом є використання мнемоніки меню, тобто наявність пунктів меню в основній формі, яким призначено потрібний ярлик клавіатури. Тоді все інше обробляється внутрішньо, і все, що вам потрібно зробити, це здійснити відповідну дію, яка виконується в Clickобробнику подій цього пункту меню.


1
Проблема полягає в тому, що основна форма не використовує загальні меню Windows. На ньому використовується спеціальна панель навігації, яка використовується для показу дочірніх форм. Форми пошуку викликаються натисканням кнопки ToolStripButton на дочірній формі.
Rockcoder

menu mnemonicsреальний зразок?
Кікенет


1
Мнемоніка - це чітке поняття від клавіш швидкого доступу, і існують важливі відмінності в їх роботі. Коротше кажучи, мнемоніка - це підкреслені символи, які використовуються для доступу до меню, команд меню та діалогових елементів керування за допомогою клавіатури. Інші клавіші швидкого доступу - це спосіб доступу до команд, не проходячи через меню, і крім того, вони можуть бути довільними натисканнями клавіш на зразок Ctrl + F або F5, не обмежуючись символьними клавішами.
Стюарт

1
@Stewart Це правильно! Моя відповідь не намагалася натякнути на те, що всі комбінації клавіш - це мнемоніка, лише що мнемоніка меню - це найпростіший спосіб отримати цю функціональність. На жаль, як пояснює коментар Rockcoder, це рішення тут не здається підходящим. Я все-таки рекомендую це як найкраще рішення, де це можливо. Щодо загального рішення, прийнята відповідь Ганса - це шлях вперед.
Конрад Рудольф

11

Ви навіть можете спробувати цей приклад:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}

8

Якщо у вас є меню, то змініть ShortcutKeysвластивістьToolStripMenuItem повинна зробити трюк.

Якщо ні, ви можете створити його і встановити його visibleвластивість false.


Ні, у мене немає меню. ToolStripButton для пошуку фактично розташований у керуванні BindingNavigator, тому додавання меню, ймовірно, не є можливим.
Rockcoder

6

З основної форми ви повинні:

  • Будьте впевнені, що ви встановили для KeyPreview значення true (TRUE за замовчуванням)
  • Додати MainForm_KeyDown (..) - за допомогою якого ви можете тут встановити будь-які ярлики.

Крім того, я знайшов це в google і хотів поділитися цим тим, хто все ще шукає відповіді. (для глобальних)

Я думаю, ви повинні використовувати user32.dll

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == 0x0312)
    {
        /* Note that the three lines below are not needed if you only want to register one hotkey.
         * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

        Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
        KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
        int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


        MessageBox.Show("Hotkey has been pressed!");
        // do something
    }
}

Далі читайте це http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

Відповідь Ганса могла б трохи полегшити когось нового в цьому, тому ось моя версія.

Вам не потрібно дурити KeyPreview, залиште це налаштовано false. Щоб використовувати код нижче, просто вставте його нижче form1_loadта запустіть, F5щоб він працював:

protected override void OnKeyPress(KeyPressEventArgs ex)
{
    string xo = ex.KeyChar.ToString();

    if (xo == "q") //You pressed "q" key on the keyboard
    {
        Form2 f2 = new Form2();
        f2.Show();
    }
}

7
По-перше, переосмислення ProcessCmdKey є рекомендованим способом обробки натискання клавіші, призначеного для виконання певної команди, подібної до операцій, про що запитувала ОП. По-друге, ви неправильно зрозуміли коментар Ганса про встановлення KeyPreview на істинне; він просто казав ОП, чому його техніка не працює. Встановлення KeyPreview на true не потрібне для використання ProcessCmdKey.
RenniePet

2

У WinForm ми завжди можемо отримати статус контрольного ключа:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.