面板没有得到焦点
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();
【讨论】:
以上是关于面板没有得到焦点的主要内容,如果未能解决你的问题,请参考以下文章