ここでは、テキストボックス(TextBoxコントロール)に数字以外の文字が入力できないようにする方法を幾つか紹介します。
注意:ここで紹介した方法だけでは、数字以外の文字列が入力されることを完全に防げることはできません。入力された文字列が本当に数字だけか確かめ、そうでなければ拒否するためには、必ずTextBoxのValidatingイベントを使用してください。文字列が数値に変換できるか調べる方法に関しては、「文字列が数字に変換できるか調べる」をご覧ください。
テキストボックス(TextBox1)のKeyPressイベントで数字以外のキー入力をキャンセルするには、次のようなコードを書きます。
'TextBox1のKeyPressイベントハンドラ Private Sub TextBox1_KeyPress(sender As Object, _ e As System.Windows.Forms.KeyPressEventArgs) If e.KeyChar < "0"c OrElse "9"c < e.KeyChar Then '押されたキーが 0~9でない場合は、イベントをキャンセルする e.Handled = True End If End Sub
//TextBox1のKeyPressイベントハンドラ private void TextBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { if (e.KeyChar < '0' || '9' < e.KeyChar) { //押されたキーが 0~9でない場合は、イベントをキャンセルする e.Handled = true; } }
補足:「e.KeyChar < '0' || e.KeyChar > '9'」(VB.NETでは「e.KeyChar < "0"c Or e.KeyChar > "9"c」)の条件式は、「!Char.IsDigit(e.KeyChar)」(VB.NETでは「Not Char.IsDigit(e.KeyChar)」)とすることもできます。
補足:.NET Framework 2.0からは、KeyDownイベントハンドラでKeyEventArgs.SuppressKeyPressプロパティをTrueにすることによっても、キー入力を無効にすることができます。KeyDownイベントハンドラでSuppressKeyPressプロパティをTrueにすると、KeyPressイベントは発生しなくなります。
上記のようにしたテキストボックスではDeleteキーを使用して文字を削除することはできますが、バックスペースは使用できなくなります。バックスペースが使えるようにするには、次のようにして数字に加えてバックスペース文字も許可するようにします。テキストボックスに入力できる文字を増やしたい時は、同様にしてIf文の条件式に許可する文字を追加してください。
'TextBox1のKeyPressイベントハンドラ Private Sub TextBox1_KeyPress(sender As Object, _ e As System.Windows.Forms.KeyPressEventArgs) '0~9と、バックスペース以外の時は、イベントをキャンセルする If (e.KeyChar < "0"c OrElse "9"c < e.KeyChar) AndAlso _ e.KeyChar <> ControlChars.Back Then e.Handled = True End If End Sub
//TextBox1のKeyPressイベントハンドラ private void TextBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { //0~9と、バックスペース以外の時は、イベントをキャンセルする if ((e.KeyChar < '0' || '9' < e.KeyChar) && e.KeyChar != '\b') { e.Handled = true; } }
補足:入力された文字が制御文字か調べるには、「Char.IsControl(e.KeyChar)」とすることもできます。
補足:このようにしてもテキストボックスでDeleteキーが使用できるのは、Deleteキーが押されてもKeyPressイベントが発生しないからです。Deleteキーが押されても何もしないようにする方法は、「コントロールで矢印、Tab、Enter、Escキーが押されたことを知る」をご覧ください。
しかしこれだけでは、IMEがオンになっている時は、数字以外の文字が入力されてしまいます。これを出来ないようにするには、テキストボックスのImeModeプロパティをDisableにしておきます。
また、クリップボードにコピーされた文字列を貼り付けることによっても数字以外を入力できてしまいます。クリップボードからのペーストを防ぐ方法は、「TextBoxにペースト(貼り付け)できないようにする」で説明しています。
TextBoxコントロールを継承して、数字とバックスペース以外の入力を無効にしたTextBoxの例を以下に示します。ここでは、数字のみで構成された文字列がクリップボードにあるときしか貼り付けできないようにしています。このコントロールを使う方法は、『「○○○クラスの代わりに派生クラスを使用します」の意味は?』をご覧ください。
Imports System.Windows.Forms Imports System.Security.Permissions Imports System.ComponentModel ''' <summary> ''' 数字とバックスペース以外の入力を無効にしたTextBox ''' </summary> Public Class NumericTextBox Inherits TextBox Const WM_PASTE As Integer = &H302 <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = WM_PASTE Then Dim iData As IDataObject = Clipboard.GetDataObject() '文字列がクリップボードにあるか If Not iData Is Nothing AndAlso _ iData.GetDataPresent(DataFormats.Text) Then Dim clipStr As String = _ DirectCast(iData.GetData(DataFormats.Text), String) 'クリップボードの文字列が数字のみか調べる If Not System.Text.RegularExpressions.Regex.IsMatch( _ clipStr, "^[0-9]+$") Then Return End If End If End If MyBase.WndProc(m) End Sub Public Sub New() MyBase.New() 'IMEを無効にする MyBase.ImeMode = ImeMode.Disable '数字以外で入力が可能な文字 Me.SetAllowKeyChars(New Char() {ControlChars.Back}) End Sub <Browsable(False), EditorBrowsable(EditorBrowsableState.Never)> _ Public Shadows Property ImeMode() As ImeMode Get Return MyBase.ImeMode End Get Set(value As ImeMode) End Set End Property Private _allowKeyChars As Char() ''' <summary> ''' 数字以外で入力が可能な文字を設定する ''' </summary> Public Sub SetAllowKeyChars(keyChars As Char()) Me._allowKeyChars = keyChars End Sub ''' <summary> ''' 数字以外で入力が可能な文字を取得する ''' </summary> Public Function GetAllowKeyChars() As Char() Return Me._allowKeyChars End Function Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs) MyBase.OnKeyPress(e) '数字以外が入力された時はキャンセルする If (e.KeyChar < "0"c OrElse "9"c < e.KeyChar) AndAlso _ Array.IndexOf(Me._allowKeyChars, e.KeyChar) < 0 Then e.Handled = True End If End Sub End Class
using System.Windows.Forms; using System.Security.Permissions; using System.ComponentModel; /// <summary> /// 数字とバックスペース以外の入力を無効にしたTextBox /// </summary> public class NumericTextBox : TextBox { private const int WM_PASTE = 0x302; [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { if (m.Msg == WM_PASTE) { IDataObject iData = Clipboard.GetDataObject(); //文字列がクリップボードにあるか if (iData != null && iData.GetDataPresent(DataFormats.Text)) { string clipStr = (string)iData.GetData(DataFormats.Text); //クリップボードの文字列が数字のみか調べる if (!System.Text.RegularExpressions.Regex.IsMatch( clipStr, @"^[0-9]+$")) { return; } } } base.WndProc(ref m); } public NumericTextBox() : base() { //IMEを無効にする base.ImeMode = ImeMode.Disable; //数字以外で入力が可能な文字 this.SetAllowKeyChars(new char[] { '\b' }); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new ImeMode ImeMode { get { return base.ImeMode; } set { } } private char[] _allowKeyChars; /// <summary> /// 数字以外で入力が可能な文字を設定する /// </summary> public void SetAllowKeyChars(char[] keyChars) { this._allowKeyChars = keyChars; } /// <summary> /// 数字以外で入力が可能な文字を取得する /// </summary> public char[] GetAllowKeyChars() { return this._allowKeyChars; } protected override void OnKeyPress(KeyPressEventArgs e) { base.OnKeyPress(e); //数字以外が入力された時はキャンセルする if ((e.KeyChar < '0' || '9' < e.KeyChar) && Array.IndexOf(this._allowKeyChars, e.KeyChar) < 0) { e.Handled = true; } } }
補足:上記NumericTextBoxクラスのSetAllowKeyChars、GetAllowKeyCharsメソッドをプロパティにすると、NumericTextBoxをフォームデザイナでフォームに配置した時、フォームデザイナが開かなくなってしまうというご報告を掲示板にいただきました。ただし、Char型の配列をList<char>に変更すれば、プロパティにしても大丈夫なようです。
TextBoxコントロールの代わりに、NumericUpDownコントロールを使うという手も考えられます。NumericUpDownコントロールならば、Valueプロパティから入力値を取得することで、確実に数値を取得できます。
NumericUpDownコントロールでも、IMEを有効にしていると数字以外の文字が入力できますし、コピー&ペーストもできます。しかし数字以外の文字が入力された場合、Valueプロパティで値を取得すると、それ以前に入力されていた数字が返され、NumericUpDownコントロールの表示もその数字に戻ります。
.NET Framework 2.0以降では、TextBoxコントロールの代わりにMaskedTextBoxコントロールを使う方法も考えられます。
例えばMaskedTextBoxコントロールのMaskプロパティを「99999」とすると、5文字の数字か空白しか入力できなくなります。Maskプロパティの書式については、MSDNの「MaskedTextBox.Mask プロパティ」をご覧ください。
しかしこの方法でも全角の数字が入力できてしまいますし、空白文字が入ることもできます。
MaskedTextBox.ValidatingTypeプロパティを使うと、MaskedTextBoxコントロールに入力された文字列が指定された型に変換できるかの確認を、コントロールがフォーカスを失う時に行うことができます。例えばValidatingTypeプロパティを「Int32」にすると、コントロールがフォーカスを失う時、入力された文字列がInt32.Parseメソッドで変換できるかが確かめられ、その結果をTypeValidationCompletedイベントで知ることができます。
以下の例では、MaskedTextBox1に入力された文字列がInt32型に変換できない時は、メッセージボックスを表示して、MaskedTextBox1からフォーカスが移動しないようにしています。
'Form1のLoadイベントハンドラ Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load '数字と空白しか入力できないようにする Me.MaskedTextBox1.Mask = "99999" 'Int32型に変換できるか検証する Me.MaskedTextBox1.ValidatingType = GetType(Integer) 'TypeValidationCompletedイベントハンドラを追加する AddHandler Me.MaskedTextBox1.TypeValidationCompleted, _ AddressOf MaskedTextBox1_TypeValidationCompleted End Sub Private Sub MaskedTextBox1_TypeValidationCompleted( _ sender As Object, e As TypeValidationEventArgs) 'Int32型に変換できるか確かめる If Not e.IsValidInput Then 'Int32型への変換に失敗した時は、フォーカスが移動しないようにする MessageBox.Show("数値を入力してください") e.Cancel = True End If End Sub
//Form1のLoadイベントハンドラ private void Form1_Load(object sender, EventArgs e) { //数字と空白しか入力できないようにする this.MaskedTextBox1.Mask = "99999"; //Int32型に変換できるか検証する this.MaskedTextBox1.ValidatingType = typeof(int); //TypeValidationCompletedイベントハンドラを追加する this.MaskedTextBox1.TypeValidationCompleted += MaskedTextBox1_TypeValidationCompleted; } private void MaskedTextBox1_TypeValidationCompleted( object sender, TypeValidationEventArgs e) { //Int32型に変換できるか確かめる if (!e.IsValidInput) { //Int32型への変換に失敗した時は、フォーカスが移動しないようにする MessageBox.Show("数値を入力してください"); e.Cancel = true; } }
最後にもう1つ方法を紹介しましょう。これは、ニュースグループで紹介されていた方法です。CreateParams.StyleにES_NUMBERを追加しています。この方法でもやはりコピー&ペーストで文字列以外の文字を入力できてしまいます。
Imports System.Windows.Forms Imports System.Security.Permissions ''' <summary> ''' 数字しかキー入力できないTextBox ''' </summary> Public Class NumericTextBox Inherits TextBox Private ES_NUMBER As Integer = &H2000 Protected Overrides ReadOnly Property CreateParams() As CreateParams <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Get Dim parms As CreateParams = MyBase.CreateParams parms.Style = parms.Style Or ES_NUMBER Return parms End Get End Property End Class
using System.Windows.Forms; using System.Security.Permissions; /// <summary> /// 数字しかキー入力できないTextBox /// </summary> public class NumericTextBox : TextBox { const int ES_NUMBER = 0x2000; protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { CreateParams parms = base.CreateParams; parms.Style |= ES_NUMBER; return parms; } } }
(この質問は掲示板でいただいた質問です。)