Search code examples
excelvbatextboxuserform

How can I get a reference to a TextBox itself instead of to its default value in Excel vba?


Windows 10 Pro 64, Office 365 Excel vba

ClassCounter is a class that operates on a Long value it stores internally and then displays that value in a TextBox in an active UserForm. I want to be able to assign the TextBox to the ClassCounter object dynamically, so that I can use the same class to instantiate a number of objects, each of which references its own TextBox in the same UserForm.

It has the following private members declared at the class level:

Private mctrLinked As ClassCounter
Private mnCount As Long
Private mtbxDisplay As TextBox

The Initialize subroutine makes the connection between displayTextBox (the textbox used to display the value) and the object. linkCounter provides the opportunity to link to another object of the same class and fire off the same operation on it in a daisychain fashion.

Public Sub Initialize(ByRef displayTextBox As msforms.TextBox, Optional linkCounter As ClassCounter = Nothing)
    Const kstrMethodName As String = "Initialize"

    Set mtbxDisplay = displayTextBox
    Set mctrLinked = linkCounter
    Clear
End Sub ' Initialize

The class is instantiated in another class, as follows:

Private mobjAllBlankCounter As New ClassCounter
Private mobjAllEnteredCounter As New ClassCounter
Private mobjAllFoundCounter As New ClassCounter
Private mobjAllIssuesCounter As New ClassCounter
...

And the connection between the TextBox and the ClassCounter object is established by calling the Initialize subroutine in this way:

Public Sub InitializeAllCounters()
    With mufMCP
        mobjAllBlankCounter.Initialize .tbxBlankCountAll
        mobjAllEnteredCounter.Initialize .tbxEnteredCountAll
        mobjAllFoundCounter.Initialize .tbxFoundCountAll
        mobjAllIssuesCounter.Initialize .tbxIssuesCountAll
    End With
End Sub ' InitializeAllCounters

where mufMCP is the UserForm in which the TextBoxes are defined.

Ultimately, the Increment function (and others like it) will operate on the stored variable and then display it in the referenced TextBox as follows:

Public Sub Increment()
    Const kstrMethodName As String = "Increment"

    If (mtbxDisplay Is Nothing) Then
        Err.Raise gknErrNoControlForCounter, mkstrModuleName & "." & kstrMethodName, "Attempt to Increment Counter with no associated control."
    Else
        mnCount = mnCount + 1
        mtbxDisplay.Text = CStr(mnCount)
        If (Not (mctrLinked Is Nothing)) Then
            mctrLinked.Increment
        End If
    End If
End Sub ' Increment

The problem I'm having is in the Initialize subroutine where I attempt to assign the value of the TextBox argument to the local variable. Instead of assigning a reference to the TextBox itself, the right side of the assignment is evaluating to the TextBox's default value, which is its Text property. As a result, I get a type mismatch error.

How can I get it to evaluate to a reference to the TextBox itself? I've spent a couple of days searching for the answer and found several sources that said that using ByRef displayTextBox As msforms.TextBox to define the parameter would do the trick, but I'm still getting the control's default value.


Solution

  • As FaneDuru writes, TextBox and MsForms.TextBox are two different object types. A TextBox is a textbox (Form Control, not Active X Control) placed on a sheet. A MsForms.TextBox is a textbox places on a user form.

    Bad thing (1): The name "Form Control" related to sheet controls is misleading, it is not the same as a control placed on a user form.

    Bad thing (2): As the Form Control Textbox is no longer available from the Developer menu, it is not easy to proof. If you are interested: You can still create them using VBA.

    Dim tb1 As TextBox
    Set tb1 = ActiveSheet.TextBoxes.Add(255, 243, 73.5, 22.5)
    Dim tb2 As msforms.TextBox
    UserForm1.Show False
    Set tb2 = UserForm1.TextBox1
    

    Checking both objects in the Locals window of the VBA editor, type for both is displayed as "Textbox/Textbox". However, when you look at the properties of the objects, you see that they are different.

    So declare all your (userform) controls with the suffix msforms to be sure that you are dealing with the right object types.