2010-08-25 22 views
26

Continuo a programmare una sorta di navigazione da tastiera nel mio semplice programma grafico (utilizzando C#). E mi sono imbattuto nei guai ancora una volta.Il pannello non si attiva

alt text

Il mio problema è che voglio elaborare l'input da tastiera per spostare un livello intorno. Lo spostamento del livello con il mouse funziona già abbastanza bene, tuttavia il controllo non ottiene il focus (né KeyUp/KeyDown/KeyPress né GotFocus/LostFocus vengono attivati ​​per questo controllo). Poiché la mia classe deriva da Panel (e sovrascrive un paio di eventi), ho anche sovrascritto gli eventi menzionati sopra, ma non riesco a far scattare quegli eventi.

Penso che potrei riuscire a implementare la risposta della tastiera usando qualcosa come Keyboard.GetState() o ProcessCmdWnd o qualcosa del genere. Tuttavia: devo ancora essere in grado di dire quando il controllo ha il focus.

C'è un modo più o meno elegante di aggiungere questa capacità a un controllo utente (basato su Panel)?

Ho controllato molti thread qui e potrei usare this approach per l'input da tastiera. Il problema di messa a fuoco tuttavia rimane ancora.

Grazie mille per le informazioni in anticipo!

Igor.

p.s .: Sto programmando in C# .NET v3.5, utilizzando VS2008. È un'applicazione Windows.Forms, non WPF.

risposta

57

La classe del Pannello è stata progettata come contenitore, evita di focalizzarsi in modo tale che il controllo figlio possa sempre ottenerlo. Avrai bisogno di un intervento chirurgico per risolverlo. Ho buttato nel codice per ottenere combinazioni di tasti cursore in KeyDown così:

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

Incredibile! Funziona davvero ed è stato così facile da implementare. Non conoscevo la classe ControlStyles e quindi non sapevo che avrei potuto cambiarlo. Grazie mille :). – Igor

+0

@HansPassant In quali casi esattamente si dovrebbe usare 'Focus()' piuttosto che 'Select()'? – Medinoc

+0

Una risposta corretta è lunga, utilizzare il pulsante Chiedi domanda per favore. –

6

Lo stesso codice Hans Passant 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()' è il costrutto in C#, dovrebbe essere 'Public Sub New' qui. – KekuSemau

0

chiamata attenzione all'evento di click

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

I pannelli non ottengono la messa a fuoco, è necessario selezionare il pannello se si desidera tenere traccia e inserire eventi

chiama panel1.Select() in MouseClick Evento

0

Per ottenere lo stato attivo, verificare l'evento MouseEnter nella finestra Proprietà.

Scrivi sotto il codice:

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

Il trucco più semplice che uso quando per qualsiasi motivo non riesco a utilizzare la proprietà genitore Modulo KeyPreview per rendere il Modulo di gestire gli eventi chiave, è quello di mettere una casella di testo su

Il pannello:

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

e utilizzarlo per catturare KeyDown evento:

_focusTextBox.KeyDown += panel_KeyDown; 

L'ultimo passo è quello di impostare lo stato attivo a questo TextBox quando altri comandi sul pannello cliccato:

_focusTextBox.Focus(); 
Problemi correlati