web-dev-qa-db-fra.com

C # essayant de capturer l'événement KeyDown sur un formulaire

Je crée un petit jeu, le jeu est imprimé sur un panneau sur un formulaire Windows. Maintenant, je veux capturer l'événement keydown pour voir si ce sont les touches fléchées qui ont été enfoncées, le problème est que je n'arrive pas à le capturer.

Permettez-moi de vous expliquer, sur le formulaire, j'ai 4 boutons et divers autres contrôles et si l'utilisateur, par exemple, appuie sur l'un des boutons (pour déclencher un événement de jeu), le bouton a le focus et je ne peux pas capturer les mouvements avec les touches fléchées .

J'ai essayé quelque chose comme

private void KeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Left)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.E);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Right)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.W);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Up)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.N);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Down)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.S);
            game.DrawObjects(panel1.CreateGraphics());
        }
    }

et puis quand l'événement de touche de formulaire a été enfoncé, j'ai utilisé

private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        KeyDown(e);
    }

J'ai également ajouté des touches pour les boutons et les divers autres contrôles du formulaire Windows, mais je ne reçois aucune réponse. J'ai configuré un point d'arrêt à l'intérieur de la fonction pour voir s'il est appelé, mais ce point d'arrêt ne se déclenche jamais?

Des idées?

Le plus optimal était d'avoir un événement KeyDown général qui se déclenche (quel que soit le contrôle qui a actuellement le focus), puis appelle la méthode KeyDown.

25
Patrick

Remplacer IsInputKey comportement


Vous devez remplacer le comportement IsInputKey pour indiquer que vous souhaitez que la touche flèche droite soit traitée comme une clé d'entrée et non comme une clé de comportement spéciale. Pour cela, vous devez remplacer la méthode pour chacun de vos contrôles. Je vous conseille de créer vos boutons gagnés, disons MyButton

La classe ci-dessous crée un bouton personnalisé qui remplace la méthode IsInputKey afin que la touche fléchée droite ne soit pas traitée comme une clé spéciale. De là, vous pouvez facilement le faire pour les autres touches fléchées ou autre chose.

    public partial class MyButton : Button
    {
        protected override bool IsInputKey(Keys keyData)
        {
            if (keyData == Keys.Right)
            {
                return true;
            }
            else
            {
                return base.IsInputKey(keyData);
            }
        }
    }

Ensuite, vous pouvez traiter votre événement d'événement keyDown dans chaque bouton différent ou dans le formulaire lui-même:

Dans la méthode KeyDown des boutons, essayez de définir ces propriétés:

private void myButton1_KeyDown(object sender, KeyEventArgs e)
{
  e.Handled = true;
  //DoSomething();
}

- OR -

gérer le comportement courant sous la forme: (ne pas définir e.Handled = true; dans les boutons)

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    //DoSomething();
}
17
Luis Filipe

Avez-vous défini la propriété KeyPreview du formulaire sur true? Cela permettra au formulaire d'obtenir un "premier aperçu" des événements clés.

Mise à jour: pour que cela fonctionne correctement quand un Button a le focus semble être un peu délicat. Le contrôle Button intercepte les touches fléchées et déplace le focus vers le contrôle suivant ou précédent dans l'ordre de tabulation de manière à ce que les événements KeyDown, KeyUp et KeyPress ne soient pas élevé. Cependant, l'événement PreviewKeyDown est déclenché, ce qui peut être utilisé:

private void Form_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = ProcessKeyDown(e.KeyCode);
}

// event handler for the PreViewKeyDown event for the buttons
private void ArrowButton_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    ProcessKeyDown(e.KeyCode);

}

private bool ProcessKeyDown(Keys keyCode)
{
    switch (keyCode)
    {
        case Keys.Up:
            {
                // act on up arrow
                return true;
            }
        case Keys.Down:
            {
                // act on down arrow
                return true;
            }
        case Keys.Left:
            {
                // act on left arrow
                return true;
            }
        case Keys.Right:
            {
                // act on right arrow
                return true;
            }
    }
    return false;
}

Pourtant, la mise au point se déplace d'une manière plutôt laide ...

29
Fredrik Mörk

Je crois que la façon la plus simple de résoudre ce problème est de remplacer la méthode ProcessCmdKey () du formulaire. De cette façon, votre logique de manipulation des clés est exécutée, quel que soit le contrôle mis au point au moment de la pression de touche. À côté de cela, vous pouvez même choisir si le contrôle focalisé obtient la clé après l'avoir traitée (retour faux) ou non (retour vrai).
Votre petit exemple de jeu pourrait être réécrit comme ceci:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Left)
    {
        MoveLeft(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Right)
    {
        MoveRight(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Up)
    {
        MoveUp(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Down)
    {
        MoveDown(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else
        return base.ProcessCmdKey(ref msg, keyData);
}
17
RudolfW
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        KeyPreview = true;
        KeyDown += new KeyEventHandler(Form1_KeyDown);
    }

    void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        System.Diagnostics.Debug.Write(e.KeyCode);
    }
}
7
dnkira