Dynamisch erstellte Textboxen mit Buttons beschreiben

  • VB.NET
  • .NET (FX) 4.5–4.8

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

    Dynamisch erstellte Textboxen mit Buttons beschreiben

    Holla
    Ich erzeuge anhand der Menge Einträge in einer DataTable dynamisch Textboxen. Diese Textboxen speichere ich dann in einer List of Controls, damit ich später leichter darauf zugreifen kann.
    Es handelt sich beim Inhalt der DataTable um Warengruppen, welche durch die Textboxen eine Tageseinnahme zugewiesen bekommen. Das klappt alles.
    Diese Textboxen möchte ich nun mithilfe eines TouchNumPads (also Button 0 bis 9, ein Komma, einmal Enter, und einmal Backslash) auf der gleichen Form beschreiben.
    Zusätzlich zu den im Code erstellten Textboxen gibt es noch eine Per Designer erstellte (für die Kundenzahl) mit TabIndex 0.

    Also ein Druck auf einen Zahlenbutton, soll die entsprechende Zahl in die Box schreiben (angefangen bei Kunden (TabIndex0)), beim Komma genauso.
    Druck auf Enter soll dann ein Beschreiben der nächsten Box ermöglichen, oder, wenn keine Box mehr zum beschreiben da ist, denn "speichern" Button fokussieren, und beim erneuten druck den Button "klicken".
    Also das gleiche Verhalten, als wenn ich mit der Tab Taste durchschalte.

    Theoretisch müsste ich ja hierzu die aktive Textbox Klassenweit speichern, angefangen mit der ersten "Kunden", um diese dann entsprechend zu beschreiben.
    Das wäre ja nicht das Problem, denn das kann ich ja über das Enter Event der Textbox lösen.
    Wie aber realisiere ich dies, bei meinen dynamisch erstellten Textboxen?


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim TBList As New List(Of Control)
    2. Private Sub DrawControls()
    3. 'Anzahl der Warengruppen ermitteln
    4. Dim GroupCount As Integer
    5. GroupCount = DtsSettings.ProductGroup.Count
    6. 'abbrechen, wenn es keine Warengruppen gibt
    7. If GroupCount = 0 Then
    8. MessageBox.Show("Eitragen nicht möglich. - keine Warengruppen gespeichert.")
    9. Me.Close()
    10. Exit Sub
    11. End If
    12. Dim GroupName As String
    13. Dim yPosition As Integer = 190
    14. Dim xPosition As Integer = 12
    15. 'Controls für jede Warengruppe erzeugen
    16. For i = 1 To GroupCount
    17. 'Name aus BindingSource lesen
    18. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i - 1), DataRowView).Row, DtsSettings.ProductGroupRow)
    19. GroupName = ProductGroup.Name
    20. 'Label
    21. Dim NewLBL = New System.Windows.Forms.Label
    22. With NewLBL
    23. .Location = New System.Drawing.Point(xPosition, yPosition)
    24. .Font = New Font("Microsoft Sans Serif", 12)
    25. .TextAlign = ContentAlignment.MiddleCenter
    26. .Name = "LBL " & GroupName
    27. .Size = New System.Drawing.Size(200, 20)
    28. .Text = GroupName
    29. .Visible = True
    30. End With
    31. 'TextBox
    32. Dim newTB = New System.Windows.Forms.TextBox
    33. With newTB
    34. .Location = New System.Drawing.Point(xPosition, yPosition + 23)
    35. .Font = New Font("Microsoft Sans Serif", 12)
    36. .Name = "TB " & GroupName
    37. .Size = New System.Drawing.Size(200, 26)
    38. .TabIndex = i
    39. .Visible = True
    40. AddHandler .TextChanged, AddressOf TextChangeEvent
    41. End With
    42. TBList.Add(newTB)
    43. 'Controls auf die Form malen
    44. Me.Controls.Add(NewLBL)
    45. Me.Controls.Add(newTB)
    46. 'Position für nächste Controls anpassen
    47. xPosition += 250
    48. If xPosition > 532 Then
    49. xPosition = 12
    50. yPosition += 70
    51. End If
    52. Next
    53. 'Höhe der Form anpassen
    54. If xPosition = 12 Then yPosition -= 70 'y verkleinern, wenn WG durch 3 teilbar ist, sonst zu groß
    55. Me.Height = yPosition + 140
    56. End Sub


    Das hier wäre mein Ansatz für die codeerstellte Textbox "kunden":

    VB.NET-Quellcode

    1. Dim SelectedBox As TextBox
    2. Private Sub TBCustomers_Enter(sender As Object, e As EventArgs) Handles TBCustomers.Enter
    3. Dim EnteredBox = DirectCast(sender, TextBox)
    4. SelectedBox = EnteredBox
    5. End Sub
    6. Private Sub NumBUtton_Click(sender As Object, e As EventArgs) Handles BTN9.Click, BTN8.Click, BTN7.Click, BTN6.Click, BTN5.Click, BTN4.Click, BTN3.Click, BTN2.Click, BTN1.Click, BTN0.Click
    7. Dim pressedbutton = DirectCast(sender, Button)
    8. SelectedBox.Text &= pressedbutton.Text
    9. End Sub


    Nun kann ich ja auch ein Enter Event mit gleichem Inhalt für meine per Code erstellten Textboxen erstellen, aber das bekomme ich ja nicht ausgelöst.
    Bilder
    • Unbenannt.jpg

      218,87 kB, 1.920×1.080, 76 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DerSmurf“ ()

    Du hast doch alle TextBoxen in Deiner TBList. Lass einfach ne Zählvariable bei 0 (Null) beginnen. Dann weiß Dein Programm, dass die erste TextBox den Input bekommt. Wenn Du Enter drückst, wird die Zählvariable um 1 erhöht und dann wird die nächste TextBox beschrieben. Für den Anfang:

    VB.NET-Quellcode

    1. Dim CurrentTextBoxIndex = 0
    2. '…
    3. Private Sub NumBUtton_Click(sender As Object, e As EventArgs) Handles BTN9.Click, BTN8.Click, BTN7.Click, BTN6.Click, BTN5.Click, BTN4.Click, BTN3.Click, BTN2.Click, BTN1.Click, BTN0.Click
    4. If CurrentTextBoxIndex > TBList.Count - 1 Then Return
    5. Dim pressedbutton = DirectCast(sender, Button)
    6. TBList(CurrentTextBoxIndex).Text &= pressedbutton.Text
    7. End Sub
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @DerSmurf Ist es da nicht einfacher, mit nem DataGridView zu arbeiten?
    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).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VaporiZed
    hmm, wenn ich deine Lösungsvorshläge so sehe, wirkt das immer so einfach - ich hoffe ich komme auch mal an den Punkt.
    Denn hierauf hätte ich ja alleine kommen können.
    Aber wurscht - danke erstmal :o)

    Dann sieht mein Fahrplan wie folgt aus:
    Der CurrentTextBoxIndex startet bei -1 und
    ​ If CurrentTextBoxIndex > TBList.Count - 1 Then 'TBKunden beschreiben
    Wenn CurrentTextBoxIndex größer als TBList.Count -1 dann Enter markieren.
    Dann noch eine Abfrage mit dem Index ob Enter markiert ist - ich denke hier werde ich einfach einen negativen Wert einsetzen, wenn CurrentTextBoxIndex größer als TBList.Count -1, in der vorherigen Prüfung - dann den speicher Code hinterm Button ausführen.

    Dann werde ich noch per Code TextBox Enter Events erstellen, denn wenn mein Index 3 ist und ich in eine Box vorher klicke (weil ich was falsches eingetragen habe), wurde mein Enter Button ja zwei nach vorne springen.
    Also für jede TextBox ein Enter Event, in der CurrentTextBoxIndex entsprechend beschrieben wird.
    Hier muss ich mal schauen, ob ich bei einer "EventSub" einen Parameter übergeben kann, denn ich bräuchte ja die Zählvariable i, um im Enter Event entsprechend ​CurrentTBIndex = i auszuführen.
    Wenn das nicht geht muss ich mir mit einer Klassenweiten Hilfsvariablen helfen (j = i)

    @RodFromGermany
    Ja, ich glaube ein DGV wäre sehr viel einfacher.
    Aber aus optischen Gründen, habe ich mich für die Boxen entschieden.
    Soho. Läuft alles.
    Das einzige was denke ich ein wenig doof ist, ist dass ich im Enter Event der codeerzeugten Textboxen den TabIndex hernehme.
    Aber hier wusste ich mir nicht anders zu helfen.
    Generell tut der Code exakt was er soll, ich denke auch mal was ich hier zusammengetippt habe, ist auch nicht so schlecht.
    Einzig das Verhalten zum beschreiben einer bereits gefüllten Textbox (also ich springe von TB2 durch "Enter" Button in TB3 und da steht schon was) ändere ich glaub ich noch.
    Es wird ja immer hinten angefügt - ich glaube ein Ersetzen wäre schöner. Aber das wird die Praxis zeigen.

    Hier die relevanten Codeteile:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Controls für jede Warengruppe erzeugen
    2. For i = 1 To GroupCount
    3. 'Name aus BindingSource lesen
    4. Dim ProductGroup = DirectCast(DirectCast(ProductGroupBindingSource(i - 1), DataRowView).Row, DtsSettings.ProductGroupRow)
    5. GroupName = ProductGroup.Name
    6. 'Label
    7. Dim NewLBL = New System.Windows.Forms.Label
    8. With NewLBL
    9. .Location = New System.Drawing.Point(xPosition, yPosition)
    10. .Font = New Font("Microsoft Sans Serif", 12)
    11. .TextAlign = ContentAlignment.MiddleCenter
    12. .Name = "LBL " & GroupName
    13. .Size = New System.Drawing.Size(200, 20)
    14. .Text = GroupName
    15. .Visible = True
    16. End With
    17. 'TextBox
    18. Dim newTB = New System.Windows.Forms.TextBox
    19. With newTB
    20. .Location = New System.Drawing.Point(xPosition, yPosition + 23)
    21. .Font = New Font("Microsoft Sans Serif", 12)
    22. .Name = "TB " & GroupName
    23. .Size = New System.Drawing.Size(200, 26)
    24. .TabIndex = i
    25. .Visible = True
    26. AddHandler .TextChanged, AddressOf TextChangeEvent
    27. AddHandler .Enter, AddressOf TextBox_Enter
    28. End With
    29. TBList.Add(newTB)
    30. 'Controls auf die Form malen
    31. Me.Controls.Add(NewLBL)
    32. Me.Controls.Add(newTB)
    33. 'Position für nächste Controls anpassen
    34. xPosition += 250
    35. If xPosition > 532 Then
    36. xPosition = 12
    37. yPosition += 70
    38. End If
    39. Next
    40. 'Höhe der Form anpassen
    41. If xPosition = 12 Then yPosition -= 70 'y verkleinern, wenn WG durch 3 teilbar ist, sonst zu groß
    42. Me.Height = yPosition + 140[/spoiler][spoiler]


    VB.NET-Quellcode

    1. 'Enter Event für code erzeugte Textboxen
    2. Private Sub TextBox_Enter(sender As Object, e As EventArgs)
    3. Dim SelectedTextBox = DirectCast(sender, TextBox)
    4. CurrentTextBoxIndex = SelectedTextBox.TabIndex - 1 'Tab Index -1, da Beginn mit 1 / aber Rest 0 basiert
    5. End Sub
    6. 'Enter Event für TB Kunden
    7. Private Sub TBCustomers_Enter(sender As Object, e As EventArgs) Handles TBCustomers.Enter
    8. CurrentTextBoxIndex = -1
    9. End Sub
    10. 'Button Zahl auf Numpad
    11. Private Sub NumBUtton_Click(sender As Object, e As EventArgs) Handles BTN9.Click, BTN8.Click, BTN7.Click, BTN6.Click, BTN5.Click, BTN4.Click, BTN3.Click, BTN2.Click, BTN1.Click, BTN0.Click
    12. Dim pressedbutton = DirectCast(sender, Button)
    13. 'TBIndex = -1 = TBCustomers
    14. If CurrentTextBoxIndex = -1 Then
    15. TBCustomers.Text &= pressedbutton.Text
    16. Else
    17. 'sonst - Abfrage, ob Einnahme TB beschrieben wird
    18. If TBList.Count > CurrentTextBoxIndex Then TBList(CurrentTextBoxIndex).Text &= pressedbutton.Text
    19. End If
    20. End Sub
    21. 'Button Komma auf NumPad
    22. Private Sub BTNKomma_Click(sender As Object, e As EventArgs) Handles BTNKomma.Click
    23. If CurrentTextBoxIndex = -1 Then Return
    24. If Not TBList(CurrentTextBoxIndex).Text.Contains(",") Then TBList(CurrentTextBoxIndex).Text &= ","
    25. End Sub
    26. 'Button Enter auf NumPad
    27. Private Sub BTNEnter_Click(sender As Object, e As EventArgs) Handles BTNEnter.Click
    28. CurrentTextBoxIndex += 1
    29. If TBList.Count > CurrentTextBoxIndex Then
    30. TBList(CurrentTextBoxIndex).Select()
    31. Else
    32. 'wenn TBListCount = TBIndex, dann letzte Box + Enter = speichern markieren
    33. If TBList.Count = CurrentTextBoxIndex Then
    34. BTNSave.Select()
    35. Else
    36. 'sonst (TBList.Count < TBIndex) speichern Code ausführen
    37. SaveIncome()
    38. End If
    39. End If
    40. End Sub
    41. 'Button Backslash auf NumPad
    42. Private Sub BTNBackslash_Click(sender As Object, e As EventArgs) Handles BTNBackslash.Click
    43. 'TBIndex = -1 = TBCustomers
    44. If CurrentTextBoxIndex = -1 Then
    45. If TBCustomers.Text.Length > 0 Then TBCustomers.Text = (TBCustomers.Text.Substring(0, TBCustomers.Text.Length - 1))
    46. Else
    47. 'sonst - Abfrage, ob Einnahme TB beschrieben wird
    48. If TBList.Count > CurrentTextBoxIndex Then
    49. If TBList(CurrentTextBoxIndex).Text.Length > 0 Then TBList(CurrentTextBoxIndex).Text = (TBList(CurrentTextBoxIndex).Text.Substring(0, TBList(CurrentTextBoxIndex).Text.Length - 1))
    50. End If
    51. End If
    52. End Sub

    VB.NET-Quellcode

    1. Private Sub TextBox_Enter(sender As Object, e As EventArgs)
    2. Dim SelectedTextBox = DirectCast(sender, TextBox)
    3. CurrentTextBoxIndex = SelectedTextBox.TabIndex - 1 'Tab Index -1, da Beginn mit 1 / aber Rest 0 basiert
    4. End Sub

    Mach doch ne normale For-Schleife über die TBList. Und wenn TBList(i) Is sender, dann ist CurrentTextBoxIndex = i
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Danke!

    VB.NET-Quellcode

    1. Private Sub TextBox_Enter(sender As Object, e As EventArgs)
    2. Dim SelectedTextBox = DirectCast(sender, TextBox)
    3. For i = 0 To TBList.Count - 1
    4. If TBList(i) Is SelectedTextBox Then CurrentTextBoxIndex = i
    5. Next
    6. End Sub