Why does my function's name appear twice in the "locals" window? - vba

I have created a Class Module in which I have defined a function. Whenever that function is called, it is listed twice in the locals window. Only the second one's value changes, the first one stays either empty or "zero", depending on its type, until the end of the code's execution. I don't have this problem with functions defined in standard modules. Did I do something wrong, is this a bug, or is there a logical reason behind this?
Contents of the TestClass class module:
Public Value As Double
Function AddFive() As Double
AddFive = Me.Value + 5
End Function
Contents of the standard module:
Sub TestSub()
Dim TestObject As New TestClass
TestObject.Value = 2
MsgBox TestObject.AddFive
End Sub
Here is a screenshot showing that, when the code is executed line-by-line, the function's value is listed twice in the locals window, and only the second value has changed after the function's code was executed.
(link to screenshot)
I'm using VBA for Excel 2010.
Thanks in advance.

The issue is more in how you are doing it. If you have a function that just adds 5 to an internal variable of a class object, then it's technically a void (Sub in VBA) since you don't need a return value.
Your code should be:
CLASS
Public Value As Double
Sub AddFive()
Me.Value = Me.Value + 5
End Sub
MODULE
Sub test()
Dim testObject As New TestClass
testObject.Value = 2
testObject.AddFive
MsgBox testObject.Value
End Sub
I can imagine there could be a number of reasons why there are 2 variables created, but I find it a bit pointless to go into why there is unexpected behavior since you are doing improper code.
If you want, you can even write class function that will show it's value + 5 in a msgbox and this would not create an extra variable either. But that is strange and I think you want the code above. But here it is regardless:
CLASS
Public Value As Double
Sub ShowPlusFive()
MsgBox Me.Value + 5
End Sub
MODULE
Sub test()
Dim testObject As New TestClass
testObject.Value = 2
testObject.ShowPlusFive
End Sub

Related

Set a Property Value From Database of Properties

My database has the formname, control, and control property type value stored.
I would like to have a line of code like this.
Forms(i%).Controls(ControlName$)).controlpropertytype$ = NewValue
I am currently using a select case structure to handle the various property types. It would be much simpler to have a single statement take care of it.
Using a helper function, you can achieve this with one line of code. Here's an example of setting a TextBox on Form1 to the value 'aaa':
Option Explicit
Private Sub Test()
CallByName FindForm("Form1").Controls("Text1"), "Text", VbLet, "aaa"
End Sub
Public Function FindForm(ByVal Name As String) As Form
Dim f As Form
For Each f In Forms
If UCase(f.Name) = UCase(Name) Then
Set FindForm = f
Exit Function
End If
Next
End Function
While this is an interesting exercise, I would not recommend this approach. It assumes the form and the control can both be found, but if they can't be found this one-liner will crash your app.
Here's documentation for CallByName.

Can you put VBA code in a bare module, outside of Function or Sub?

I'm trying to keep a Collection Class of Classes persistent while a Userform is running so that the form objects they create can still have event handlers.
But if I create any classes for these in subs or functions, their respective classes and event handlers would be cleared at the end of whatever subroutine created it.
I should specify that user input determines how many classes there will be, so I can't just hard code the event handlers into the userform module.
You can use a publicly declared dictionary to hold instances of your class that will be available to your project. You declare variables outside of a function or sub and declare them as Public for other modules and their subs/functions to be able to use them. They stay resident in memory between calls while the application is open.
Consider a class called c_gumball:
Public color As String
Public diameterInches As Double
Public Function getSize(unit As String) As Double
Select Case unit
Case "mm"
getSize = diameterInches * 25.4
Case "cm"
getSize = diameterInches * 2.54
Case "yd"
getSize = diameterInches / 36
End Select
End Function
And then a new module called m_gbmachine:
Public gumballMachine As Dictionary
Public Sub createGumbalMachine()
gumballMachine = New Dictionary
End Sub
Public Sub addGumball(color As String, sizeInInches As Double, nameKey As String)
Dim gb As c_gumball
Set gb = New c_gumball
gb.color = "green"
gb.diameterInches = 1.2
gumballMachine.Add Key = nameKey, gb
End Sub
Public Sub removeGumball(nameKey As String)
gumballMachine.Remove (nameKey)
End Sub
Any module can now use m_gbmachine.gumballMachine dictionary and see what's in it. They can add gumballs using it's functions.
Perhaps in your userform you create a gumball called "gumball2" in your dictioanry and then want to get the color property of "gumball2" in the gumballMachine dictionary, you could do:
Public Sub button_Click()
'add gumball 2 to the machine
m_gbmachine.addGumball "green", 1.2, "gumball2"
End Sub
Public Sub someFormRoutine()
'msgbox the color of gumball 2
MsgBox m_gbmachine.gumballMachine("gumball2").color
End Sub
You can go deeper and change this module over to a class of it's own and have many gumball machine instances as well.

Global variables not working on excel vba

I'm trying to use global variables in a excel macro I'm creating, but i can't get them to work. I wrote te following code:
Public globalVar As Integer
Public Sub TestGlobal()
SetGlobalVar
GetGlobalVar
End Sub
Public Sub SetGlobalVar()
globalVar = 5
End Sub
Public Sub GetGlobalVar()
Debug.Print "globalVar = "
Debug.Print globalVar
End Sub
I expected this code to show globalVar = 5, but it's showing globalVar =, and when I put the mouse over the globalVar variable in SetGlobalVar it shows "5", but when I do that on GetGlobalVar, it shows "Empty".
What am I doing wrong? Shouldn't the value be the same, since the variable is global?
When i run the code it works, just to check you are declaring the public variable at the top of the module and not after another sub?
Your Immediate Window may not be high enough.
Based on Coleman's suggestion:

Getting 'SubScript Out of Range' Error in VBA when calling class Method

I'm going to try to lay out this issue in as much detail as possible. Apparently I can't post images, as I am a New Member...So I will try to describe my situation as good as I possibly can.
So, I am working with a custom class called "Shifts". I have this class declared and set up in a Class Module in VBA. I declare an instance of the "Shifts" class inside a normal Module and call it "Shift".
Dim Shift As New Shifts
My "Shifts" class has 4 variables (String Arrays):
Private ShiftMembers() As String
Private ShiftCallSigns() As String
Private ShiftAssignments() As String
Private ShiftStatuses() As String
I have written a Sub within the class called "Clear" to clear the data in these variables (via ReDim):
Public Sub Clear()
ReDim ShiftMembers(-1) As String
ReDim ShiftCallSigns(-1) As String
ReDim ShiftAssignments(-1) As String
ReDim ShiftStatuses(-1) As String
End Sub
Now, when I call the Clear Sub of the "Shifts" class (declared as "Shift"):
Shift.Clear 'This is called from within the Module.
i get Subscript out of range (Error 9). My class is declared at the very top of the module, outside of any methods or functions. The Clear() sub within my class is declared Public. I don't understand why I can't seem to access my Clear Sub properly.
Any help would be greatly appreciated!
-Rob
I don't know if you can use ReDim that way. From the documentation, the subscripts argument is bound by the Option Base statement:
subscripts
Required
Dimensions of an array variable; up to 60 multiple dimensions may be declared. The subscripts argument uses the following syntax: [lower To] upper [,[lower To] upper] . . . When not explicitly stated in lower, the lower bound of an array is controlled by the Option Base statement. The lower bound is zero if no Option Base statement is present.
The Option Base statement must be either 1 or 0, and -1 is out of bounds, so the error makes sense.
In order to clear your arrays use the Erase command instead of ReDim.
I put this in my class module (I use the _Initialize procedure just to make one of the array's non-empty, in order to verify that Erase did its job):
Private ShiftMembers() As String
Private ShiftCallSigns() As String
Private ShiftAssignments() As String
Private ShiftStatuses() As String
Sub Class_Initialize()
ReDim ShiftMembers(1 To 2)
End Sub
Public Sub Clear()
Erase ShiftMembers
Erase ShiftCallSigns
Erase ShiftAssignments
Erase ShiftStatuses
End Sub
I use the following to test:
Sub t()
Dim s As New Shift
s.Clear
End Sub

Why does Intellisense not work for Default Public Property (sometimes)?

I've had problems with default properties in my code that I can - at least to some extent - reproduce with the following code:
Public Class Dawg
Public Enum DawgEnum
Demo1
Demo2
End Enum
Default Public Property DawgProp(x As DawgEnum) As String
Get
Return "whatever"
End Get
Set(value As String)
'...
End Set
End Property
Public Sub DawgSub()
Me(DawgEnum.Demo1) = "Intellisense works here..."
End Sub
End Class
Public Class DawgTest
Public Sub SomeSub()
Dim d As New Dawg
d(Dawg.DawgEnum.Demo1) = "And here as well..."
End Sub
Public Shared Sub AnotherSub()
Dim d As New Dawg
d(Dawg.DawgEnum.Demo1) = "No help for finding 'Dawg.DawgEnum.Demo1' here..."
d.DawgProp(Dawg.DawgEnum.Demo1) = "...Intellisense helped here..."
End Sub
End Class
The problem being that within the "Shared Sub AnotherSub" when I start typing "d(" Intellisense does not offer me the list of available Enum values for the property.
I also have the problem in other classes that structurally are identical to the class "DawgTest" (a simple public class) where it doesn't work either (within a shared sub or not) - although there are no problems in the test above.
Of course, this isn't a major problem since the code compiles fine and I can always use the explicit property, but it's very annoying and confusing and just like to know, if this is by-design? And, if so: why? If not: how can I fix it?
I can't for sure say, if this problem has been there all along or, if it just came up out of nowhere...
Any thoughts - even 5 cents or less - on the issue would be greatly appreciated :o)