以前、以下の記事でテキストボックスの入力される文字を数字のみに限定するコントロールについて記述しましたが、 このコントロールは数値入力には適さないので、今回は少し使える様に入力の見た目は電卓の感じにしてみました。 (数字が1の位から左側へシフトしていきます。)
今回のコントロールの動きは以下の様になります。
- 数値の表示は3桁毎にカンマ編集での表示とする。
- カーソル(キャレット)は常にコントロールの右端に存在し動かない。 (矢印キーは動作しない)
- マイナス値は「-」(マイナスキー)を押下することで数値をプラスとマイナスを反転する。
- 「BackSpace」キーで最終文字を削除する。
- クリップボードからのペーストは出来ない様にする。
前回のコントロールでは KeyPress イベントで入力されたキーの制御をしていましたが、 今回はほとんどの処理を KeyDown イベントで行い、 KeyPress イベントでの処理は全て行わない様にします。
今回の処理ではテキストボックスの Text プロパティへの再表示を自分で強制的に行っているため、 KeyPress イベントでの処理をスキップしないと表示がおかしくなるためです。 (文字がダブって表示されたりします)
今回の処理で肝となる KeyDown イベントでは以下のキー処理を行います。
- [Enter]:[Ctrl]キーが押下されていない場合、自分の親のコントロールの次のフォーカスへ移動
- [↑][↓][←][→]:矢印キーは処理無し(キーを捨てる)
- [0]~[9]:入力文字列が数値桁数を超えない場合にカンマ編集表示
- [-]:数値のプラス、マイナスの反転処理
- [BackSpace]:最終文字を削除
- その他のキー:処理無し(キーを捨てる)
尚、クリップボードからのペースト処理をしない様に WndProc をオーバーライドしペーストのメッセージを処理しない様にしています。
テキストボックスの電卓の様な入力コントロールクラス
Public Class ClsNumTextBox3 Inherits TextBox '数値桁数("-",","を含まない数値の桁数) Private _NumericUnits As Integer = 9 '数値マイナスフラグ Private _fMinus As Boolean = False 'クリップボード貼付メッセージ Const WM_PASTE As Integer = &H302 '''''' コンストラクタ ''' Public Sub New() MyBase.New() 'IMEを無効にする MyBase.ImeMode = ImeMode.Disable 'MaxLengthは取り敢えず16を設定 Me.MaxLength = 16 'テキストは右寄せ Me.TextAlign = HorizontalAlignment.Right End Sub '''''' WndProc メソッド(クリップボード処理の為) ''' ''' <param name="m">メッセージ</param> Protected Overrides Sub WndProc(ByRef m As Message) Select Case m.Msg Case WM_PASTE 'クリップボードからのコピーは処理しない Return End Select 'メッセージのデフォルト処理を呼出す MyBase.WndProc(m) End Sub '''''' 数値桁数プロパティ ''' Public WriteOnly Property NumericUnits As Integer Set(value As Integer) Me._NumericUnits = value '退避値に設定 End Set End Property '''''' 数値での取得設定プロパティ ''' '''設定値 '''取得値 Public Property Value As Decimal Set(value As Decimal) Dim strNum As String = Math.Abs(value).ToString If strNum.Length > Me._NumericUnits Then MsgBox("ERR:数値桁数 " & Me._NumericUnits & " より大きい値が設定された") Else Me._fMinus = (value < 0) 'マイナスフラグ設定 Me.Text = strNum '取敢えず数値文字列設定 Call Me.RepairNumString("", Me._fMinus) End If End Set Get '文字列からカンマ除去 Dim strNum As String = Me.Text.Replace(",", "") 'Decimal変換値を返す Return ToDec(strNum) End Get End Property '''''' KeyDownイベントの処理 ''' Protected Overrides Sub OnKeyDown(e As KeyEventArgs) MyBase.OnKeyDown(e) Dim strAdd As String = "" Dim fEdit As Boolean = False 'キーコードによる処理 Select Case e.KeyCode Case Keys.Enter If e.Control = False Then '[Ctrl]キーが押下されていない場合、自分の親のコントロールの次のフォーカスへ移動 Me.Parent.SelectNextControl(Me, Not e.Shift, True, True, True) End If Case Keys.Up, Keys.Down, Keys.Left, Keys.Right e.Handled = True Case Keys.D0 To Keys.D9, Keys.NumPad0 To Keys.NumPad9 'キーが [0]~[9] '入力文字列が数値桁数を超えないかチェック Dim strNum As String = Me.Text.Replace("-", "").Replace(",", "") If strNum.Length >= Me._NumericUnits Then e.Handled = True Else Select Case e.KeyCode Case Keys.D0 To Keys.D9 strAdd = "0123456789".Substring(e.KeyCode - Keys.D0, 1) Case Keys.NumPad0 To Keys.NumPad9 strAdd = "0123456789".Substring(e.KeyCode - Keys.NumPad0, 1) End Select fEdit = True '編集表示フラグON e.Handled = True End If Case Keys.Subtract 'キーが [-] Me._fMinus = Not Me._fMinus 'マイナスフラグ反転 fEdit = True '編集表示フラグON Case Keys.Back '最後尾1文字削除 RepairNumString("", Me._fMinus, True) Me.SelectionStart = Me.Text.Length If Me.Text.Length = 0 Then '文字列が空になった場合はマイナスフラグOFF Me._fMinus = False End If e.Handled = True Case Else e.Handled = True End Select If fEdit = True Then '編集表示フラグONの場合、編集表示 Call Me.RepairNumString(strAdd, Me._fMinus) Me.SelectionStart = Me.Text.Length End If End Sub '''''' KeyPressイベントの処理 ''' Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs) MyBase.OnKeyPress(e) '全ての文字をイベントをキャンセル e.Handled = True End Sub '''''' MouseDownイベント処理 ''' Protected Overrides Sub OnMouseDown(e As MouseEventArgs) MyBase.OnMouseDown(e) If Not (Me.SelectionStart = Me.Text.Length) Then 'カーソル位置を最後尾に強制移動 Me.SelectionStart = Me.Text.Length End If End Sub '''''' 文字列の編集表示 ''' ''' <param name="strAdd">最後尾付加文字</param> ''' <param name="fMinus">数値マイナスフラグ</param> ''' <param name="fBackSpace">BACKSPACEフラグ</param> '''文字列を3桁ごとにカンマ編集する Private Sub RepairNumString(ByVal strAdd As String, ByVal fMinus As Boolean, Optional fBackSpace As Boolean = False) '文字を最後に追加する Dim strNum As String = Me.Text.Replace("-", "").Replace(",", "") & strAdd If fBackSpace = True Then 'BackSpaceの指定の場合、最後の文字を削除 If strNum <> "" Then strNum = strNum.Substring(0, strNum.Length - 1) End If End If '3桁ごとのカンマ表示 Dim str As String = Me.ToDec(strNum).ToString("#,###") 'マイナスの場合は"-"付加 If fMinus = True Then If str <> "" Then str = "-" & str End If End If Me.Text = str 'マイナスの場合は赤色設定 If fMinus = True Then If Not Me.ForeColor = Color.Red Then Me.ForeColor = Color.Red End If Else If Not Me.ForeColor = Color.Black Then Me.ForeColor = Color.Black End If End If End Sub '''''' 文字列をDecimal数値変換 ''' ''' <param name="str">文字列</param> '''変換後の数値 Private Function ToDec(ByVal str As String) As Decimal Dim dec As Decimal = 0 Try If str <> "" Then dec = CDec(str) End If Catch ex As Exception End Try Return dec End Function End Class
今回のコントロールを2個とボタンをフォームに張り付け、 そのボタンで1個目の数値を2個目の数値コントロールにコピーを行う例を以下に示します。
電卓風数値入力コントロールの例
Public Class frmTextBox3 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Try Dim dec As Decimal = Me.NumTextBox1.Value Me.NumTextBox2.Value = dec Catch ex As Exception End Try End Sub End Class
ボタンを押下することで、上のコントロールの Value プロパティから値を取得し、 その値を下のコントロールの Value プロパティに設定します。 その結果、値がコピーされたことが分かります。 (上の画像は先にマイナス値をコピーした後で、上のコントロールで「-」キーを押下した様子です)
関連する記事
⇒テキストボックスの入力を数字のみにする方法⇒テキストボックス拡張クラスにプロパティを追加する方法
⇒テキストボックスの Leave イベントでのエラー処理でフォーカス強制移動する方法について
コメント