Il modo migliore per implementare le scorciatoie da tastiera in un'applicazione Windows Form?


280

Sto cercando il modo migliore per implementare le scorciatoie da tastiera comuni di Windows (ad esempio Ctrl+ F, Ctrl+ N) nella mia applicazione Windows Form in C #.

L'applicazione ha un modulo principale che ospita molti moduli figlio (uno alla volta). Quando un utente preme Ctrl+ F, mi piacerebbe mostrare un modulo di ricerca personalizzato. Il modulo di ricerca dipende dall'attuale modulo figlio aperto nell'applicazione.

Stavo pensando di usare qualcosa del genere nell'evento ChildForm_KeyDown :

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

Ma questo non funziona. L'evento non si attiva nemmeno quando si preme un tasto. Qual'è la soluzione?


È davvero strano che Winforms non abbia funzionalità specifiche per questo come l'API nativa di Windows.
Stewart,

Risposte:


460

Probabilmente hai dimenticato di impostare la proprietà KeyPreview del modulo su True. La sostituzione del metodo ProcessCmdKey () è la soluzione generica:

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

Funziona bene, ma lo rileva solo se il modulo è la finestra attiva. Qualcuno sa come legarlo così in qualsiasi vista della finestra è possibile?
Gaʀʀʏ

In alcune situazioni KeyPreviewè abbastanza indispensabile. Ad esempio, quando si preme una scorciatoia è necessario sopprimere l'input ma tuttavia consentire l'attivazione di un MenuStripevento separato . ProcessCmdKeyl'approccio forzerebbe la duplicazione della logica di attivazione degli eventi.
Saul,

1
Hmm, no, il gestore eventi KeyDown del form è abbastanza distinto dal gestore eventi Click di una voce di menu. Continui a fare esattamente lo stesso, o chiama direttamente il metodo del gestore eventi (non è necessario che venga chiamato esclusivamente da un evento) o trasforma la logica comune in un metodo separato.
Hans Passant,

14
"Che cos'è Ctrl + F?" LOL
kchad

73

Nel tuo modulo principale

  1. Impostare KeyPreviewsu True
  2. Aggiungi il gestore eventi KeyDown con il seguente codice

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

4
+ per, imposta KeyPreview su True .. mancava quello
Usman Younas il

20

Il modo migliore è utilizzare i menu mnemonici, ovvero avere voci di menu nel modulo principale a cui è assegnata la scorciatoia da tastiera desiderata. Quindi tutto il resto viene gestito internamente e tutto ciò che devi fare è implementare l'azione appropriata che viene eseguita nel Clickgestore eventi di quella voce di menu.


1
Il problema è che il modulo principale non utilizza i menu di Windows comuni. Utilizza un pannello di navigazione personalizzato utilizzato per mostrare i moduli figlio. I moduli di ricerca vengono richiamati facendo clic su ToolStripButton nel modulo figlio.
Rockcoder il

menu mnemonicscampione reale?
Kiquenet,


1
I mnemonici sono un concetto distinto dai tasti di scelta rapida e ci sono differenze importanti nel modo in cui funzionano. In breve, i mnemonici sono i caratteri sottolineati usati per accedere ai menu, ai comandi di menu e ai controlli delle finestre di dialogo usando la tastiera. OTOH, i tasti di scelta rapida sono un modo per accedere ai comandi senza passare attraverso i menu e inoltre possono essere tasti arbitrari come Ctrl + F o F5, non limitati ai tasti carattere.
Stewart,

1
@Stewart È corretto! La mia risposta non stava cercando di implicare che tutte le scorciatoie da tastiera sono mnemoniche, semplicemente che il menu mnemonico è il modo più semplice per ottenere questa funzionalità. Sfortunatamente, come chiarisce il commento di Rockcoder, questa soluzione non sembra appropriata qui. Lo consiglio comunque come soluzione preferibile, ove possibile. Per una soluzione generale, la risposta accettata da Hans è la via da seguire.
Konrad Rudolph,

11

Puoi anche provare questo esempio:

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

Se si dispone di un menu, modificare la ShortcutKeysproprietà del ToolStripMenuItemdovrebbe fare il trucco.

In caso contrario, è possibile crearne uno e impostarne la visibleproprietà su false.


No, non ho un menu. ToolStripButton per la ricerca si trova effettivamente sul controllo BindingNavigator, quindi probabilmente aggiungere un menu non è un'opzione.
Rockcoder il

6

Dal modulo principale, devi:

  • Assicurati di impostare KeyPreview su true (TRUE per impostazione predefinita)
  • Aggiungi MainForm_KeyDown (..) - con cui puoi impostare qui le scorciatoie che desideri.

Inoltre, l'ho trovato su Google e volevo condividerlo con coloro che sono ancora alla ricerca di risposte. (per globale)

Penso che devi usare 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
    }
}

Leggi ulteriormente questo http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

La risposta di Hans potrebbe essere resa un po 'più semplice per qualcuno che non conosce questo, quindi ecco la mia versione.

Non è necessario ingannare KeyPreview, lasciarlo impostato su false. Per usare il codice qui sotto, incollalo sotto il tuo form1_loaded eseguilo F5per vederlo funzionare:

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
Innanzitutto, l'override di ProcessCmdKey è il modo consigliato di gestire una sequenza di tasti destinata a eseguire un'operazione simile a un comando, che è ciò di cui l'OP stava chiedendo. Secondo, hai frainteso il commento di Hans sull'impostazione di KeyPreview su true; stava solo dicendo all'OP perché la sua tecnica non funzionava. L'impostazione di KeyPreview su true non è necessaria per l'utilizzo di ProcessCmdKey.
RenniePet,

2

In WinForm, possiamo sempre ottenere lo stato della chiave di controllo:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.