面板没有得到焦点

Posted

技术标签:

【中文标题】面板没有得到焦点【英文标题】: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

【问题讨论】:

【参考方案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();

【讨论】:

以上是关于面板没有得到焦点的主要内容,如果未能解决你的问题,请参考以下文章

swing,关于焦点

NSTableView 响应面板中的第一次单击

在sencha touch 2中滚动面板时的文本字段焦点问题

引导面板没有得到扩展

错误的组件(在单独的 JPanel 类中)获得焦点

在加载面板时关注组件