Re: Static and Global Variables
- From: "BruceM" <bamoob@xxxxxxxxxxxxxxxx>
- Date: Thu, 10 Jul 2008 15:29:37 -0400
Thank you again for the time and attention you have put into this response. Questions and comments inline.
"Albert D. Kallal" <PleaseNOOOsPAMmkallal@xxxxxxx> wrote in message news:%239ZR43i4IHA.2332@xxxxxxxxxxxxxxxxxxxxxxx
"BruceM" <bamoob@xxxxxxxxxxxxxxxx> wrote in message news:%234cbvOd4IHA.4920@xxxxxxxxxxxxxxxxxxxxxxxThanks to both for the replies. This posting is in response to both.
If I understand correctly, any variable (public, private, or static) will be reset if there is an unhandled error. In light of this it seems a static variable offers no advantages over any other kind of variable in this regard. Does the same apply to a static function?
Your above assumptions are correct. The only advantage of using a "static" declaration for variables in a sub/function is that if you have to call the function/sub over and over and need some variables to "retain" their values from call to call. This feature simply means that you can limit the scope of the variables to JUST that routine, but they keep their values.
OK, this will probably be good to know.
In programming languages before we had a static type declaration ability, you would have to declare your variable at a lower scope level (say perhaps at a module level) for the ONE routine to keep some of the values intact when the routine EXITS. If you don't use the static declaration, when you exit the subroutine/function, then ALL of the variables declared in that fucntion/sub instantly lose their values. So, the exception to this rule is of course when you use the static key word to declare the variable(s).
Once again however, the the issue of the variables being reset due to an handeled error is not related to this issue of a static varible in a sub.
In that sense all errors and handled, but is that is what you mean?
Yes, if you have a error handling code in every single function and sub that you write in your application, then it's going to be impossible for you to have an un-handled error. And, if you have some subs and routines that don't have error code handling in them, then you have the possibility of a un handeled error.
Or is a handled error in this context one that is specifically trapped by number?
no...is just a case of where you have an routine where no error code traps the error (so it has nothing to do with a error number. It's just the issue that if an error occurs and you don't have an error handling routine, all your variables are simply lost..).
As mentioned, I never had this problem since I've always for years and years have religiously distributed a mde to my users, and no matter if you have an error handling or not, a mde does not lose its variables of under any circumstances (even when your application has zero error handling code in it).
Here is a better example of how I have used global variables:
...I see one disadvantage is that anybody maintaining the code will need to hunt down the variable declaration if it is some place other than in the procedure, or in the form's code module. The "advantage" is that the declaration only has to happen once, but I am starting to realize it is probably offset by the potential confusion.
I agree with your above conclusion 100%
more comments follow:
Here is a situation in which I do not know how best to proceed, even in light of the new information I have learned. I have a Purchase Order form with a LineItems subform, based on related tables in a standard set-up for this situation. The LineItems subform includes a combo box that gets its
DoCmd.OpenForm "frmAdd", , , , , acDialog
Set rs = db.OpenRecordset("tblProduct", dbOpenDynaset)
On Error Resume Next
rs.AddNew
rs!SupplierID = lngSuppID
rs!ProdCode = strNewCode
rs!ProdDescr = strNewDescr ' This could be NewData
rs!ProdUnit = strNewUnit
rs!UnitPrice = varUnitPrice
If Err Then
MsgBox Err.Number etc.
The variables in the five lines of code after rs.AddNew were passed from the pop-up form (frmAdd). Where do I declare the variables? If I declare them as Public in frmAdd, from what I understand they will not be available to the NotInList event after frmAdd is closed.
That is correct, but why don't you make the form based on tblProduct, and open the from in add mode? That way, you not have to write all that extra rs code? However a lot of people in the newsgroups actually suggest to make some global variables to return the values back from the form after it's closed, I find that a poor programming practice, and you'll have to declare the variables somewhere.
I have spent the best part of the day attempting to base the form on tblProduct. I finally stripped the NotInList code down to:
If MsgBox("New Product?", vbQuestion + vbYesNo) = vbYes Then
DoCmd.OpenForm "frmAdd", , , , acFormAdd, acDialog, NewData
Response = acDataErrAdded
Else
Response = acDataErrContinue
Me.Undo
End If
However, I still get the notification that the item is not in the list. In stepping through the code I find that the message appears after the code has run. When the highlighted line of code is End Sub and I press F8 I get the message that the item isn't in the list. I think I have done everything you suggested, but I have run into a wall here. I don't see anything left to try.
However, I did get away from the global variables by hiding frmAdd and leaving it open. In the NotInList event I declared private variables, then assigned their values from text boxes on frmAdd. At the end of the NotInList event I close frmAdd.
Even though I have been frustrated by the attempt to use a bound form for NotInList, I have taken a lot of valuable information away from this exchange. For one thing is the added information about the use of variables, but there was lots of other good stuff like about the use of form in Dialog mode, and about setting the Cycle property to Current Record. That last one is simple, but very useful.
In the following article of mine I explain in far better details as to how you can have a form return all the values, and you don't need to declare variables or even use globals:
http://www.members.shaw.ca/AlbertKallal/Dialog/Index.html
And the above also shows that in place of using variables, you simply can reference the text controls on the form directly.
As I recall I can hide a form that is open in Dialog mode, and will then be able to copntinue with the next line of code (Set rs etc. in this case). If so I could keep frmAdd open, and use the NotInList event to take the values directly from the frmAdd text boxes.
yes, that is exactly what my article suggesting to do.
Assuming you don't wanna examine the text controls on that form, as my above article shows, let's pretend for some strange reason we do want use variables (I see no reason why). you would simply declare the variables as public in the form frmAdd. You can then go:
someValue = forms!frmAdd.nameOfPublicVarible
So keep in mind that if you do delare module level variables in a form's module level as **public**, then any routine in any other place your application can reference the variables in that form (as long as the form is open) as I've shown above.
Or I could declare the variables as Public in the LineItems form (or the Purchase Order form), but then am I getting into the global variable house of cards?
Again a good assumption and thinking on your part, I agree you're getting into the global variable house of cards, and those other forms would not be re-usable in other applications or by other code if you start declaring variables that actually belong in frmAdd. The design philosophy and approach here is to encapsulate as much into each individual object or form as possible. (so in this case, since those variables belong to frmAdd, that is where we should try and limit or keep those variables).
Also, as I recall I had frmAdd be unbound because otherwise the NotInList event generated a standard message about the item not being in the list.
The above is incorrect and I'm going to cut and paste a post of how to solve this problem correctly ----------------------------------
The easy way to do this is have ms-access do ALL of the work for you. So,
given that new data is the actually text you typed into the combo, then you
can do the following:
Private Sub Distributee_NotInList(NewData As String, Response As Integer)
if MsgBox("Do you want to add this value to the list?", _
vbYesNo) then
DoCmd.OpenForm "frmAddClient", , , , acFormAdd, acDialog, NewData
Response = acDataErrAdded
Else
Response = acDataErrContinue
End If
End Sub
The above is ALL YOU need. You can see it is not much code.
Note that by setting response = acDataErrAdded, then ms-access does a
re-load, and a re-query of the comb box list for you. In other words, quite
a bit of stuff happens to ensue that the combo box is re-loaded, and re-set.
(so, don't forget to set the response as above...it is the key here).
However, there
is one thing we should do, and that is that then the frmAddClient loads, we
should put in the NewData value into the correct field so the user does not
have to re-type it. (and it helps the user "see" things a lot better". So,in
our forms on-load event, we will take the value of NewData, and set the
correct field. The code for this is:
if isnull(me.OpenArgs) = false then
me.CompanyName = me.Openargs
endif
I did this part. I know about OpenArgs, but for some reason I got it into my head to pass a string variable. I changed it to add OpenArgs to the OpenForm command, as you suggested.
That is all you need. However, to make life a bit easier to your users,
there are a good number of things you should set in frmAddClent to make life
better.
They are:
Set the forms "cycle" property to current. This means the cursor when on the
bottom of the screen at the last field does not jump to another record. It
is horrible when a user bumps the tab key, and access goes to another
record, so, set the forms cycle property (other tab) to current. In fact,
this is a good setting for most forms, and NOT just this add example.
Since this is just a add form, then turn off the record navigation at the
bottom, again this serves only to confuse the user (since you have a
frmAddClient, I bet you already did this too). Why confuse the user!
I almost always use substitute command buttons. Most often lately I have been using Lebans use of a command button subform that allows the AutoRepeat property of the command button work for record navigation. I keep the subform in a storage database, and import it into new projects.
Further, turn off the forms ability to "add new" records. Yes, you read this
100% correct. You want turn off the forms allow additions property. The
reason for this is that the above "open" form will OVER RIDE this setting.
This is ideal, since once again, hitting page/down key, or even the mouse
wheel will not cause the form to jump to another record, and confuse the
heck out of the user (this is along the same lines as the tab key setting
above as per "cycle" setting).
Note if you need this form to do "double duty" and want to use it in other
places in the application to allow the user will add MORE THEN ONE record at
a time, then put the follwing in the forms on open
if isnull(me.OpenArgs) = false then
me.Company = me.Openargs
me.AllowAdditions = false
Me.NavigationButtons = False
endif
That way, this form can be used else where in the program, but for our combo
box, the navigation buttons, and accidental adding of MORE THEN one record
will not occur.
All in all, you don't have to do any of the additional things I mention
above, but can *just* use the short sample code, but all of the above
together makes a real slick app.
I wish I knew why it isn't working, but thanks again for all of the attention you put into these responses.
--
Albert D. Kallal (Access MVP)
Edmonton, Alberta Canada
pleaseNOOSpamKallal@xxxxxxx
.
- Follow-Ups:
- Re: Static and Global Variables
- From: Klatuu
- Re: Static and Global Variables
- References:
- Static and Global Variables
- From: BruceM
- Re: Static and Global Variables
- From: Albert D. Kallal
- Static and Global Variables
- Prev by Date: Re: determine whether a pdf file is being viewed using vba
- Next by Date: Re: Subform Navigation
- Previous by thread: Re: Static and Global Variables
- Next by thread: Re: Static and Global Variables
- Index(es):
Loading