2010-08-25 7 views
26

Ich fahre fort, eine Art Tastaturnavigation in meinem einfachen Grafikprogramm (mit C#) zu programmieren. Und ich geriet erneut in Schwierigkeiten.Panel nicht Fokus bekommen

alt text

Mein Problem ist, dass ich die Tastatureingabe verarbeiten will um eine Schicht zu bewegen. Das Verschieben der Ebene mit der Maus funktioniert bereits ganz gut, aber das Steuerelement erhält den Fokus nicht (weder KeyUp/KeyDown/KeyPress noch GotFocus/LostFocus wird für dieses Steuerelement ausgelöst). Da meine Klasse von Panel abgeleitet ist (und ein paar Ereignisse überschreibt), habe ich auch die oben erwähnten Ereignisse überschrieben, aber ich kann diese Ereignisse nicht auslösen.

Ich denke, ich könnte es schaffen, Tastaturantwort entweder mit etwas wie Keyboard.GetState() oder ProcessCmdWnd oder etwas zu implementieren. Allerdings: Ich muss noch sagen können, wann die Kontrolle den Fokus hat.

Gibt es eine mehr oder weniger elegante Möglichkeit, diese Fähigkeit einem Benutzersteuerelement hinzuzufügen (das auf Panel basiert)?

Ich habe viele Themen hier überprüft und ich könnte this approach für Tastatureingabe verwenden. Das Fokusproblem bleibt jedoch bestehen.

Vielen Dank für Informationen im Voraus!

Igor.

ps. .: Ich programmiere in C# .NET v3.5, mit VS2008. Es ist eine Windows.Forms-Anwendung, nicht WPF.

Antwort

57

Die Panel-Klasse wurde als Container entworfen, es vermeidet, den Fokus zu nehmen, so dass eine Kindersteuerung es immer bekommt. Sie benötigen eine Operation, um das zu beheben. Ich warf in dem Code Cursor Tastenanschläge in dem Ereignisse KeyDown zu erhalten, wie gut:

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

Amazing! Es funktioniert wirklich und es war so einfach zu implementieren. Ich kannte die ControlStyles-Klasse nicht und wusste daher nicht, dass ich das ändern konnte. Vielen Dank :). – Igor

+0

@HansPassant In welchen Fällen sollte man 'Focus()' statt 'Select()' genau benutzen? – Medinoc

+0

Eine richtige Antwort ist eine lange, verwenden Sie bitte die Schaltfläche Frage stellen. –

6

Der gleiche Hans Passant Code in VB.NET

Imports System 
Imports System.Drawing 
Imports System.Windows.Forms 

Public Class SelectablePanel 
    Inherits Panel 

    Public Sub SelectablePanel() 
     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 
+5

'SelectablePanel()' ist der Konstruktor in C#, hier sollte 'Public Sub New' stehen. – KekuSemau

0

Aufruf Fokus in Click-Ereignisse

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

Die Panels werden nicht fokussiert, Sie müssen das Panel auswählen, wenn Sie die Abwesenheitsnotiz verfolgen und Ereignisse eingeben möchten

Anruf panel1.Select() in MouseClick Ereignis

0

Um den Fokus zu erhalten, überprüfen Sie im Eigenschaftenfenster das MouseEnter-Ereignis.

schreiben unten Code:

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

Der einfachste Trick, den ich verwenden, wenn aus irgendeinem Grund, den ich nicht das übergeordnete Formular KeyPreview Eigenschaft verwenden, kann das Formular behandeln wichtige Ereignisse zu machen, eine Textbox auf

zu setzen ist

Das Panel:

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

Und es verwenden KeyDown Ereignis zu erfassen:

_focusTextBox.KeyDown += panel_KeyDown; 

Der letzte Schritt ist Fokus auf diese TextBox zu setzen, wenn andere Steuerelemente auf dem Panel angeklickt:

_focusTextBox.Focus();