2009-08-19 27 views
24

我正在創建一個小遊戲,遊戲被打印到窗體上的面板上。現在我想捕獲keydown事件來查看它是否被按下的箭頭鍵,但問題是我似乎無法捕獲它。C#試圖捕獲表單上的KeyDown事件

讓我解釋一下,我有4個按鈕和各種其他控件的形式,如果用戶按下其中一個按鈕(觸發遊戲事件),那麼按鈕有焦點,我無法捕捉到運動用箭頭鍵。

我想是這樣

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

,然後按下形式鍵按下事件的時候,我用這個

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

我還添加了的keydown上的按鈕和其他各種控制窗體窗體,但我沒有得到任何迴應。我在函數內部設置了一個斷點來查看它是否被調用,但是該斷點從不觸發?

任何想法?

最理想的是有一個觸發的常規KeyDown事件(不管當前有什麼焦點),然後調用KeyDown方法。

回答

17

覆蓋IsInputKey行爲


您必須重寫IsInputKey行爲以通知您想要右Ar行鍵被當作一個InputKey而不是一個特殊的行爲鍵。 爲此,您必須重寫每個控件的方法。 我會建議你創建你贏了按鈕,讓我們說myButton的

下面的類創建了覆蓋IsInputKey方法使右箭頭鍵沒有作爲一個特殊的鍵處理自定義按鈕。從那裏你可以很容易地爲其他箭頭鍵或其他任何東西。

中的按鈕的KeyDown方法嘗試設置這些屬性:

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

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

之後,您可以在各個不同的按鈕或在窗體本身對待你的keyDown事件事件

- 或 -

處理窗體中的常見行爲:(不要設置e.Handled = true;在按鈕

private void Form1_KeyDown(object sender, KeyEventArgs e) 
{ 
    //DoSomething(); 
} 
+1

這是半工作,現在我得到了keydown事件,但是當我按下按鈕時,他們仍然變得專注,然後它停止工作,除非我按頂部的箭頭鍵,直到它循環通過它們,他們鬆散的焦點。 – Patrick 2009-08-19 10:46:13

+0

你如何捕捉「Keys.Left」和「Keys.Right」KeyDown事件? – 2009-08-19 13:23:27

+0

我編輯了我的答案以引用IsInputKey方法 – 2009-08-19 13:44:22

29

您是否已將表格的KeyPreview屬性設置爲true?這將導致表單在關鍵事件中獲得「第一眼」。

更新:得到這個正常工作時,Button具有焦點似乎是有點棘手。按鈕控件攔截箭頭鍵按下,並按照Tab鍵順序將焦點移至下一個或上一個控件,以便不會引發KeyDown,KeyUpKeyPress事件。然而,PreviewKeyDown事件引發的,所以可以使用:

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

不過,重點在一個比較難看的方式四處移動...

+0

它是半的工作,現在我得到的keydown事件,但是當我按下按鈕,他們還是成爲集中,然後它會停止工作,除非我按頂部的箭頭鍵,直到它循環通過它們,並且它們失去焦點。 – Patrick 2009-08-19 10:03:32

+0

@帕特里克:是的,箭頭鍵和按鈕控件似乎有非常緊密的關係。我已經更新了我的答案,向前邁進了一步。 – 2009-08-19 12:56:58

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

你不知道你的回答節省了我的很多時間。非常感謝。 – 2012-03-12 06:30:42

+0

它應該是'KeyPreview = true;'這使KeyDown觸發 – 2017-02-20 07:11:45

16

我認爲解決這個問題的最簡單的方法就是通過覆蓋表單的給ProcessCmdKey()方法。這樣,無論鍵盤按下什麼控件,焦點處理邏輯都會得到執行。除此之外,您甚至可以選擇是否在處理焦點後控制焦點(返回false)或不是(返回true)。
你的小遊戲例子可以改寫這樣的:

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

這很好,但空間鍵不處理 – Singlet 2011-01-20 12:05:21

+2

偉大的解決方案。捕獲所有按鍵。甚至空間。 – Kibbee 2011-07-08 02:20:44

+0

這是解決這些問題的最簡單方法,也適用於我。 – 2014-01-07 08:36:31