Windowsアプリケーションでは、[Tab]キーだけでなく[Enter]キーによるコントロール間のフォーカス移動処理を要求されることがよくある。一般ユーザーにとっては、普段あまり使わない[Tab]キーよりも[Enter]キーの方が押しやすく、利便性が向上するからである。
本稿では、このような[Enter]キーでフォーカス移動する処理の実装方法を紹介する。
[Enter]キーによるコントロール間のフォーカス移動
といってもその実装は難しくはない。フォーム上の各コントロールについてKeyDownイベント・ハンドラを追加し、そのイベント・ハンドラ内で[Enter]キーが押されたときの処理として、次のいずれかのメソッドを呼び出せばよい。これらのメソッドはいずれも、別のコントロールにフォーカスを移動させるためのものだ。
- フォームのProcessTabKeyメソッド
- フォームのSelectNextControlメソッド
この2つのメソッドでは、ProcessTabKeyメソッドの方が呼び出しが単純で簡単だが、オプションとして指定できる機能(Bool値のパラメータにより指定)は、前方向に移動するか(True)/後方向に移動するか(False)、しかない。それに比べてSelectNextControlメソッドの方はかなり細かくフォーカス移動処理を制御できる。例えば、TabStopプロパティがFalseに設定されているコントロールへの移動や、入れ子になったコントロールには移動させないといった制御が可能だ(詳しくは、MSDNライブラリの「SelectNextControlメソッド」を参照してほしい)。
フォーカス移動の方向については、通常ならば[Enter]キーを押すと前方向にフォーカスが進む。これに加えて、[Enter]キーが押されると同時に[Shift]キーが押されている場合(つまり[Shift]+[Enter]キーの場合)に逆方向(後方向)へフォーカス移動させたいなら、次のコードのように条件判定したうえでフォーカス移動の方向を決定すればよい。
// C#
bool forward = e.Modifiers != Keys.Shift;
' VB.NET
Dim forward As Boolean = e.Modifiers <> Keys.Shift
上記コードの「e」はKeyDownイベント・ハンドラのパラメータで渡されるKeyEventArgsオブジェクト(System.Windows.Forms名前空間)である。KeyEventArgsオブジェクトのModifiersプロパティでは、同時に押し下げられている修飾子キー([Ctrl]キー、[Shift]キー、[Alt]キー)を取得できる。つまり上記のコードでは、Keys列挙体(System.Windows.Forms名前空間)の値「Shift」を使って、[Shift]キーが押されていないかを確認している。[Shift]キーが押されていなければ前方向へのフォーカス移動フラグ「forward」がTrueとなり、押されていればFalseとなる。この値をProcessTabKeyメソッドやSelectNextControlメソッドのパラメータに指定すれば、前方向へフォーカス移動するか、後方向に移動するかを、[Shift]キーの押し下げ状況に合わせて変更できる。
[Enter]キーの一括処理
コントロールごとにKeyDownイベント・ハンドラを追加して上記の処理を実装すれば、[Enter]キー押し下げるとコントロール間をフォーカス移動するようになる。しかし、それではコントロールを追加・削除するたびに同様の処理を実装しなければならない。そこで「TIPS:コントロールに対するキー入力をフォームで処理するには?」で紹介した方法を使って、フォームのKeyDownイベント・ハンドラで[Enter]キーの一括処理を行うようにしよう。これにより、コントロールの追加・削除で発生する作業が不要となる。
以下のコードは、実際にフォームのKeyDownイベント・ハンドラで、[Enter]キー押し下げるとコントロール間のフォーカス移動を行う処理を実装したものだ。なお、「TIPS:コントロールに対するキー入力をフォームで処理するには?」で解説しているように、事前にフォームのKeyPreviewプロパティをTrueに設定しておく必要がある。
private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
bool forward = e.Modifiers != Keys.Shift;
//this.ProcessTabKey(forward);
this.SelectNextControl(this.ActiveControl, forward, true, true, true);
e.Handled = true;
}
}
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = Keys.Enter Then
Dim forward As Boolean = e.Modifiers <> Keys.Shift
'Me.ProcessTabKey(forward);
Me.SelectNextControl(Me.ActiveControl, forward, True, True, True)
e.Handled = True
End If
End Sub
上記コードにあるKeyEventArgsオブジェクト「e」のHandledプロパティは、イベントを処理したかどうかを設定するためのものだ。このコード例では、[Enter]キーのイベントを処理済みとして、HandledプロパティにTrueを設定している。これにより、コントロール側のKeyDownイベント・ハンドラは呼び出されなくなる(HandledプロパティはデフォルトでFalseのため、通常は親フォームのKeyDownイベント・ハンドラが呼び出されたあと、子コントロールのKeyDownイベント・ハンドラが呼び出される)。SelectNextControlメソッドのパラメータで指定している、フォームのActiveControlプロパティは、現在アクティブな(フォーム上の)コントロールを取得するためのものである。
[Enter]キーによるフォーカス移動処理のスキップ
コントロールがデフォルト機能として[Enter]キーを処理する場合、そのコントロールでは[Enter]キーによるフォーカス移動はさせたくないだろう。例えば、複数行の入力が可能なTextBoxコントロールならば[Enter]キーで改行処理が行われるので、[Enter]キーによるフォーカス移動はさせたくない。このような場合、フォーカス移動させたくないコントロールをそのクラスの種類(型)により判別し、フォーカス移動の処理から外すようにすればよいだろう。次にその記述例を示す。
private void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
bool bThrough = false;
if (this.ActiveControl is TextBox)
{
if (((TextBox)this.ActiveControl).Multiline == true)
{
bThrough = true;
}
}
if (bThrough == false)
{
bool forward = e.Modifiers != Keys.Shift;
//this.ProcessTabKey(forward);
this.SelectNextControl(this.ActiveControl, forward, true, true, true);
}
}
}
Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If e.KeyCode = Keys.Enter Then
Dim bThrough As Boolean = False
If TypeOf Me.ActiveControl Is TextBox Then
If (CType(Me.ActiveControl,TextBox)).Multiline = True Then
bThrough = True
End If
End If
If bThrough = False Then
Dim forward As Boolean = e.Modifiers <> Keys.Shift
'this.ProcessTabKey(forward);
Me.SelectNextControl(Me.ActiveControl, forward, True, True, True)
End If
End If
End Sub
コントロールの種類(型)を判別するには、is演算子(C#)/TypeOf…Is式(VB.NET)を使えばよい。上記コードでは、キー処理中のコントロール(=アクティブなコントロール)がTextBoxコントロールであるかを判別し、それがTextBoxコントロールの場合には、そのMultiLineプロパティがTrueかどうか(つまり、TextBoxコントロールが複数行対応であるかどうか)を確認している。MultiLineプロパティがTrueの場合(つまり複数行対応の場合)には[Enter]キーによるフォーカス移動は行われない。
ちなみに、Buttonコントロールも[Enter]キーによるフォーカス移動が必要でない場合が多いが、Buttonコントロールの場合は(デフォルト設定のままでは)[Enter]キーによるKeyDownイベントが発生しないようである。そのため、Buttonコントロールについては[Enter]キーによるフォーカス移動処理をスキップするためのコードは不要だ。
カテゴリ:Windowsフォーム 処理対象:キーボード
使用ライブラリ:KeyEventArgsオブジェクト(System.Windows.Forms名前空間)
使用ライブラリ:Keys列挙体(System.Windows.Forms名前空間)
関連TIPS:コントロールに対するキー入力をフォームで処理するには?
Copyright© Digital Advantage Corp. All Rights Reserved.