View Single Post
  #2  
Old May 7th, 2008, 11:30 PM posted to microsoft.public.access.forms
Albert D. Kallal
external usenet poster
 
Posts: 2,874
Default Calling a Function on a subform from the Main Form (Round II)

"Max Moor" wrote in message
. 16...
Hi All,

I asked how to do this some time back, and got a response from Allen
Browne, explaining (in part):

If the subform is name Sub1, and the procedure is named Text0_AfterUpdate,
you can then call it like this:

Call Form_Sub1.Text0_AfterUpdate


Actually, the above syntax is wrong, because you using the forms "base"
class object, and you NEVER EVER want to do that.

The reason why you never want to do this, is if the form is not loaded, the
above syntax will actually create an instance of that form, and all the
forms events such as on load, on open etc. will in fact fire, and that is
completely unexpected behavior.

Furthermore, you are confusing the concept of a sub form, and that of a sub
form control. In the access world, in a sense, there's no such thing as a
true sub form, but only a control called sub form "control" that you place
into a regular existing form. Keep in mind that most of the time you usually
give that sub form control the same name as the form, but it does not have
to be so.

For example, many developers to reduce confusion always use a different name
for the text box controls that they place on a form, as opposed to the
underlying fields that the control is bound to. By doing this, they
never get confused if they're referencing a control in their code, or the
actual direct underlying record set in their code. And of course the worst
thing to do is to have a text control box that's not bound, but has the same
name as the underlying field in the form, then things get really confusing
fast.

So, first and foremost I can't stress enough that when you place a sub form
into a form, you are placing a control on the form, not a real sub form.
Furthermore, what this means is that if you have five sub form controls on
your form named F1 to f5, you're now free have these five sub form controls
set or point to any instance of any form you have in your application.
Furthermore, those sub form controls can all point to the same form. If you
take a look at the following screen shot you'll see to create a calendar I
simply placed a grid of sub form controls laid out in a calendar fashion.

The result is in a small amount of time, I've created a very functional
outlook style calendar with almost no code:

http://www.kallal.ca/ridestutorialp/setdriver.htm

(Take a look at the third screen shot the above, you'll see it's a grid of 7
x 6 sub forms. That means the actual form (frmDay) used by the sub-form
control is repeated 42 times!!!)

So the question then becomes, when we have 42 instances of the same form
active here, how are you going to know which form you're actually
referencing?

To make a long story short, you're original syntax don't know what form it
going to reference when that form is used several places in your application
as a sub form (which one will it call).

Furthermore if you used more advanced coding techniques, often you will
allow multiple instances of one form to be opened at the **same** time.
Often a developer will "enable/allow" this feature in applications,
especially
when they're doing entry of a customer, the phone rings, and they have to
inquire and deal with another customer, but are halfway through entering a
whole bunch of data in the current existing form. If you don't want to lose
your place in the current form, it is perfectly legal in MS access to write
your code that supports multiple instances of the same form opened more then
once. I should point out that having multiple instances of forms also works
well when those forms have many sub forms inside of them.

So, you never want to access the base class object of a form in code,
because it causes an instance of that form to be created in code at that
point in time (unless, there's *already* one instance of that form created,
then MS uses that instance! I believe this **why your** above coding
practice has been working up to this point in time. While most developers
don't do extra coding to allow multiple instances of the same form open, it
is quite common that a sub form will be used more in one place in your
application.

Because you have no control over what instance of the base class object of
the form is being used, and when where and how it is being used, then you
really have to avoid that syntax altogether.


In this case, when I make a call like the one above, how would Access
know that I wanted the instance of Form_Sub1 that is a child on the main
form making the call?


As I said, in your case it simply takes the first instance of that form that
was created, and as I mentioned you only been *very* lucky up to this point.
Furthermore, your syntax will actually launch a copy of that form, if it's
currently not in use, and all of the forms events such as on load, open etc
will fire, and that is unexpected behavior.

I think this has worked so far because I never have
more than one instance of any given form open at a time.


Golly, I should have read your post BEFORE I started typing! You are 100%
right on the money here!


In search of a calling convention that would properly resolve to the
child form's function, I tried, "Call Forms!frmMain!
fsub_Child.Form.FuncCall", where fsub_Child is the subform's control name.
It didn't work, but I'm sure those of you in the know could have told me
that it wouldn't.

Is there a syntax that I could use to call the child form's function
specifically?


If you inside of the "main" form, then you can go:

call me.subFormContorl.Form.NameOfSub

or in your example:

Call me.fsubContorl.Form.FuncCall

Note that in the above I've changed your syntax slightly, because I really
want is stressed that you're referencing the control name + the .form
property of that control. the ".form" property is what gets you a reference
to the instance of a form that you want.

I haven't checked, but I also notice in the above you have "FuncCall", and
were actually calling the code, then that should be declared as a
subroutine, not a function. However all public functions of that form
actually become a method of the form, and if it *really* is a function, then
you can use it like in the standard property like any other object

eg:

me.fsubContorl.Form.FuncCall

Once again I can't stress how in the above your specifying the name of the
sub form control, which is not necessarily the same name of the form that
the sub form "control" points to.

If I had five sub form controls all with the same sub form action specified,
then you could go

call me.day1.Form.SetToblue
call me.day2.Form.SetToblue
call me.day3.Form.SetToblue
call me.day4.Form.SetToblue

The above syntax would call a subroutine called set SetToBlue in each of the
4 subforms (in my hypothetical example, I'm assuming sub forms day1 to day4
all specify the exact same form).

And of course is the code is to be called from outside of the form, then you
can not use "me", you would go:

Call Forms("frmMain").fsubContorl.Form.FuncCall

perhaps as a slight inconsistency, but when you use the "call", you can
*NOT*
reference the form as

forms!frmMain

You *have* TO USE for call

forms("frmMain")

Not also in the above you use the "dot", not the bang to get to the forms
contorl(s).

I suggest you get in the habit of *always* using the dot when you're
referencing a control on a form

eg:
use
forms!frmCustomer.compayName

However if there might not be a company name control on the form, but you
want a reference the underlying record set, then in all cases, then use

forms!frmCustomer!compayName

The above syntax will work and function regardless if you actually have the
CompanyName control on the form.

Hope this helps....

Also don't forget to make the function or sub declared of public in that sub
form or form, else external callers will not be able to see it.

--
Albert D. Kallal (Access MVP)
Edmonton, Alberta Canada