以前、以下の記事でテキストボックスの入力される文字を数字のみに限定するコントロールについて記述しましたが、 このコントロールは数値入力には適さないので、今回は少し使える様に入力の見た目は電卓の感じにしてみました。 (数字が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 イベントでのエラー処理でフォーカス強制移動する方法について
コメント