0

From a previous post I learned a way to populate a userform with a grid of textboxes:

Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox

Private Sub UserForm_Initialize()

Dim x As Long
Dim y As Long

For x = 1 To 10
    For y = 1 To 5
        Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
        With Grid(x, y)
            .Name = "TextBox_" & x & "_" & y
            .Width = 50
            .Height = 20
            .Left = y * .Width
            .Top = x * .Height
            .SpecialEffect = fmSpecialEffectFlat
            .BorderStyle = fmBorderStyleSingle
        End With
    Next y
Next x

End Sub

Now, I need to run certain code when I change the contents of any textbox in columns 5 and 6. But since the textbox won't exist until after Initialize is run, their Change events don't exist either.

So I need to either:

  • Write the change events in advance, since I know the names of the textboxes in advance.
  • Use an event that will trigger whenever I click any textbox, and be able to identify the textbox in question.

If the only way to do this is by using a class module, please explain it carefully, since I've never actually used one.

EDIT: The answers from @TinMan and @Storax work a little too well. The code reacts to every keystroke in the textbox, but I really need to wait until the user is finished typing. There's no "Exit" event for the textbox when it's in the class module. Any thoughts?

Shawn V. Wilson
  • 1,002
  • 3
  • 17
  • 42
  • 2
    From my comment on your previous post: https://bettersolutions.com/excel/macros/vba-control-arrays.htm There are plenty of articles out there which "explain it carefully" (Google on "VBA control array"), so please try reviewing some of those first, then if you need clarifications post back here with the code you're trying. – Tim Williams Mar 17 '22 at 18:54
  • Sorry, those articles didn't give me a good idea of where to start. The answers below where much more helpful. – Shawn V. Wilson Mar 19 '22 at 15:18

2 Answers2

3

You'll need to create a class to listen for the changes.

Class: TextBoxListener

Public WithEvents TextBox As MSForms.TextBox
Public UserForm As Object

Private Sub TextBox_Change()
    UserForm.TextBoxGridChange TextBox
End Sub

Userform

With a few modifications you can use the Grid() to hold the TextBoxListeners references.

Option Explicit
Private Grid(1 To 10, 1 To 5) As New TextBoxListener

Public Sub TextBoxGridChange(TextBox As MSForms.TextBox)
    Debug.Print TextBox.Value
End Sub

Private Sub UserForm_Initialize()
    
    Dim x As Long
    Dim y As Long

    For x = 1 To 10
        For y = 1 To 5
            With Grid(x, y)
                Set .TextBox = Me.Controls.Add("Forms.Textbox.1")
                Set .UserForm = Me
                With .TextBox
                    .Name = "TextBox_" & x & "_" & y
                    .Width = 50
                    .Height = 20
                    .Left = y * .Width
                    .Top = x * .Height
                    .SpecialEffect = fmSpecialEffectFlat
                    .BorderStyle = fmBorderStyleSingle
                End With
            End With
        Next y
    Next x
    
End Sub

Class Listener Demo

TinMan
  • 6,624
  • 2
  • 10
  • 20
  • The line `Private Grid(1 To 10, 1 To 5) As New TextBoxListener` gives me the error "User-defined type not defined." – Shawn V. Wilson Mar 17 '22 at 20:33
  • I'm not sure where the lines beginning with "Option Explicit" are supposed to go -- in the class module, or a regular module, or the userform module? – Shawn V. Wilson Mar 17 '22 at 20:34
  • @ShawnV.Wilson This will help [workbook example](https://docs.google.com/spreadsheets/d/18pDOMo03SWDkH-9HyfWk-5mtKWe8UY45/edit?usp=sharing&ouid=114888086960932662321&rtpof=true&sd=true) – TinMan Mar 17 '22 at 20:52
  • @ShawnV.Wilson [How to use Option Explicit Statement in VBA](https://excelchamps.com/vba/option-explicit/) – TinMan Mar 17 '22 at 20:54
  • Thanks, but there were errors in your workbook. The "Option Explicit" and "Private Grid" lines have to be at the top. (Even I knew that.) After I fixed that and ran the form, 'UserForm.TextBoxGridChange TextBox' gave the error "Object doesn't support this property or method" – Shawn V. Wilson Mar 17 '22 at 21:17
  • @ShawnV.Wilson My post was screwed up. I fixed it too. – TinMan Mar 17 '22 at 21:31
  • 1
    Thanks. Also, the reason I got the "Object doesn't support...." error is that I needed to rename the class module from "Class1" to "TextBoxListener" – Shawn V. Wilson Mar 18 '22 at 17:07
1

Just a simple example how the class could look like for the textboxes. I named the class clsTextBoxes

Option Explicit

Public WithEvents tb As MSForms.TextBox
' just to keep track of the box in the grid
Public x As Long
Public y As Long

' Just a simple example for the change event.
' you could  use x and y to tell the different textboxes apart
Private Sub tb_Change()
    Debug.Print tb.Text, x, y
End Sub

You have to adjust your code in the userform like that

Option Explicit

Dim Grid(1 To 10, 1 To 5) As MSForms.TextBox

' Collection to save all the textboxes in the grid
Dim colTxt As New Collection

Private Sub UserForm_Initialize()

Dim x As Long
Dim y As Long
Dim cTxt As clsTextBoxes

For x = 1 To 10
    For y = 1 To 5
        Set Grid(x, y) = Me.Controls.Add("Forms.Textbox.1")
        
        ' create an new clsTextBoxes
        Set cTxt = New clsTextBoxes
        ' save a pointer to the just created textbox
        Set cTxt.tb = Grid(x, y)
        ' store the postion
        cTxt.x = x
        cTxt.y = y
        ' add it to the collection
        colTxt.Add cTxt
        
        With Grid(x, y)
            .Name = "TextBox_" & x & "_" & y
            .Width = 50
            .Height = 20
            .Left = y * .Width
            .Top = x * .Height
            .SpecialEffect = fmSpecialEffectFlat
            .BorderStyle = fmBorderStyleSingle
        End With
    Next y
Next x

End Sub

Look at the comments for a short explanation

Storax
  • 11,158
  • 3
  • 16
  • 33
  • The line `Dim cTxt As clsTextBoxes` gives me the error "User-defined type not defined" like the other answer. There's something I'm really missing. – Shawn V. Wilson Mar 17 '22 at 20:48
  • You have to create a class with the name `clsTextBoxes`. In the other answer you have to create a class with the name `TextBoxListener`. [Here](https://excelmacromastery.com/vba-class-modules/#Creating_a_Simple_Class_Module) is an explanation how to do that. – Storax Mar 17 '22 at 20:49
  • I see - I had the class modules, but I left them called "Class1" – Shawn V. Wilson Mar 17 '22 at 21:25
  • @ShawnV.Wilson Sorry about that. I updated the workbook. – TinMan Mar 17 '22 at 21:30