忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

テキストボックスの入力を数字のみにする方法その2(電卓の様な入力)

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











PR

コメント

コメントを書く