BruceM said:
Thanks 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.
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.
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
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!
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.