【问题标题】:Automatic decimal places in textbox文本框中的自动小数位
【发布时间】:2017-12-06 20:27:45
【问题描述】:

看起来很奇怪,但是我的问题找不到在线解决方案!至少在 VB.NET 中。

这里是交易: 我有一个表单中的文本框(仅限于KeyPress 事件的数字),并且只要用户输入他的数据,我就希望保留两位小数。

例如,如果 TextBox 是空白的,那么当用户按下“2”时,TextBox 会显示“0,02”。然后,如果用户按下“7”,TextBox 将显示“0,27”。然后再按“6”,它显示“2,76”等等......

我设法用代码做到了小数点后一位:

    Select Case Me.TextBox.Text
        Case ""
        Case ","
            Me.TextBox.Text = ""
        Case Else
            Me.TextBox.Text = Strings.Left(Replace(Me.TextBox.Text, ",", ""), Strings.Len(Replace(Me.TextBox.Text, ",", "")) - 1) & "," & Strings.Right(Replace(Me.TextBox.Text, ",", ""), 1)
            Me.TextBox.SelectionStart = Len(Me.TextBox.Text)
    End Select

请注意:1. 此代码在TextChanged 事件上运行; 2.我来自葡萄牙,在这里我们使用逗号 (",") 而不是点 (".") 作为小数分隔符。

您能帮我调整一下我的代码,使其在保留两位小数的情况下正常工作吗?

任何帮助将不胜感激。和往常一样,提前谢谢大家。

【问题讨论】:

  • 我不会更改文本,而是使用Leave 事件,这样您就不必与放入其中的十进制字符竞争。然后使用ToString(0 使用文化使用的任何十进制字符
  • 您使用了错误的事件,请改用 Validating 事件。 Decimal.TryParse + Decimal.ToString 应该很有用。
  • stackoverflow.com/questions/16035506/… 一个相对类似问题的 c# 答案,它可能会对你有所帮助!
  • @Plutonix,@Hans Passant,对不起,当您完成输出时,LeaveValidating 事件都会发生,我很确定。只要用户填写TextBox,我希望代码运行。
  • @Kevin,我去看看。

标签: vb.net textbox decimal


【解决方案1】:

这是我制作的自定义类,可以满足您的要求:

Public Class FactorDecimal
    Private _value As String = "0"

    Public DecimalPlaces As Integer

    Public Sub AppendNumber(ByVal Character As Char)
        If Char.IsNumber(Character) = False Then Throw New ArgumentException("Input must be a valid numerical character!", "Character")
        _value = (_value & Character).TrimStart("0"c)
    End Sub

    Public Sub RemoveRange(ByVal Index As Integer, ByVal Length As Integer)
        If _value.Length >= Me.DecimalPlaces + 1 AndAlso _
            Index + Length > _value.Length - Me.DecimalPlaces Then Length -= 1 'Exclude decimal point.

        If Index + Length >= _value.Length Then Length = _value.Length - Index 'Out of range checking.

        _value = _value.Remove(Index, Length)

        If _value.Length = 0 Then _value = "0"
    End Sub

    Public Overrides Function ToString() As String
        Dim Result As Decimal
        If Decimal.TryParse(_value, Result) = True Then
            'Divide Result by (10 ^ DecimalPlaces) in order to get the amount of decimal places we want.
            'For example: 2 decimal places   =>   Result / (10 ^ 2) = Result / 100 = x,xx.
            Return (Result / (10 ^ Me.DecimalPlaces)).ToString("0." & New String("0"c, Me.DecimalPlaces))
        End If
        Return "<parse error>"
    End Function

    Public Sub New(ByVal DecimalPlaces As Integer)
        If DecimalPlaces <= 0 Then DecimalPlaces = 1
        Me.DecimalPlaces = DecimalPlaces
    End Sub
End Class

它的工作原理是让您附加数字以形成一长串数字字符(例如 3174 + 8 = 31748),然后当您调用 ToString() 时,它会执行以下操作:

  • 它将长数字字符串解析为十进制(例如"31748" =&gt; 31748.0

  • 它将小数除以 10 的小数次幂(例如:2 个小数 => 31748.0 / 10<sup>2</sup> = 317.48) .

  • 最后它以0.x 的格式在小数点上调用ToString() - 其中x 是重复的零数量,具体取决于您想要多少个小数(例如2 个小数 => 0.00)。

注意:此解决方案适应当前系统的文化设置,因此将自动使用该文化中定义的小数点。例如,在美国 (en-US) 系统中,它将使用点:317.48,而在瑞典语 (sv-SE) 或葡萄牙语 (pt-PT) 系统中,它将使用逗号:317,48

你可以这样使用它:

Dim FactorDecimal1 As New FactorDecimal(2)

Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
    If Char.IsNumber(e.KeyChar) = False Then
        e.Handled = True 'Input was not a number.
        Return
    End If

    FactorDecimal1.AppendNumber(e.KeyChar)
    TextBox1.Text = FactorDecimal1.ToString()
End Sub

Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
    Dim TargetTextBox As TextBox = DirectCast(sender, TextBox)
    e.SuppressKeyPress = True

    Select Case e.KeyData 'In order to not block some standard keyboard shortcuts (ignoring paste since the pasted text won't get verified).
        Case Keys.Control Or Keys.C
            TargetTextBox.Copy()
        Case Keys.Control Or Keys.X
            TargetTextBox.Cut()
        Case Keys.Control Or Keys.A
            TargetTextBox.SelectAll()
        Case Keys.Back, Keys.Delete 'Backspace or DEL.
            FactorDecimal1.RemoveRange(TextBox1.SelectionStart, If(TextBox1.SelectionLength = 0, 1, TextBox1.SelectionLength))
            TextBox1.Text = FactorDecimal1.ToString()
        Case Else
            e.SuppressKeyPress = False 'Allow all other key presses to be passed on to the KeyPress event.
    End Select
End Sub

在线测试:http://ideone.com/fMcKJr

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    谢谢@Visual Vincent。你的方法效果很好。但是,我设法找到了一种更简单的方法来执行以下代码所要求的操作:

    Private Sub TextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox.KeyPress
        If Not Char.IsDigit(e.KeyChar) And Not Char.IsControl(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub TextBox_TextChanged(sender As Object, e As EventArgs) Handles TextBox.TextChanged
        Select Case Val(Replace(Me.TextBox.Text, ",", "."))
            Case 0 : Me.TextBox.Text = ""
            Case Else
                Me.TextBox.Text = Format(Val(Replace(Me.TextBox.Text, ",", "")) / 100, "0.00")
                Me.TextBox.SelectionStart = Len(Me.TextBox.Text)
        End Select
    End Sub
    

    对我来说,这段代码看起来很简单。现在它工作正常,并且完全按照我想要的方式完成。也许我缺少一些东西,或者我对目标的描述不够清楚。 如果您发现我的方法有任何缺陷,请随时指出!我会非常感激的。

    【讨论】:

    • 我想唯一要指出的是这也将适应系统的小数点。因此,尝试用"" 替换"," 将不适用于例如美国系统。否则我想它应该工作。 :)
    • 也许这就是它起作用的原因...对于某些事情,不是美国人很好,嗯嗯嗯...非常感谢您的回复:)
    • 那么你唯一需要做的就是第二次替换它应该可以工作:Replace(Replace(Me.TextBox.Text, ",", ""), ".", "")
    • 我刚刚注意到的一件事(由于我正在度假,我无法对此进行测试)是不应该在 TextChanged 中更改 Me.TextBox.Text 导致事件一次又一次地无限期引发?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多