Eingabe auf 2 Nachkommastellen begrenzen

  • VB.NET

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Eingabe auf 2 Nachkommastellen begrenzen

    Hallo zusammen,

    ich habe hier ein kleines Problem an dem ich jetzt gut paar Stunden sitze und mittlerweile nicht mehr vorankomme.
    Ich habe eine Textbox, in der ein Preis eingetragen werden soll, also nur Zahlen, ein Komma Zeichen und vor allem nur 2 Nachkommastellen.

    Das mit den Zahlen und einem Komma Zeichen bekomme ich hin, aber das mit den 2 Nachkommastellen funktioniert überhaupt nicht, egal was ich versuche.
    Mein Gedanke war, dass sobald ein Komma gesetzt wird ein Counter die Nachkommastellen begrenzt, leider ohne Erfolg.

    Der Code steht im KeyPress event der TextBox drin.

    Hier der Code:

    Quellcode

    1. If InStr(TextBox1.Text, ",") < 1 Then
    2. If (e.KeyChar < "0" OrElse e.KeyChar > "9") AndAlso e.KeyChar <> ControlChars.Back AndAlso e.KeyChar <> "," Then
    3. e.Handled = True
    4. End If
    5. Else
    6. If (e.KeyChar < "0" OrElse e.KeyChar > "9") And e.KeyChar <> ControlChars.Back Then
    7. e.Handled = True
    8. End If
    9. End If


    Ich hoffe jemand hat eine Lösung.

    Viele Grüße
    Sie: „Schatz, wir haben kein Brot mehr, könntest du bitte zum Supermarkt gehen und 1 holen? Und wenn sie Eier haben, bring 6 Stück mit.“
    Er: „Klar Schatz, mach ich!“
    Nach kurzer Zeit kommt er wieder zurück und hat 6 Brote dabei.
    Sie: „Warum nur hast du 6 Brote gekauft?!?“
    Er: „Sie hatten Eier.“
    Man nehme ein NumericUpDown mit 2 Nachkommenstellen und das Problem ist gegessen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    @Maltur Ich pflichte @VaporiZed bei.
    Bei der Textbox hast Du das Problem, dass da jemand "Roulade mit Klößen" eingeben könnte oder zwei Kommas oder Punkt, Plus, Minus.
    Probleme über Probleme, die Du mit nem NumericUpDown nicht hast.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Hi, danke für eure antworten.

    Ich habe das jetzt mit der NumericUpDown Box versucht, das Problem, das ich aber habe bleibt bestehen oder ich habe es nicht entdeckt, wie ich das verhindern kann. Ich kann nach dem Komma immer noch mehr als 2 stellen eingeben, was ich aber gerne verhindern würde.
    Sie: „Schatz, wir haben kein Brot mehr, könntest du bitte zum Supermarkt gehen und 1 holen? Und wenn sie Eier haben, bring 6 Stück mit.“
    Er: „Klar Schatz, mach ich!“
    Nach kurzer Zeit kommt er wieder zurück und hat 6 Brote dabei.
    Sie: „Warum nur hast du 6 Brote gekauft?!?“
    Er: „Sie hatten Eier.“
    Meine Vorredner haben beide recht, dennoch gibt es einen anderen Weg. KeyPress ist als Event ist allerdings nicht gut gewählt, denn wenn man in die Textbox etwas reinkopiert (Strg + V), dann bekommt dein Programm das nicht mit. Wenn also nicht mit einem NumericUpDown Control, dann nimm das TextChanged Event

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
    2. Dim txtbox As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
    3. Dim propertyName As String = txtbox.Name
    4. Dim seperator As Boolean = False
    5. Dim pos As Integer = 0
    6. For Each c As Char In txtbox.Text
    7. If pos = 0 Then
    8. If Not "-1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    9. Else
    10. If seperator Then
    11. If Not "1234567890".Contains(c) Then
    12. txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    13. End If
    14. Dim idx As Integer = txtbox.Text.IndexOf(",")
    15. If idx > -1 Then
    16. If txtbox.Text.Length > idx + 3 Then
    17. txtbox.Text = txtbox.Text.Substring(0, idx + 3)
    18. Exit For
    19. End If
    20. End If
    21. Else
    22. If Not "1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    23. End If
    24. End If
    25. pos += 1
    26. If c = ","c Then seperator = True
    27. Next
    28. txtbox.[Select](txtbox.Text.Length, 0)
    29. End Sub

    Die NumericUpDown ist ein geeignetes Werkzeug dafür.

    Sofern du jedoch trotzdem auf einer Textbox bleiben willst, dann gäbe es noch die MaskedTextBox
    msdn.microsoft.com/en-us/libra….forms.maskedtextbox.aspx

    Oder man bleibt bei der Textbox-Variante, muss es aber dann auch richtig machen. Eine kleine Hilfe bringt sicher dieser Hinweis.
    stackoverflow.com/a/15473340
    stackoverflow.com/a/7672752

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Maltur schrieb:

    Problem, das ich aber habe bleibt bestehen oder ich habe es nicht entdeckt

    Du kannst die Anzahl der Dezimalstellen bei Property DecimalPlaces angeben. Beim Validieren wird die Eingabe geprüft. Lässt sich die Eingabe in eine Dezimalzahl umwandeln, wird getan. Dabei wird die Dezimalstellen auf- bzw. abgerundet, falls mehr eingegeben wurden als erlaubt.
    Im Verlauf dieses Tuts: Alles über Events
    habich eine Eingabe-Restriktion für Richtextbox gebastelt. Das Prinzip ist, einen Backup-Mechanismus zu haben, der die Textbox bei ungültigen Eingaben wieder so herstellt, wie sie vorher war - inklusive Selection.
    Wie die Gültigkeit der Eingabe geprüft wird, wäre denn halt anzupassen - je nach Spezifikation der Bedingungen.
    Es bietet sich Regex an, String-Operationen, Decimal.Parse() oder auch Kombinationen davon.
    Wird ziemlich knifflig, weil man muss auch ungültige Eingaben zulassen, etwa 20,. Weil mit dem nächsten Tastendruck mag die erste Nachkommastelle ja kommen, sodass aus der ungültigen eine gültige Eingabe wird.
    Nix, hier werden erstmal nur verschiedene Lösungswege gesammelt.
    Das könnte mit Deinem Vorschlag was Gutes werden. Später noch als eigene Klasse usw. und das könnte klappen. Habe auf die Schnelle was gesehen: Gibt man 2 Kommata ein, verschwinden alle Kommata inkl Nachkommastelle (sofern man nicht das 2. Komma nach der 2 Nachkommastelle setzen will).
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Danke für den Hinweis, hab die Bearbeitung erweitert, nicht schön aber ich hoffe lesbar. Mit RegEx wäre das sicher nicht passiert ;)
    Das mit der eigenen Klasse habe ich so, ist aber ein anderes Projekt und in C#.

    Hier erst einmal die verbesserte Variante:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub tbFloatIn_TextChanged(sender As Object, e As EventArgs) Handles tbFloatIn.TextChanged
    2. Dim txtbox As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
    3. Dim propertyName As String = txtbox.Name
    4. Dim seperator As Boolean = False
    5. Dim pos As Integer = 0
    6. For Each c As Char In txtbox.Text
    7. If pos = 0 Then
    8. If Not "-1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    9. Else
    10. If seperator Then
    11. If Not "1234567890".Contains(c) Then
    12. If c = ","c Then
    13. Dim seperatorposition As Integer = txtbox.Text.IndexOf(",")
    14. If seperatorposition > -1 Then
    15. Dim untilfinally As String = txtbox.Text.Substring(0, seperatorposition + 1)
    16. Dim after As String = txtbox.Text.Substring(seperatorposition + 1, txtbox.Text.Length - (seperatorposition + 1))
    17. after = after.Replace(",", Microsoft.VisualBasic.Constants.vbNullChar)
    18. txtbox.Text = untilfinally & after
    19. Else
    20. 'what the fuck
    21. txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    22. End If
    23. Else
    24. txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    25. End If
    26. Else
    27. Dim idx As Integer = txtbox.Text.IndexOf(",")
    28. If idx > -1 Then
    29. If txtbox.Text.Length > idx + 3 Then
    30. txtbox.Text = txtbox.Text.Substring(0, idx + 3)
    31. Exit For
    32. End If
    33. End If
    34. End If
    35. Else
    36. If Not "1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    37. End If
    38. End If
    39. pos += 1
    40. If c = ","c Then seperator = True
    41. Next
    42. txtbox.[Select](txtbox.Text.Length, 0)
    43. End Sub



    Nachtrag: Puh, geht noch einfacher:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub tbFloatIn_TextChanged(sender As Object, e As EventArgs) Handles tbFloatIn.TextChanged
    2. Dim txtbox As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
    3. Dim propertyName As String = txtbox.Name
    4. Dim seperator As Boolean = False
    5. Dim pos As Integer = 0
    6. For Each c As Char In txtbox.Text
    7. If pos = 0 Then
    8. If Not "-1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    9. Else
    10. If seperator Then
    11. If Not "1234567890".Contains(c) Then
    12. If c = ","c Then
    13. txtbox.Text = txtbox.Text.Remove(pos, 1)
    14. Else
    15. txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    16. End If
    17. Else
    18. Dim idx As Integer = txtbox.Text.IndexOf(",")
    19. If idx > -1 Then
    20. If txtbox.Text.Length > idx + 3 Then
    21. txtbox.Text = txtbox.Text.Substring(0, idx + 3)
    22. Exit For
    23. End If
    24. End If
    25. End If
    26. Else
    27. If Not "1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    28. End If
    29. End If
    30. pos += 1
    31. If c = ","c Then seperator = True
    32. Next
    33. txtbox.[Select](txtbox.Text.Length, 0)
    34. End Sub



    Nachtrag 2: Wobei dann kann man auch weiter eindampfen zu:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub tbFloatIn_TextChanged(sender As Object, e As EventArgs) Handles tbFloatIn.TextChanged
    2. Dim txtbox As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
    3. Dim propertyName As String = txtbox.Name
    4. Dim seperator As Boolean = False
    5. Dim pos As Integer = 0
    6. For Each c As Char In txtbox.Text
    7. If pos = 0 Then
    8. If Not "-1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Replace(c, Microsoft.VisualBasic.Constants.vbNullChar)
    9. Else
    10. If seperator Then
    11. If Not "1234567890".Contains(c) Then
    12. txtbox.Text = txtbox.Text.Remove(pos, 1)
    13. Else
    14. Dim idx As Integer = txtbox.Text.IndexOf(",")
    15. If idx > -1 Then
    16. If txtbox.Text.Length > idx + 3 Then
    17. txtbox.Text = txtbox.Text.Substring(0, idx + 3)
    18. Exit For
    19. End If
    20. End If
    21. End If
    22. Else
    23. If Not "1234567890,".Contains(c) Then txtbox.Text = txtbox.Text.Remove(pos, 1)
    24. End If
    25. End If
    26. pos += 1
    27. If c = ","c Then seperator = True
    28. Next
    29. txtbox.[Select](txtbox.Text.Length, 0)
    30. End Sub


    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Dksksm“ ()

    Ich denke mal ja, sollte man immer prüfen. die erste Variante aus Post #11 funktioniert dann auch noch immer, allerdings ist die Funktion auch etwas brutal, denn durch das Einfügen von vbNullChar exisitiert das ungültige Zeichen und auch alles was dann noch käme nicht mehr.
    Ich schätze, dass Du jetzt mit RegEx aus dem Busch kommst und eine ordentliche Funktion zeigst ;)

    Nachtrag: wie wär's damit (nochmal aufpoliert):

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub tbFloatTwoDigits_TextChanged(sender As Object, e As EventArgs) Handles tbFloatIn.TextChanged
    2. Dim seperator As String = System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator
    3. Dim txtbox As System.Windows.Forms.TextBox = CType(sender, System.Windows.Forms.TextBox)
    4. Dim newtext As New StringBuilder()
    5. Dim numbers As String = "01235456789"
    6. Dim minus As String = "-"
    7. For index As Integer = 0 To txtbox.Text.Length - 1
    8. If newtext.Length = 0 Then
    9. Dim permissible As String = minus & numbers & seperator
    10. If permissible.Contains(txtbox.Text.Substring(index, 1)) Then newtext.Append(txtbox.Text.Substring(index, 1))
    11. Else
    12. If newtext.ToString().Contains(",") Then
    13. If numbers.Contains(txtbox.Text.Substring(index, 1)) Then newtext.Append(txtbox.Text.Substring(index, 1))
    14. Dim idx As Integer = newtext.ToString().IndexOf(",")
    15. If idx > -1 Then
    16. Dim temptxt As String = newtext.ToString()
    17. If temptxt.Length > idx + 3 Then
    18. newtext.Clear()
    19. newtext.Append(temptxt.Substring(0, idx + 3))
    20. Exit For
    21. End If
    22. End If
    23. Else
    24. Dim permissible As String = numbers & seperator
    25. If permissible.Contains(txtbox.Text.Substring(index, 1)) Then newtext.Append(txtbox.Text.Substring(index, 1))
    26. End If
    27. End If
    28. Next
    29. txtbox.Text = newtext.ToString()
    30. txtbox.[Select](txtbox.Text.Length, 0)
    31. End Sub


    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Dksksm“ ()

    Dksksm schrieb:

    denn wenn man in die Textbox etwas reinkopiert (Strg + V)

    ErfinderDesRades schrieb:

    muss das auch sicher dagegen sein, dass jemand mit Copy & pASTe da mehrere Zeichen auf einmal einpastet - von denen evtl. welche ungültig sind?

    man kann das bei einer Textbox ganz einfach unterbinden: ShortcutsEnabled = True
    In meiner Trickkiste hab ich eine eigene TextBox gefunden, mit der man Paste wahlweise schalten kann:
    TextBoxPaste

    C#-Quellcode

    1. using System;
    2. using System.Windows.Forms;
    3. namespace WindowsFormsApplication1
    4. {
    5. internal class TextBoxPaste
    6. : TextBox
    7. {
    8. public event EventHandler<EventArgsHandled> OnPaste;
    9. protected override void WndProc(ref System.Windows.Forms.Message m)
    10. {
    11. const int WM_PASTE = 0x0302;
    12. if (m.Msg == WM_PASTE)
    13. {
    14. if (this.OnPaste != null)
    15. {
    16. EventArgsHandled e = new EventArgsHandled();
    17. this.OnPaste(this, e);
    18. if (e.Handled)
    19. {
    20. return;
    21. }
    22. }
    23. }
    24. base.WndProc(ref m);
    25. }
    26. private void InitializeComponent()
    27. {
    28. this.SuspendLayout();
    29. this.ResumeLayout(false);
    30. }
    31. }
    32. /// <summary>
    33. /// Represents an Event Argument class with a Handled property
    34. /// </summary>
    35. public class EventArgsHandled
    36. : EventArgs
    37. {
    38. /// <summary>
    39. /// Gets or sets a value indicating whether the Paste proceeding was handled.
    40. /// </summary>
    41. public bool Handled { get; set; }
    42. /// <summary>
    43. /// Constructs an instance of the EventArgsPaste class
    44. /// </summary>
    45. public EventArgsHandled()
    46. {
    47. this.Handled = false;
    48. }
    49. }
    50. }
    Compilieren, auf das GUI zuehen und noch ne CheckBox cbNoPaste:
    Hauptform

    C#-Quellcode

    1. using System;
    2. using System.Windows.Forms;
    3. namespace WindowsFormsApplication1
    4. {
    5. public partial class Form1 : Form
    6. {
    7. public Form1()
    8. {
    9. this.InitializeComponent();
    10. }
    11. private void Form1_Load(object sender, EventArgs e)
    12. {
    13. this.textBoxPaste1.OnPaste += this.textBoxPaste1_OnPaste;
    14. }
    15. void textBoxPaste1_OnPaste(object sender, EventArgsHandled e)
    16. {
    17. e.Handled = this.cbNoPaste.Checked;
    18. }
    19. }
    20. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Ich hab's auch einmal versucht:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
    2. Dim tbx = DirectCast(sender, TextBox)
    3. Dim txt = tbx.Text
    4. If e.KeyChar = Convert.ToChar(Keys.Escape) Then tbx.Text = "" : Return
    5. If e.KeyChar = Convert.ToChar(Keys.Back) Then Return
    6. If e.KeyChar = "-"c Then
    7. If txt.Contains("-"c) Then
    8. tbx.Text = txt.Replace("-"c, "")
    9. Else
    10. tbx.Text = "-"c & txt
    11. End If
    12. tbx.SelectionStart = txt.Length + 1
    13. e.Handled = True
    14. Return
    15. End If
    16. If txt.IndexOf(","c) > -1 AndAlso (txt.Length - txt.IndexOf(","c)) > 2 Then e.Handled = True : Return
    17. If e.KeyChar = ","c Then
    18. If txt.Contains(","c) Then e.Handled = True : Return
    19. Return
    20. End If
    21. e.Handled = Not "0123456789".Contains(e.KeyChar)
    22. End Sub​
    hihi - ich hab mein Senf ja schon abgegeben, zum Code gugge muss man halt das Tutorial aufsuchen.
    Meine kann Copy/Paste, und man kann auch mitten drin was einfügen, und braucht ShortCuts nicht abzuschalten.
    Aber meine zeigt auch nur das Prinzip (mit dem TextBoxRestore)- man müsste es auf Textbox umstricken, und auch die Validierung an die hiesige Anforderung anpassen.