StatusBarPanel派生クラスです。本クラスはキーステートの変化を感知するだけです。表示はフォーム側でオーナードローを使って行います。
@ "Application_Idol_Ex"関数でキーが押されたことを感知。
A "GetKeyState"関数(Win32API)でキーの状態を取得。
B 取得したキーの状態を"VKState"プロパティに格納。
C "VKStateChange"イベントで変更があったことをフォームに通知。
D フォームは"VKState"プロパティの値に基づいてパネルに描画。
列挙体"VKType"はキーの状態を格納するためのものです。複数の項目を同時に選択できるよう、Flags属性をつけて、ビット演算ができるようにしています。これはクラシックなスタイル。これ以外にも、"BitArray"クラスや"BitVector32"構造体を使う手もあります。
キーの状態は、Win32APIの"GetKeyState"関数でキーごとに取得します。その引数として、"VK_CAPITAL"以下の定数が必要になります。キーが無効なら"0"、有効なら"1"を返してきます。
Public Class VKStatePane
Inherits StatusBarPanel
' 変数
Private m_state As VKFlags ' キーの状態(プロパティ用)
Private m_current As VKFlags ' キーの状態(現状取得用)
' イベント
Public Event VKStateChanged( _
ByVal pane As VKStatePane, _
ByVal e As EventArgs)
' Win32API : 定数
Private Const VK_CAPITAL As Integer = &H14
Private Const VK_KANA As Integer = &H15
Private Const VK_INSERT As Integer = &H2D
Private Const VK_NUMLOCK As Integer = &H90
Private Const VK_SCROLL As Integer = &H91
' 列挙体 : VKType
<Flags()> Public Enum VKFlags
None = 0
VKCapital = 1
VKKana = 2
VKInsert = 4
VKNumlock = 8
VKScroll = 16
VKAll = _
VKCapital Or VKKana Or VKInsert Or VKNumlock Or VKScroll
End Enum
' Win32API : GetKeyState
Private Declare Function GetKeyState Lib "user32" _
(ByVal vk As Integer) As Short
' プロパティ : VKState
Public Property VKState() As VKFlags
Get
Return m_state
End Get
Set(ByVal Value As VKFlags)
m_state = Value
End Set
End Property
' New : コンストラクタ
Public Sub New(ByVal width As Integer)
MyBase.New()
Me.Width = width
Me.Alignment = HorizontalAlignment.Left
' Idleイベントハンドラの追加
AddHandler Application.Idle, AddressOf Application_Idle_Ex
End Sub
' Application_Idle : アプリケーションがアイドル状態の時
Private Sub Application_Idle_Ex( _
ByVal sender As Object, _
ByVal e As EventArgs)
' キーの状態を監視
m_current = VKFlags.None
If GetKeyState(VK_CAPITAL) <> 0 Then
m_current = m_current Or VKFlags.VKCapital
End If
If GetKeyState(VK_KANA) <> 0 Then
m_current = m_current Or VKFlags.VKKana
End If
If GetKeyState(VK_INSERT) <> 0 Then
m_current = m_current Or VKFlags.VKInsert
End If
If GetKeyState(VK_NUMLOCK) <> 0 Then
m_current = m_current Or VKFlags.VKNumlock
End If
If GetKeyState(VK_SCROLL) <> 0 Then
m_current = m_current Or VKFlags.VKScroll
End If
If (m_state Xor m_current) <> VKFlags.None Then
m_state = m_current
RaiseEvent VKStateChanged(Me, Nothing)
End If
End Sub
End Class
コンストラクタでステータスバーパネルの幅を引数にしていますが、これは余計かもしれません。フォーム側で直接指定した方がすっきりするような気がします。
"KeyStateCanged"イベントを感知したら、"Refresh"メソッドを使って、ステータスバー"SB1"に描画をするよう命令をします。これによってステータスバーの"DrawItem"イベントが発生します。
' ステータスバーパネル : キーステートの変更イベント
Private Sub KeyStateChanged(ByVal pane As VKStatePane, ByVal e As EventArgs)
SB1.Refresh() '再描画
End Sub
"sbdEvent.Panel"でどのパネルに描画するかを指定する必要があります。
また、文字列の描画位置を直接数字で指定しています。手抜きです。面倒くさがらずに定数として宣言するべきでしょう。
' ステータスパネル : 描画イベント
Private Sub SB1_DrawItem( _
ByVal sender As Object, _
ByVal sbdevent As StatusBarDrawItemEventArgs) _
Handles SB1.DrawItem
Dim f As Font = New Font("MS UI Gothic", 9) ' 描画フォントの指定
' ファイル名の描画
If sbdevent.Panel Is Me.sbPath Then
sbdevent.Graphics.DrawString( _
sbdevent.Panel.Text, _
f, _
Brushes.Black, _
2, _
2)
sbdevent.Graphics.Dispose()
End If
' キーステートの描画
If sbdevent.Panel Is m_vkpane Then
Dim status As VKStatePane.VKFlags = _
DirectCast(sbdevent.Panel, VKStatePane).VKState
Dim r As Rectangle = sbdevent.Bounds ' 描画対象四角形
Dim x As Integer = r.Left + 2 ' 描画位置X
Dim y As Integer = r.Top + 3 ' 描画位置Y
Dim brDark As Brush = SystemBrushes.WindowText '有効時の文字色
Dim brLight As Brush = SystemBrushes.ControlDark ' 無効時の文字色
With sbdevent.Graphics
If (status And VKStatePane.VKFlags.VKInsert) = _
VKStatePane.VKFlags.VKInsert Then
.DrawString("上書", f, brDark, x, y)
Else
.DrawString("挿入", f, brDark, x, y)
End If
If (status And VKStatePane.VKFlags.VKNumlock) = _
VKStatePane.VKFlags.VKNumlock Then
.DrawString("Num", f, brDark, x + 32, y)
Else
.DrawString("Num", f, brLight, x + 32, y)
End If
If (status And VKStatePane.VKFlags.VKCapital) = _
VKStatePane.VKFlags.VKCapital Then
.DrawString("Caps", f, brDark, x + 60, y)
Else
.DrawString("Caps", f, brLight, x + 60, y)
End If
If (status And VKStatePane.VKFlags.VKScroll) = _
VKStatePane.VKFlags.VKScroll Then
.DrawString("Scrl", f, brDark, x + 90, y)
Else
.DrawString("Scrl", f, brLight, x + 90, y)
End If
.Dispose()
End With
End If
f.Dispose()
End Sub
ビット処理のところは、なれないうちはややこしいですよね。
states and VKStatePanel.VKFlags.VKInsert
で、VKInsertの箇所だけの値を取り出すことができます。したがって、この値が VKInsert と同じ 4 なら有効、それ以外なら無効であると判断できるわけです。
"Windowsフォームデザイナで生成されたコード"内のNewコンストラクタに、ステータスバーパネルを追加するコードを付け足します。これでキーステート関係のコーディングは終了です。
' New : コンストラクタ
Public Sub New()
MyBase.New()
' この呼び出しは Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後に初期化を追加します。
m_vkpane = New VKStatePane(128)
m_vkpane.Style = StatusBarPanelStyle.OwnerDraw
AddHandler m_vkpane.VKStateChanged, AddressOf KeyStateChanged
SB1.Panels.Add(m_vkpane)
End Sub