views:

95

answers:

4

Hi,

Im trying to pass the name of a global variable to a sub routine and would like to know how to reference it. For example I could do the below with a control:

Private Sub passCtrlName(ctlName as String)
Me.Controls(ctlName) = "Whatever"
End Sub

Edit:

For Example

Public imGlobVar As String
Public Sub passGlobVar(frm as Form, ctlName as String, globVar as String)
frm.Controls(ctlName) = globVar
End sub

And call it as Private Sub imaButton_Click() imGlobVar = "something" Call passGlobVar(Me , txtBox1, imGlobVar) End sub

2nd Edit:

It seems that I could most definitely be barking up the wrong tree here, so I will explain what I'm trying to achieve.

I have a form that has textboxes for the users (risk) address, with a checkbox at the top that lets the user select that this address is the same as the 'contact' details already on the system, and the textboxes are locked.

Populating the textboxes is fine and works. What I use the global variables for is to improve usability (albeit slightly). The user can add new details, and if they hit the checkbox 'make same as contact' the details that they have entered are stored in the global variables, one for each control.

If the user has made a mistake by hitting the checkbox, they haven't lost these value, and by unchecking the box the entered values are returned. I hoped to create a sub routine where I could pass the name of the global variable and control and calling this routine, as opposed to writing it out for each control.

I have a feeling that I could be using the wrong technique to achieve my goals. But in answer to my original question, it appears that you can not pass global variables to sub routines in the manner that I wished.

+1  A: 

You do not need to pass global variables, you can simply refer to them by name. Note that global variables are reset if an unhandled error occurs.

In http://msdn.microsoft.com/en-us/library/dd897495(office.12).aspx you will find a section on Scope and Lifetime of Variables and Constants.

In a module:

Option Explicit 
Public glbVarName As String
Const MyConstant=123

Sub InitVar
   glbVarName="Something"
End Sub

Any other module, includeing a form's class module:

Sub SomeSub
    MsgBox glbVarName
    SomeVar=2+MyConstant
End Sub
Remou
Hi Remou, do you mean I could refer to it as "Private Sub passCtrlName(glbVarName as Global)" ? Or something similar? I need to be able to pass the global variable name to the sub.
glinch
No, I have added some notes just to be sure we are referring to the same thing. Perhaps, if you say exactly what you want to do and why, it may be easier for someone to give you a way to do it.
Remou
Hi Remou, I understand that i can refer to a global variable by name. What I'm trying to achieve is to pass the global variable to a sub routine (therefore the name can not be guaranteed as it could be one of many) and then reference that within the routine. Hopefully my edit above helps to make it clearer.
glinch
I can see what you want to do, but why? What is the underlying problem that will be solved by this? Why do you need to pass the name of the variable rather than the value?
Remou
Why do you think you need a Global for this? Globals are to be avoided in the first place, but the reason to store something globally is so that it is globally available, in all code contexts. Thus, it doesn't have to be passed in as a parameter.
David-W-Fenton
Hi Remou, have edited the question to include what im tring to achieve. Hi David, why is it best to avoid globals in the first place?
glinch
Rather than use the tag property, I suggest you use the default value of each control. The values will be carried through until they are changed or the form is closed. Global values should be avoided because they are reset if an unhandled error occurs.
Remou
Using Globals is a mistake because you're storing temporary data in the wrong scope. It's also unreliable for two reasons, first, a reset clears them, and second, they might get modified in unexpected ways.
David-W-Fenton
Fanatastic, never thought of using tag or default value in this way, great advice.
glinch
Also, cheers for the heads up on global variables David/Remou
glinch
+1  A: 

If you're asking if you can dynamically reference global variables using a string containing the variable name the answer is no. You could use a single global array and pass the index, which would allow you to dynamically reference an element of the array.

[Edit]
In response to the clarification in the question: You could just save the value of each control to its Tag property when the user checks the checkbox. Then, if the user unchecks the checkbox, you can just loop over your controls and assign the value from the Tag back to the Value of the control.

BenV
Yes Ben that was what I was hoping to do, looks like I can't unfortunately, cheers for the advice regarding the arrays.
glinch
@glinch: And cheers for the upvote. Oh wait...
BenV
Does Eval() not work on this?
David-W-Fenton
Eval does not accept the names of user defined variables in VBA, only user defined functions AFAIK.
Remou
@BenV: apologies, poor stackoverflow etiquette on my behalf!
glinch
@glinch: No problem. I've updated my answer with a possible solution in response to the clarification in the question.
BenV
Great advice BenV, gonna go with Remou and use the defaultValue as im using tag for something else. Cheers all the same, never thought of using these properties in this manner.
glinch
+1  A: 

You could store the values from your controls in a Dictionary object, using the control names as the dictionary keys. Then you can retrieve the value for each control based on the control's name.

Option Compare Database
Option Explicit

Const cstrMyControls As String = "Text0,Text2,Text4,Text6"
Dim objDict As Object

Private Sub chkToggle_Click()
    If Me.chkToggle = True Then
        Call SaveValues
    Else
        Call RestoreValues
    End If
End Sub

Private Sub SaveValues()
    Dim varControls As Variant
    Dim i As Long

    Set objDict = Nothing 'discard previous saved values '
    Set objDict = CreateObject("Scripting.Dictionary")
    varControls = Split(cstrMyControls, ",")
    For i = 0 To UBound(varControls)
        objDict.Add varControls(i), Me.Controls(varControls(i)).Value
    Next i
End Sub

Private Sub RestoreValues()
    Dim varControls As Variant
    Dim i As Long
    If objDict Is Nothing Then
        'MsgBox "No values to restore." '
    Else
        varControls = objDict.keys()
        For i = 0 To UBound(varControls)
            Me.Controls(varControls(i)).Value = objDict(varControls(i))
        Next i
    End If
End Sub
HansUp
Is there some reason to use the scripting object dictionary instead of a VBA custom collection or an array?
David-W-Fenton
I chose a dictionary over a collection because dictionaries have a .keys() method, which actually isn't necessary here. I didn't consider using an array. Also I still tend to think of dictionaries first because of Python.
HansUp
@HansUp cheers for another technique that I would not have been aware of at all, thanks alot.
glinch
I use collections for single-column lists. They are very easy to use and blazingly fast. Arrays I only use when I need more than one attribute. I've never used a dictionary object because it's not provided by Access/VBA. What does the .Keys() method do?
David-W-Fenton
`.keys()` returns an array of the dictionary's keys. When you assign a key to a collection item, there's no way I know to retrieve the keys. My approach was to use the control name as the item's key, and the control's value for the item's value. But, since you mentioned single-column list, I think we saw this thing differently. I'd be interested to hear more from your POV.
HansUp
I think you can do exactly the same thing with a collection, but I could be misremembering.
David-W-Fenton
I looked again at the help topic for Collections, but still can't find a way to retrieve a list of the keys. I found a Knowledge Base article, http://support.microsoft.com/kb/187234/EN-US/, which suggests that is part of the functionality provided by the Dictionary which is absent from the Collection.
HansUp
Oh, you want a list of the keys. You can't get the keys out of the collection, which suggests to me that if you want them, a collection is not the right structure. I'd likely use an array in that case (since apparently both the key and the value are of use). Still not seeing the point of the dictionary object.
David-W-Fenton
A: 

I use additional field in table - name cancel - of course boolean - when i'm not sure if contents of fields will be valid I set it true. If this field will be true by the end - then I clean up (it may be all record or some fileds of course). Very easy.

Norbert Wróblewski