martedì 1 novembre 2011

[VB.NET] Gestire Comandi Tastiera su Controlli

Descrizione :
Una tecnica per intercettare e gestire a livello di Control i comandi da tastiera.

+ Articolo :

Nell'esempio seguente definisco una Classe MioPanel che eredita da Panel, e che permette la gestione di comandi da tastiera, senza alcun uso del mouse, e soprattutto senza alcun bisogno di aggiungere e gestire eventi dall'esterno, ossia dalla FormMain Parent.

Per rendere l'articolo più significativo gestisco in particolare i 4 Tasti Arrows, che normalmente sono di selezione / spostamento tra controlli, e che quindi, senza un'opportuna implementazione degli Override di OnPreviewKeyDown e OnKeyDown, verrebbero ignorati a livello di Control.
Vanno gestiti entrambi, perchè OnPreviewKeyDown serve solo a definire quali tasti sono da considerare "di Input" per il controllo, anzichè di Selezione e lo si fa con e.IsInputKey.
Mentre sotto OnKeyDown va la logica per gestire ogni particolare tasto...

Le logiche di gestione tasti e spostamento sono incapsulate nella Classe "MioPanel", e non gestite dall'esterno ( dal codice Form... ).
Settare KeyPreview = True sulla Form che ospita i Panel non serve, perciò su FormMain, KeyPreview = False.

--> La Classe MioPanel :

Public Class MioPanel
    Inherits Panel

    Private m_selected As Boolean
    Private m_selectedcolor As Color = Color.Red
    Private m_defaultcolor As Color = Color.White
    Private m_movestep As Integer = 10

    Public Property Selected As Boolean
        Get
            Return m_selected
        End Get
        Set(ByVal value As Boolean)
            m_selected = value
            If m_selected = True Then
                Me.BackColor = m_selectedcolor
                For Each C As Control In Me.Parent.Controls
                    If TypeOf (C) Is MioPanel And Not C Is Me Then DirectCast(C, MioPanel).Selected = False
                Next
                Me.Select()
            Else
                Me.BackColor = m_defaultcolor
            End If
        End Set
    End Property

    Public Property SelectedColor As Color
        Get
            Return m_selectedcolor
        End Get
        Set(ByVal value As Color)
            m_selectedcolor = value
        End Set
    End Property

    Public Property DefaultColor As Color
        Get
            Return m_defaultcolor
        End Get
        Set(ByVal value As Color)
            m_defaultcolor = value
        End Set
    End Property

    Public Property MoveStep As Integer
        Get
            Return m_movestep
        End Get
        Set(ByVal value As Integer)
            m_movestep = value
        End Set
    End Property

    Public Sub New()

        Me.BackColor = m_defaultcolor

    End Sub

    Protected Overrides Sub OnMouseClick(ByVal e As System.Windows.Forms.MouseEventArgs)

        If e.Button = MouseButtons.Left Then Me.Selected = True

    End Sub

    Protected Overrides Sub OnPreviewKeyDown(ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs)

        Select Case e.KeyCode

            Case Keys.Up, Keys.Down, Keys.Right, Keys.Left
                'Tasti Arrows = spostamento da tastiera
                e.IsInputKey = True

            Case Keys.Tab
                'Tasto TAB = passaggio al prossimo controllo di tipo MioPanel
                e.IsInputKey = True

            Case Else
                e.IsInputKey = False

        End Select

    End Sub

    Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)

        Select Case e.KeyCode

            Case Keys.Up
                Me.Top -= m_movestep

            Case Keys.Down
                Me.Top += m_movestep

            Case Keys.Right
                Me.Left += m_movestep

            Case Keys.Left
                Me.Left -= m_movestep

            Case Keys.Tab
                Dim j As Integer
                Dim c As Integer = Me.Parent.Controls.Count - 1
                For i As Integer = 0 To c
                    If Me.Parent.Controls(i) Is Me Then
                        j = i + 1
                        Do
                            If j > c Then j = 0
                            Try
                                DirectCast(Me.Parent.Controls(j), MioPanel).Selected = True
                                Exit For
                            Catch ex As Exception
                                j += 1
                            End Try
                        Loop Until j = i
                    End If
                Next

            Case Else
                '...

        End Select

    End Sub

End Class

Il codice, apparentemente "complicato", per gestire il tasto TAB, è giustificato dal fatto che la selezione manuale ( Click sinistro del mouse oppure tastiera con TAB ), e la selezione da codice, vengono centralizzate in un solo Metodo di Propery-Set : la Property Selected.
Inoltre è possibile avere anche altri controlli su FormMain : in questo caso tutti i controlli che non sono Oggetti della Classe MioPanel verranno ignorati : la pressione di TAB su un "MioPanel" correntemente selezionato avrà come effetto la selezione del "MioPanel" successivo, con una logica ciclica.
Per queste ragioni non ce la si può fare con un semplice Me.Parent.SelectNextControl ...

--> FormMain :
Su FormMain ho un Button "cmd_aggiungi", che serve allo scopo di creare alcuni Oggetti "MioPanel" a runtime, e inoltre a verificare la logica di selezione ciclica ogni volta che si fa TAB su un "MioPanel" attivo.
Public Class FormMain

    Private Sub cmd_aggiungi_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_aggiungi.Click

        Dim mp1 As New MioPanel
        Me.Controls.Add(mp1)
        mp1.SelectedColor = Color.Red
        mp1.Location = New Point(0, 100)
        mp1.Size = New Size(50, 50)

        Dim mp2 As New MioPanel
        Me.Controls.Add(mp2)
        mp2.SelectedColor = Color.Gold
        mp2.Location = New Point(100, 100)
        mp2.Size = New Size(50, 50)

        Dim mp3 As New MioPanel
        Me.Controls.Add(mp3)
        mp3.SelectedColor = Color.Green
        mp3.Location = New Point(200, 100)
        mp3.Size = New Size(50, 50)
        mp3.Selected = True

    End Sub

End Class

Perciò riassumendo il tutto :

--> Avvio il Progetto, e poi senza toccare il mouse, premo Invio, che comporta un Click sul Button cmd_aggiungi.
--> Vengono creati 3 Oggetti della Classe MioPanel, e viene selezionato il terzo.
--> Con i tasti Arrows sposto il "MioPanel" attivo.
--> Con il tasto TAB seleziono ciclicamente tutti i "MioPanel" presenti, ignorando eventuali altri controlli.

+ Fine Articolo.

Un Click su "Mi Piace" è il modo migliore per ringraziare l'autore di questo articolo.



0 commenti:

Posta un commento

 
Design by Free WordPress Themes Modificato da MarcoGG