Access Global not working - vba

I have a Global Variable called EmployeeID. I set this by calling a function:
Global EmployeeID As Integer
Public Sub init_Globals(emp As Integer)
EmployeeID = emp
End Sub
On the main form, I used:
MsgBox EmployeeID
from a button and it works just fine; but the funny thing is when I use this from a subform it returns a 0:
I might add that this is a Continuous Form as well.
Private Sub cboWhichDate_AfterUpdate()
Me.txtEmployee = EmployeeID
End Sub

A "global" variable can only be "global" if its scope is global. Sticking a Global access modifier to a field declared in a class module doesn't make it global.
In fact, the Global keyword is deprecated, and is completely replaced/superseded by the Public access modifier.
What matters is the variable's scope. If that declaration is located in a class module (a form's code-behind is essentially a class module), then all you've done is declare a public instance field; you can only access the value via the object instance that owns it.
Dim MyObject As New MyForm
MyObject.EmployeeID = 42
MsgBox MyObject.EmployeeID
To make a global variable, add a standard module (.bas) to your project, and declare it there.
Public EmployeeID As Integer
Now everyone everywhere can access EmployeeID, because it's scoped to a module (i.e. not an instance of an object), and its accessibility is public.
That said, global variables are evil and can easily lead to unmaintainable spaghetti code; Consider passing values as parameters instead.

Related

Calling Public variable from userform

In a userform, I have this at the top:
Public DelMonth As Variant
The value of DelMonth is read from a ComboBox, and I can call it from different subroutines within that userform just fine. But when I call it from a separate module, it doesn't read it. It doesn't even throw an error. If I do a MsgBox DelMonth, it doesn't do anything.
A form is an object; a public field in an object module belongs to an instance of that object. UserForms are little more than class modules with a default instance (i.e. a VB_PredeclaredId = True attribute) and a designer.
If you're using the form's default instance (a rather bad idea), then you can do this:
MsgBox UserForm1.DelMonth
Note that storing state in global objects is bug-prone, and will end up causing issues.
If you're treating the form like the full-fledged class it is, then you'll have something like this:
With New UserForm1
.Show
MsgBox .DelMonth
End With
Note that the field being Public means anyone, anywhere can go and write to it. What you mean is for the form to determine its value, and for the caller to be able to read that value. You do this by encapsulating the field with a Property Get member - start by making the field Private:
Option Explicit
Private DelMonth As Variant ' wouldn't Integer or Long be more appropriate?
Public Property Get DeliveryMonth() As Long
DeliveryMonth = DelMonth
End Property
Now the callers don't get to see the private DelMonth, and all they can do with DeliveryMonth is call the Get accessor, which doesn't let them tamper with the encapsulated value.
It doesn't even throw an error.
That's worrying. You're allowing VBA to happily compile typos and otherwise illegal code. Specify Option Explicit at the top of every module. Always.

How to create a global function and pass variables to it in VBA Access?

In my program I am trying to cut down on repetitive code by putting it into global functions.
In my current setup I am calling the function like:
Call [Global variable].Close
(global variable is the name of the class module).
This function is looks like;
Public Function Close()
DoCmd.Close
Cancel = True
End Function
Unfortunately this wont compile properly. What am I doing wrong?? (As an aside I also want to pass variables to and from this function and want to know how this would be done).
Thanks for your help.
If you're using a class module, you need an instance of that module before you can call its members. That requires either creating the class module as pre-declared (which involves exporting the code, editing in Notepad, and re-importing), or creating an instance with the New keyword:
Dim myClassInstance As MyClass
Set myClassInstance = New MyClass
myClassInstance.Close
But, depending on your use-case, you might better off with the function being available in a standard module - then you can just call it from anywhere, including from within a query.

Make a global variable in Visual Basic for Applications

In VBA for Access, how do I make a global variable that I can access and change anywhere?
You can declare a variable at Global scope by declaring it in a Standard Module or a predeclared class module such as a Worksheet, UserForm or PreDeclared class, using the Public keyword:
Public myVar As String
You can also declare a Global variable using the now deprecated, but still valid Global syntax, which is functionally the same as Public
Global myVar As String
But note that declaring a variable with Public or Global will make the variable accessible across your entire project AND to any project that refers to that project, and even if your project is protected, a user could still query the variable from the Immediate window.
If you must have a variable that is available across your project, but only that project, then you should declare the variable in a standard module, and include an Option Private Module statement to make the module private to the project, but its variables as Public to the project only.
Option Private Module
Public myVar As String

Declare a "type" object globally

I want to pass objects between form modules.
I have made a simple database to explain the problem I am having.
I have two forms --> form1, form2 and one module --> Module1
Based on the threads I have read, I believe if I want to define a global object, it should be done in the module so I placed the declaration there;
Option Compare Database
Public Type Name
First As String
Last As String
Phone As String
End Type
On form1 I have a cmd button with the following code behind it;
Option Compare Database
Dim My_Name As Name
Private Sub cmd_Button_Click()
My_Name.First = "MyFirstName"
My_Name.Last = "MyLastName"
MsgBox ("In Form1 " & My_Name.Last)
DoCmd.OpenForm "Form2"
End Sub
on the second form I have;
Option Compare Database
Dim my_Name As Name
Private Sub Form_Load()
MsgBox (my_Name.First)
End Sub
In the first form, I see the my_Name object variable fine, when I pass control to the second form, I lose the variable.
I have tried a number of variations of Public, Static declarations all over the place on both the object variable and the sub's but I cannot figure out how to preserve the object across modules.
You are re-declaring my_name. So it is in -effect two different things. Like george forman and george forman.
I am sorry I can't be more help it's been like a a million years since I have had to deal with this. However, it seems that your 'froms' are actually declared in an 'module' like block -name from1. That from global scope you can reference a variable in your form1.
In this case form1.my_name. However, this can lead to issues if form1.my_name has not yet been instanciated.
My recommendation is to find the module with global scope ( I dont remember exactly what it is, if you have to create it or now, and when it gets life). Declare and initicialize your variables in it. Then access those from within you event handlers ("cmd_Button_Click" for example.)

Add Public Methods to a Userform Module in VBA

Is it possible to call a public sub located in a UserForm from a Class Module? I want to put a callback in the Form Module but I can't seem to get it to expose.
Is this a fundamental limitation of UserForms in VBA?
It is exposed inside the UserForm Code Module, I can see it in the intelisense for the Me object, but I can't seem to access it from outside the Form Module.
The real answer to my question is to have a better understanding of UserForms and since I could not find a good reference for that I thought I would answer my own question to share my learnings.
Thanks to #Dick Kusleika for the key insight!
First of all, this is not a UserForm:
It is no more a Form than a Class Module is a variable.
UserForm1 is a Class Module with a GUI and with the following default, inherited properties
These properties are like a standard Interface that is common to all Form Class Modules and therefore instances. The Name property is in parentheses because it is not the name of the object, it is the name of the the Type that is used to declare variables to instantiate the particular Form Class.
More properties and methods can be added by the user at design time and this is done in exactly the same way as a Class Module.
For example, in a Form Module...
Option Explicit
Dim mName As String
Property Let instName(n As String)
mName = n
End Property
Property Get instName() As String
If Len(mName) = 0 Then mName = Me.Name
instName = mName
End Property
In this example, the Form Class Name is used as the default Instance Name.
When you add Controls to the form, its like graphically adding
Public WithEvents controlName As MSForms.ControlType
...in a Class Module.
The Methods inherited in the standard interface include one called Show.
You can create an instance of a form using UserForm1.Show and this is very confusing and misleading. To me it implies that you are showing the Object called UserForm1 but you are not. I don't know why you would want to use this method because, apart from being confusing, it does not deliver any direct reference to the object created. Its a bit like Dim v as New Type only worse, because there is no referencing variable.
You can instantiate a Form Class in exactly the same way you can a Custom Class object and then use the show method to deploy it...
Dim f As UserForm1
Set f = New UserForm1
f.Show
For me, this is the preferred method.
You can add custom properties and controls to the UserForm1 Class and you can give it a meaningful name when creating it, but you can also reference it using the standard UserForm interface.
For example
'In a Class Module
Dim mForm as UserForm1
Property let Form(f as MSForms.UserForm)
Set mForm = f
End Property
For me, after understanding the above, all of my confusion about UserForms and my frustration at not being able to find a decent reference disappears. I just treat them as Class Modules and its fine.
The only difference between a Userform and Class Module is that a Userform has a UI element that a Class Module doesn't. So a Userform is just a special type of Class Module. That means that Public Subs inside a Userform behave just as they do in any other class - as a method of the class.
To access a Public Sub inside a class module (such as a userform), you need to instantiate the class, then call the method.
Dim uf1 As UserForm1
Set uf1 = New UserForm1
Uf1.MyPublicSub