【问题标题】:Panel not getting focus面板没有得到焦点
【发布时间】:2011-04-03 11:56:46
【问题描述】:

我将继续在我的简单图形程序(使用 C#)中编写某种键盘导航。我又遇到了麻烦。

我的问题是我想处理键盘输入以移动图层。用鼠标移动图层已经很有效了,但是控件没有获得焦点(KeyUp/KeyDown/KeyPress 和 GotFocus/LostFocus 都没有被触发)。 由于我的类派生自 Panel(并覆盖了几个事件),我也覆盖了上面提到的事件,但我无法成功触发这些事件。

我想我可以使用 Keyboard.GetState() 或 ProcessCmdWnd 之类的东西来实现键盘响应。但是:我仍然必须能够判断控件何时获得焦点。

是否有一种或多或少优雅的方式将此功能添加到用户控件(基于 Panel)?

我在这里检查了很多线程,我可能会使用this approach 进行键盘输入。然而,焦点问题仍然存在。

非常感谢您提前提供信息!

伊戈尔。

p.s.:我正在使用 VS2008 在 C# .NET v3.5 中编程。这是一个 Windows.Forms 应用程序,不是 WPF

【问题讨论】:

    标签: c# winforms keyboard focus panel


    【解决方案1】:

    Panel 类被设计为容器,它避免获取焦点,因此子控件将始终获取它。你需要做一些手术来解决这个问题。我在 KeyDown 事件中也加入了代码以获取光标击键:

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    class SelectablePanel : Panel {
        public SelectablePanel() {
            this.SetStyle(ControlStyles.Selectable, true);
            this.TabStop = true;
        }
        protected override void OnMouseDown(MouseEventArgs e) {
            this.Focus();
            base.OnMouseDown(e);
        }
        protected override bool IsInputKey(Keys keyData) {
            if (keyData == Keys.Up || keyData == Keys.Down) return true;
            if (keyData == Keys.Left || keyData == Keys.Right) return true;
            return base.IsInputKey(keyData);
        }
        protected override void OnEnter(EventArgs e) {
            this.Invalidate();
            base.OnEnter(e);
        }
        protected override void OnLeave(EventArgs e) {
            this.Invalidate();
            base.OnLeave(e);
        }
        protected override void OnPaint(PaintEventArgs pe) {
            base.OnPaint(pe);
            if (this.Focused) {
                var rc = this.ClientRectangle;
                rc.Inflate(-2, -2);
                ControlPaint.DrawFocusRectangle(pe.Graphics, rc);
            }
        }
    }
    

    【讨论】:

    • 太棒了!它真的很有效,而且很容易实现。我不知道 ControlStyles 类,因此不知道我可以更改它。非常感谢:)。
    • @HansPassant 在哪些情况下应该使用Focus() 而不是Select()
    • 正确答案很长,请使用按钮。
    • @HansPassant 在我看来, OnEnter 和 OnLeave 没有被可靠地调用。这意味着可能会省略失效。我是否犯了一些明显的错误,或者这是一个已知的限制?
    • 当我scroll the contents by changing the scrollbar values时,focusrectangle 绘图会到处留下刷新错误。
    【解决方案2】:

    Hans Passant 的代码翻译成 VB.NET

    Imports System
    Imports System.Drawing
    Imports System.Windows.Forms
    
    Public Class SelectablePanel
        Inherits Panel
    
        Public Sub New()
            Me.SetStyle(ControlStyles.Selectable, True)
            Me.TabStop = True
        End Sub
        
        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            Me.Focus()
            MyBase.OnMouseDown(e)
        End Sub
    
        Protected Overrides Function IsInputKey(ByVal keydata As Keys) As Boolean
            If (keydata = Keys.Up OrElse keydata = Keys.Down) Then Return True
            If (keydata = Keys.Left OrElse keydata = Keys.Right) Then Return True
            Return MyBase.IsInputKey(keydata)
        End Function
    
        Protected Overrides Sub OnEnter(ByVal e As EventArgs)
            Me.Invalidate()
            MyBase.OnEnter(e)
        End Sub
    
        Protected Overrides Sub OnLeave(ByVal e As EventArgs)
            Me.Invalidate()
            MyBase.OnLeave(e)
        End Sub
    
        Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
            MyBase.OnPaint(pe)
            If (Me.Focused) Then
                Dim rc As Rectangle = Me.ClientRectangle
                rc.Inflate(-2, -2)
                ControlPaint.DrawFocusRectangle(pe.Graphics, rc)
            End If
        End Sub
    
    End Class
    

    【讨论】:

    • SelectablePanel()是C#中的构造器,这里应该是Public Sub New
    【解决方案3】:

    在点击事件中调用焦点

    private void Panel_Click(object sender, EventArgs e)
        {
            Panel.Focus();
        }
    

    【讨论】:

      【解决方案4】:

      面板没有获得焦点,如果你想跟踪离开和输入事件,你必须选择面板

      MouseClick 事件中调用panel1.Select()

      【讨论】:

        【解决方案5】:

        要获得焦点,请检查属性窗口中的 MouseEnter 事件。

        编写以下代码:

        private void mainPanel_MouseEnter(object sender, EventArgs e)
        {
            mainPanel.Focus();
        }
        

        【讨论】:

          【解决方案6】:

          当出于某种原因我不能使用父表单的 KeyPreview 属性来使表单处理关键事件时,我使用的最简单的技巧是在上面放置一个文本框

          面板:

          Panel.Controls.Add(_focusTextBox = new TextBox() { Visible = true , Left = -300, TabIndex = 0});   
          

          并用它来捕捉 KeyDown 事件:

          _focusTextBox.KeyDown += panel_KeyDown;
          

          最后一步是当面板上的其他控件点击时,将焦点设置到这个TextBox:

          _focusTextBox.Focus();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-11-07
            • 2011-03-10
            • 1970-01-01
            相关资源
            最近更新 更多