Reputation: 3198
For VBA (in my case, MS Excel), the Public
declaration is supposed to make the variable (or function) globally accessible by other functions or subroutines in that module, as well as in any other module.
This is not true, in the case of Forms
, and I suspect also in Sheets
, but I haven't verified the latter.
The following will not create a public, accessible variable when created in a Form
, and will therefore crash, saying that the bYesNo and dRate variables are undefined in mModule1:
'(inside fMyForm)
Public bYesNo As Boolean`
Public dRate As Double
Private Sub SetVals()
bYesNo = Me.cbShouldIHaveADrink.value
dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
'(Presume the textbox & checkbox are defined in the form)
'(inside mModule1)
Private Sub PrintVals()
Debug.Print CStr(bYesNo)
Debug.Print CStr(dRate)
End Sub
If you make the alteration below, it all will work:
'(inside fMyForm)
Private Sub SetVals()
bYesNo = Me.cbShouldIHaveADrink.value
dRate = CDec(Me.tbHowManyPerHour.value)
End Sub
'(Presume the textbox & checkbox are defined in the form)
'(inside mModule1)
Public bYesNo As Boolean
Public dRate As Double
Private Sub PrintVals()
Debug.Print CStr(bYesNo)
Debug.Print CStr(dRate)
End Sub
mModule1
will work and, assuming that the fMyForm is always called first, then by the time the PrintVals
routine is run, the values from the textbox and checkbox in the form will be captured.
Upvotes: 12
Views: 42054
Reputation: 21
There are other limitations to Public within Excel VBA. MSoft documentation in learn.microsoft.com states that public variables are global to the VBA project - it's not true. Public variables are only global to the workbook within which they are declared, and then only across standard modules. Public variables declared within workbook code are not visible in standard modules, even though standard module sub's are - which are defined to be public. Public variables declared in one workbook's standard modules are certainly not accessible from other workbooks in the same VBA project, contrary to the MSoft documentation.
Upvotes: 0
Reputation: 1617
As a quick add-on answer to the community answer, just for a heads-up:
When you instantiate your forms, you can use the form object itself, or you can create a new instance of the form object by using New and putting it in a variable. The latter method is cleaner IMO, since this makes the usage less singleton-ish.
However, when in your userform you Call Unload(Me), all public members will be wiped clean. So, if your code goes like this:
Dim oForm as frmWhatever
Set oForm = New frmWhatever
Call oForm.Show(vbModal)
If Not oForm.bCancelled Then ' <- poof - bCancelled is wiped clean at this point
The solution I use to prevent this, and it is a nice alternative solution for the OP as well, is to capture all IO with the form (i.e. all public members) into a separate class, and use an instance of that class to communicate with the form. So, e.g.
Dim oFormResult As CWhateverResult
Set oFormResult = New CWhateverResult
Dim oForm as frmWhatever
Set oForm = New frmWhatever
Call oForm.Initialize(oFormResult)
Call oForm.Show(vbModal)
If Not oFormResult.bCancelled Then ' <- safe
Upvotes: 2
Reputation: 38
First comment:
Userform and Sheet modules are Object modules: they don't behave the same way as a regular module. You can however refer to a variable in a userform in a similar way to how you'd refer to a class property. In your example referring to fMyForm.bYesNo would work fine. If you'd not declared bYesNo as Public it wouldn't be visible to code outside of the form, so when you make it Public it really is different from non-Public. – Tim Williams Apr 11 '13 at 21:39
is actually a correct answer...
Upvotes: 7