Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Instantiating a class that was defined before a menu is fired up.

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
621
GB
I have a form myform.scx which I can call from myprog.prg or from an intermediate menu

Myprog.prg also defines a class, clsmyfuncs whose purpose is to contain several useful functions.

So in Scenario 1, myprog.prg looks like this

* Lots of initialisation code
DO myform.scx
DEFINE CLASS clsMyFuncs AS Custom
FUNCTION FmtBigDate
. . .
RETURN Answer
ENDEFINE

This works fine, and within myform.Init() I can say
.zMyFuncs = CREATEOBJECT("clsMyFuncs")
. . .and later on call .zmyfuncs.FmtBigDate()
If however I choose to call myform.scx from a menu, I have Scenario 2, and myprog.prg looks like this.

* Lots of initialisation code
DO menu.mpr
DEFINE CLASS clsMyFuncs AS Custom
FUNCTION FmtBigDate
. . .
RETURN Answer
ENDEFINE

In this case myform.init() fails with the message : Class definition CLSMyFuncs is not found.

I am puzzled at the difference between the two cases. Why can I “see” the class definition in the first case but not in the second?


 
It's because the class definition is no longer available at the time that the user makes the menu selection.

By the time the user gets round to making the menu selection, the program that calls the menu has finished running. The menu is still on the screen, but the program that launches it is no longer available, and so VFP doesn't know where to look for the class definition.

Normally, this isn't a problem because you would call the menu from your main program, and you would have READ EVENTS in the main program. The effect is to pause the main program while the user interacts with your application. Presumably you are not doing that in this case.

I assume the reason the problem doesn't occur in the first scenario is that the form is modal, which (in this situation) has the same effect as READ EVENTS.

Either way, the solution is to put the class definition at a higher level, in a program that is still executing when you instantiate the object. Alternatively, use NEWOBJECT() instead of CREATEOBJECT(), and pass the name of the PRG that has the class definition as the second parameter.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
Thanks Mike. A clear and succinct explanation. READ EVENTS it shall be. Had forgotten about the implications of this statement. Andrew
 
Mike, you're right. The time the code executes is iportant, and what is available in the context, then.
A solution is to SET PROCEDURE TO seperate prg files with class definitions, eg at app start. Then those classes are available at any time and in any context.

I am still also puzzled why it works in the case of DO form.scx, as the init code is in a seperate file and the class definition is not available from the scx context. The prg containing the DO form.scx call is just still on the stack, while running an mpr just creates a menu and then vanishes from the execution stack, only the menu is still there.

So maybe I explained my own question, now.

Still, SET CLASSLIB (ADDITIVE) to all classlibs used at any time in the app and SET PROCEDURE (ADDITIVE) to all prgs is helpful in not having that problem at all.

Bye, Olaf.
 
Olaf said:
I am still also puzzled why it works in the case of DO form.scx, as the init code is in a seperate file and the class definition is not available from the scx context.

My guess is that it's because the form is modal, and so the calling program is still on th stack. But I'm not sure if that's right.

SET CLASSLIB and SET PROCEDURE are good solutions. But, on reflection, I prefer NEWOBJECT() with the defining file as the second parameter. That's because it's the most local solution - the one that has least effect on any other part of the app.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
I use Newobject() for classes, which remain in seperate files, and there it's very fine and the additional parameters are not only useful but needed, as the location can vary and is configurable.

So to me a NEWOBJECT call has a meta meaning of loading an external class and CREATEOBJECT has a meta meaning loading an internal class, due to my usage.

I have startup code loading all classlibs locations via SET CLASSLIB, SET PROCEDURE. I agree it's probelmatic, if you use third party modules and are not sure there could be a same name for different classes of two libs. It's also good to use NEWOBJECT for different versions of the same library, if that's needed. But in the long run, even if the usage of identical named classes is possible I prefer uniqueness of names.

It's a concept to only use Newobject(), it's said to perform better. Neglectible perhaps. But I also have to live with what the framework I use does and it works that way meta data driven with libs and prgs to load at app start in a dbf.

Bye, Olaf.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top