フォームがアクティブの時にTabキーを押すことによって、次のコントロールにフォーカスを移動させる(次のコントロールをアクティブにする、選択する)ことができます。ここでは、これを同じことをEnterキーが押された時にも行われるようにする方法を紹介します。
Enterキーが押されたかどうか知る方法は、「コントロールで矢印、Tab、Enter、Escキーが押されたことを知る」で説明しています。この内、ここではForm.ProcessDialogKeyメソッドをオーバーライドする方法を使用することにします。(KeyDownイベントを使用する方法については、後述します。)
また次のコントロールにフォーカスを移動させる方法は、「次のタブオーダーのコントロールをアクティブに(選択、フォーカスを移動)する」で説明しています。ここでは、Form.ProcessTabKeyメソッドを使用することにします。(他の方法については、後述します。)
以下に例を示します。この例では、CtrlキーかAltキーが押されている時は本来の動作をさせていますので、複数行TextBoxで改行したい場合は、Ctrlキーを押しながらEnterキーを押すことで対処できます。このコードはフォームのクラス内に記述してください。
'Imports System.Windows.Forms <System.Security.Permissions.UIPermission( _ System.Security.Permissions.SecurityAction.Demand, _ Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _ Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean 'Returnキーが押されているか調べる 'AltかCtrlキーが押されている時は、本来の動作をさせる If ((keyData And Keys.KeyCode) = Keys.Return) AndAlso _ ((keyData And (Keys.Alt Or Keys.Control)) = Keys.None) Then 'Tabキーを押した時と同じ動作をさせる 'Shiftキーが押されている時は、逆順にする Me.ProcessTabKey((keyData And Keys.Shift) <> Keys.Shift) '本来の処理はさせない Return True End If Return MyBase.ProcessDialogKey(keyData) End Function
//using System.Windows.Forms; [System.Security.Permissions.UIPermission( System.Security.Permissions.SecurityAction.Demand, Window = System.Security.Permissions.UIPermissionWindow.AllWindows)] protected override bool ProcessDialogKey(Keys keyData) { //Returnキーが押されているか調べる //AltかCtrlキーが押されている時は、本来の動作をさせる if (((keyData & Keys.KeyCode) == Keys.Return) && ((keyData & (Keys.Alt | Keys.Control)) == Keys.None)) { //Tabキーを押した時と同じ動作をさせる //Shiftキーが押されている時は、逆順にする this.ProcessTabKey((keyData & Keys.Shift) != Keys.Shift); //本来の処理はさせない return true; } return base.ProcessDialogKey(keyData); }
上記の例ではForm.ProcessTabKeyメソッドを使用してTabキーを押した時と同じ動作をさせています。この部分は、「次のタブオーダーのコントロールをアクティブに(選択、フォーカスを移動)する」にある別の方法を使用することもできます。
SendKeys.Sendメソッドを使用する方法の場合、上記のProcessTabKeyメソッドを使用している部分は、以下のようになります。
'Tabキーを押した時の動作をさせる
SendKeys.Send("{TAB}")
//Tabキーを押した時の動作をさせる
SendKeys.Send("{TAB}");
補足:Shiftキーが押されている時は「SendKeys.Send("+{TAB}")」を呼び出すというふうにしてしまうと、Shiftキーを押したままEnterキーを複数押した時、はじめの1回しか逆順にフォーカスが移動しなくなってしまいます。
また、Control.SelectNextControlメソッドを使用する方法の場合は、次のようになります。
'次のタブオーダーのコントロールにフォーカスを移動させる 'Shiftキーが押されている時は、逆順にする Me.SelectNextControl(Me.ActiveControl, _ ((keyData And Keys.Shift) <> Keys.Shift), True, True, True)
//次のタブオーダーのコントロールにフォーカスを移動させる //Shiftキーが押されている時は、逆順にする this.SelectNextControl(this.ActiveControl, ((keyData & Keys.Shift) != Keys.Shift), true, true, true);
補足:フォームにSplitContainerコントロールが配置されている場合の対処法は、「次のタブオーダーのコントロールをアクティブに(選択、フォーカスを移動)する」で紹介されているもの以外に、SplitContainerクラスのProcessDialogKeyメソッドを次のようにオーバーライドするという方法も考えられます。
'Imports System.Windows.Forms Public Class SplitContainerEx Inherits SplitContainer <System.Security.Permissions.UIPermission( _ System.Security.Permissions.SecurityAction.Demand, _ Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _ Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean If ((keyData And Keys.KeyCode) = Keys.Return) AndAlso _ ((keyData And (Keys.Alt Or Keys.Control)) = Keys.None) Then Return Me.ProcessTabKey((keyData And Keys.Shift) <> Keys.Shift) End If Return MyBase.ProcessDialogKey(keyData) End Function End Class
//using System.Windows.Forms; public class SplitContainerEx : SplitContainer { [System.Security.Permissions.UIPermission( System.Security.Permissions.SecurityAction.Demand, Window = System.Security.Permissions.UIPermissionWindow.AllWindows)] protected override bool ProcessDialogKey(Keys keyData) { if (((keyData & Keys.KeyCode) == Keys.Return) && ((keyData & (Keys.Alt | Keys.Control)) == Keys.None)) { return this.ProcessTabKey((keyData & Keys.Shift) != Keys.Shift); } return base.ProcessDialogKey(keyData); } }
現在フォーカスのあるコントロールのKeyDownイベントを使ってEnterキーが押されたかを調べることもできます。この場合、フォームにあるすべてのコントロールのKeyDownイベントを捕捉するのは面倒ですので、フォームのKeyPreviewプロパティをTrueにして、フォームのKeyDownイベントだけを捕捉するようにすればよいでしょう(詳しくは、「KeyPressなどのキーイベントをすべてフォームが受け取るようにする」)。
Buttonコントロールなど一部のコントロールでは、Enterキーを押してもKeyDownイベントが発生しませんので、この方法ではフォーカスが移動しません。よって、フォームにButtonコントロールを配置している場合は、ButtonコントロールのTabStopプロパティをFalseにしてフォーカスが移動しないようにするなどの工夫が必要になるでしょう。
また、フォームのAcceptButtonプロパティにButtonが設定されている時は、Enterキーを押すとそのButtonがクリックされたことになってしまうため、やはりフォーカスは移動しません(AcceptButtonプロパティについて詳しくは、「フォームにOKボタン、キャンセルボタンを付ける」)。よって、AcceptButtonプロパティにはなにも設定しないようにします。
この方法を使った具体例を以下に示します。
'Imports System.Windows.Forms 'フォームのLoadイベントハンドラ Private Sub Form1_Load(sender As Object, e As EventArgs) _ Handles MyBase.Load 'AcceptButtonを無効にする Me.AcceptButton = Nothing 'キーイベントをフォームで受け取る Me.KeyPreview = True 'KeyDownイベントハンドラを追加 AddHandler Me.KeyDown, New KeyEventHandler(AddressOf Form1_KeyDown) End Sub 'KeyDownイベントハンドラ Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) 'Enterキーが押されているか確認 'AltかCtrlキーが押されている時は無視する If (e.KeyCode = Keys.Enter) AndAlso _ Not e.Alt AndAlso Not e.Control Then 'あたかもTabキーが押されたかのようにする 'Shiftが押されている時は前のコントロールのフォーカスを移動 Me.ProcessTabKey(Not e.Shift) e.Handled = True '.NET Framework 2.0以降 e.SuppressKeyPress = True End If End Sub
//using System.Windows.Forms; //フォームのLoadイベントハンドラ private void Form1_Load(object sender, EventArgs e) { //AcceptButtonを無効にする this.AcceptButton = null; //キーイベントをフォームで受け取る this.KeyPreview = true; //KeyDownイベントハンドラを追加 this.KeyDown += new KeyEventHandler(Form1_KeyDown); } //KeyDownイベントハンドラ private void Form1_KeyDown(object sender, KeyEventArgs e) { //Enterキーが押されているか確認 //AltかCtrlキーが押されている時は無視する if ((e.KeyCode == Keys.Enter) && !e.Alt && !e.Control) { //あたかもTabキーが押されたかのようにする //Shiftが押されている時は前のコントロールのフォーカスを移動 this.ProcessTabKey(!e.Shift); e.Handled = true; //.NET Framework 2.0以降 e.SuppressKeyPress = true; } }
補足:この方法では単一行テキストボックスでEnterキーを押すとビープ音が鳴りますが、これを防ぐ方法は、「単一行テキストボックスでEnterやEscapeキーを押した時にビープ音が鳴らないようにする」で説明しています。
KeyDownイベントの代わりに、KeyUpイベントを使うこともできます。両者の違いを以下に示します。
今までの例では、複数行テキストボックス(またはリッチテキストボックス)にフォーカスがある時にEnterキーを押すと、次のコントロールにフォーカスが移動します。しかしCtrlキーが押されている時はそうしないようにしていますので、Ctrlを押しながらEnterキーを押すことで改行文字を入力することができます。
もし複数行テキストボックスではEnterキーで改行したい(そして、Ctrl+Enterキーで次のコントロールにフォーカスを移動させたい)という場合は、例えば次のようにすればよいでしょう。
'Imports System.Windows.Forms <System.Security.Permissions.UIPermission( _ System.Security.Permissions.SecurityAction.Demand, _ Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _ Protected Overrides Function ProcessDialogKey(keyData As Keys) As Boolean 'Returnキーが押されているか調べる 'Altキーが押されている時は、本来の動作をさせる If ((keyData And Keys.KeyCode) = Keys.Return) AndAlso _ ((keyData And Keys.Alt) <> Keys.Alt) Then '現在のコントロールが複数行テキストボックスか Dim isMultilineTextbox As Boolean = _ ((TypeOf Me.ActiveControl Is TextBoxBase) AndAlso _ DirectCast(Me.ActiveControl, TextBoxBase).Multiline) 'Ctrlキーが押されているか Dim pressingCtrl As Boolean = _ ((keyData And Keys.Control) = Keys.Control) '複数行テキストボックスでCtrlが押されている時と 'それ以外のコントロールでCtrlが押されていない時 If isMultilineTextbox = pressingCtrl Then 'Tabキーを押した時と同じ動作をさせる 'Shiftキーが押されている時は、逆順にする Me.ProcessTabKey((keyData And Keys.Shift) <> Keys.Shift) '本来の処理はさせない Return True End If End If Return MyBase.ProcessDialogKey(keyData) End Function
//using System.Windows.Forms; [System.Security.Permissions.UIPermission( System.Security.Permissions.SecurityAction.Demand, Window = System.Security.Permissions.UIPermissionWindow.AllWindows)] protected override bool ProcessDialogKey(Keys keyData) { //Returnキーが押されているか調べる //Altキーが押されている時は、本来の動作をさせる if (((keyData & Keys.KeyCode) == Keys.Return) && ((keyData & Keys.Alt) != Keys.Alt)) { //現在のコントロールが複数行テキストボックスか bool isMultilineTextbox = ((this.ActiveControl is TextBoxBase) && ((TextBoxBase)this.ActiveControl).Multiline); //Ctrlキーが押されているか bool pressingCtrl = ((keyData & Keys.Control) == Keys.Control); //複数行テキストボックスでCtrlが押されている時と //それ以外のコントロールでCtrlが押されていない時 if (isMultilineTextbox == pressingCtrl) { //Tabキーを押した時と同じ動作をさせる //Shiftキーが押されている時は、逆順にする this.ProcessTabKey((keyData & Keys.Shift) != Keys.Shift); //本来の処理はさせない return true; } } return base.ProcessDialogKey(keyData); }