If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below. |
|
|
Thread Tools | Display Modes |
#1
|
|||
|
|||
Calling a Function on a subform from the Main Form (Round II)
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 I 've been doing this and everything works fine. Every so often, I get a sick desire to understand what's happening under all the comfy layers I usually stay above. 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? I think this has worked so far because I never have more than one instance of any given form open at a time. Allen also suggested that the function being called be moved into a standard module, then passed a reference to the form I want to work done by. I can see how that would fix things. 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? Regards, Max |
#2
|
|||
|
|||
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 |
#3
|
|||
|
|||
Calling a Function on a subform from the Main Form (Round II)
"Albert D. Kallal" wrote in
: Wow, Albert, what a great reply! Thank you so much. I have a follow up question, if you're game... As agreed, if I have multiple instances of a form open at one time, and make a call like Form_frmMain.Func, Access calls the function from the first instance. How does one tell Access to call the function on the second, or third, or Nth instance of a form? Now that I've asked, I understand that this could be a big question, and I appreciate all the time you already put into my education. If you know of a reference you could point me toward to learn more, I'd be more than happy to go do some reading. Thanks Again, Max |
#4
|
|||
|
|||
Calling a Function on a subform from the Main Form (Round II)
"Max Moor" wrote in message
. 16... "Albert D. Kallal" wrote in : Wow, Albert, what a great reply! Thank you so much. I have a follow up question, if you're game... As agreed, if I have multiple instances of a form open at one time, and make a call like Form_frmMain.Func, Access calls the function from the first instance. How does one tell Access to call the function on the second, or third, or Nth instance of a form? Great question. In the case of a sub-form, there is never a problem, since you always reference the sub-form "control". In the case in which you have *several* copies of the *same* form opened, then you have to reference that form via the variable that ***holds*** the form in memory. While I just That said you should never use the base class object to reference a form, when you have multiple instances of that same form opened, the only way to do this is in fact the Clair multiple instances all that form. eg: dim f1 as New form_frmContacts dim f2 as New from_frmContacts dim f3 as New form_frmContacts f1.Visible = true f2.Visible = true f3.Visible = true to call code, we then go: Call f1.MyPublicSubName And, you can reference any variable declared as public in that form like: f1.bolNoNameEdit = False f2.bolNoNameEdit = True So, each "form" is a separate class object. Also, keep in mind that when f1, f2, f3 goes out of scope (the above sub exits and ends, then all 3 forms will magically disappear, because the three variables that hold the forms will in fact go out of scope (they will no longer exist in memory). What this means is either you have a form that launches these additional forms and holds these variables (for really cool trick, if you close that parent form, then all of the forms launched from that form will magically close at the same time because the variables no longer exist). If you need the forms to stay open in dependins of one particular form, then you'll have to declare the form variables as global in a standard code module. Often, if you don't know how many copies of the one form be opened at the same time, then we often declare a global collection, and add forms to that collection as they are needed. colMyFormsCol.Add f1 Keep in mind in the case that you're not using multiple instances of a form, you always want to use the forms() collection to reference and use your forms, and furthermore you always want to the docmd.OpenForm to open the form, so it is correctly added to the general forms() collection. Note that if you do have multiple instances of a formal opened, I believe in fact they do get added to the forms() collection, but you have no way of identifying which form you want to reference. -- Albert D. Kallal (Access MVP) Edmonton, Alberta Canada |
#5
|
|||
|
|||
Calling a Function on a subform from the Main Form (Round II)
"Albert D. Kallal" wrote in
: Great question. And a great answer! I appreciate all the time you put in on this. It makes good sense to me now. So much to know, so much to learn... Regards, Max |
Thread Tools | |
Display Modes | |
|
|