简体   繁体   English

C#专注于表单和箭头键

[英]C# focus in forms and arrow keys

I want to do a map editor for a game. 我想为游戏做一个地图编辑器。 Its a program that will have Windows Forms UI (like propertyGrid to edit object's properties) but it will also have a panel on which map will be drawn. 它是一个具有Windows Forms UI(例如,propertyGrid可以编辑对象的属性)的程序,但是它也具有一个在其上绘制地图的面板。

What i want: 我想要的是:

When focus is on the panel with the map, i'd like to use keyboard to move map around (arrow keys), add objects (number keys) etc. When focus isnt on this panel, i'd like the buttons to work as normal in windows forms - allow to tab between controls etc. 当焦点位于带有地图的面板上时,我想使用键盘来移动地图(箭头键),添加对象(数字键)等。当焦点不在此面板上时,我希望按钮可以用作在Windows窗体中正常-允许在控件之间制表符等

My form looks like this: 我的表格如下所示:

It has a ToolStripControl that has a menuStrip (for main menu) and a statusStrip (for status bar). 它具有一个ToolStripControl,它具有一个menuStrip(用于主菜单)和一个statusStrip(用于状态栏)。 In the middle of the form (or toolstripcontrol), SplitControl is docked (dock=fill) that has two panels. 在表单(或toolstripcontrol)的中间,将SplitControl停靠在其中(具有两个面板)(dock = fill)。 Panel 1 has the PanelMap - a Panel that displays the map, Panel 2 has all other stuff like propertygrid, tabcontrols, buttons etc. 面板1具有PanelMap-一个显示地图的面板,面板2具有所有其他内容,例如propertygrid,tabcontrol,按钮等。

I have KeyPreview of form set to true and process keyboard events in form's keydown event handler. 我将窗体的KeyPreview设置为true,并在窗体的keydown事件处理程序中处理键盘事件。

Now, what happens is if i assign focus to PanelMap, next time i press an arrow key, NO KeyDown event fires. 现在,发生的事情是,如果我将焦点分配给PanelMap,则下次按下箭头键时,将不会触发KeyDown事件。 Not a single one! 没有一个! Even form which is supposed to process all events because it has "KeyPreview" doesnt get its even to fire. 偶数形式应该处理所有事件,因为它具有“ KeyPreview”,它甚至不会触发。 When i press an arrow, PanelMap loses focus towards the SplitControl. 当我按箭头时,PanelMap失去对SplitControl的关注。

Okay, i thought, maybe PanelMap is not supposed to ever have focus, lets give focus to SplitControl (if i press arrow key while it has focus, i can handle it so it doesnt go further). 好的,我想,也许PanelMap不应该具有焦点,让我们将焦点赋予SplitControl(如果我在有焦点的情况下按箭头键,则可以处理它,因此它不会继续前进)。 But then, if anything like a textbox that is inside something that is inside SplitControl has focus, then SplitControl CANNOT get focus. 但是,如果在SplitControl内部的某个文本框之类的东西具有焦点,则SplitControl无法获得焦点。 .Focus() will do nothing - focus remains in the whichever control that had it! .Focus()不会执行任何操作-焦点仍然保留在拥有该控件的控件中!

Why does it act so strange? 为什么行为如此奇怪? Why doesnt Form's KeyDown fire when panel has focus and arrow key is pressed? 当面板具有焦点并按下箭头键时,为什么Form的KeyDown不会触发? Why doesnt SplitControl get focused when i call .Focus() even though CanFocus=true? 为什么即使CanFocus = true,当我调用.Focus()时,SplitControl也不会集中精力?

And ultimately, how do i achieve what i want? 最终,我如何实现自己想要的? Is there a way to do it? 有办法吗?

I think you're running into the widgets taking the keystrokes before your events get to them for navigation. 我认为在事件到达导航之前,您正在碰击小部件进行击键。 I had this issue, and did this: 我遇到了这个问题,并这样做:

    private void RemoveCursorNavigation(Control.ControlCollection controls)
    {
        foreach(Control ctrl in controls)
        {
            ctrl.PreviewKeyDown += new PreviewKeyDownEventHandler(MainWin_PreviewKeyDown);
            RemoveCursorNavigation(ctrl.Controls);
        }
    }

I call this function in the main form's Load handler, like this: 我在主窗体的Load处理程序中调用此函数,如下所示:

RemoveCursorNavigation(this.Controls);

In your PreviewKeyDown handler, you need to do this: 在您的PreviewKeyDown处理程序中,您需要执行以下操作:

    public void MainWin_PreviewKeyDown(Object sender, PreviewKeyDownEventArgs e)
    {
        switch(e.KeyCode)
        {
            case Keys.Up:
            case Keys.Down:
            case Keys.Left:
            case Keys.Right:
                e.IsInputKey = true;
                break;
            default:
                break;
        }
    }

The e.IsInputKey = true; e.IsInputKey = true; tells the outside that you've used this event, and don't want it going anywhere else. 告诉外界您已使用此事件,并且不希望它在其他任何地方使用。

Now you get to see the keystrokes before they go to the widgets, and you won't get navigation between them from the cursor keys. 现在,您可以在击键之前看到它们,并且不会从光标键之间进行导航。

I found an answer like this: 我找到了这样的答案:

I made a textbox that is hidden under a panel (but enabled and visible). 我制作了一个隐藏在面板下的文本框(但已启用且可见)。 This textbox is given focus when i want to "lock" focus on my PanelMap. 当我想“锁定” PanelMap的焦点时,将给该文本框以焦点。 It has onkeydown even with e.suppress = true so that textbox never gets any keystrokes to affect it. 即使使用e.suppress = true,它也具有onkeydown,因此文本框永远不会受到任何击键来影响它。

Crude workaround but works wonders... typical M$ business... 粗略的解决方法,但可以解决问题...典型的M $业务...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM