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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How do I reference a DEClass instance?

Status
Not open for further replies.

vfp4ever

Programmer
Oct 18, 2013
71
East Java
I have read a few posts about Form.DEClass and .DEClassLibrary properties, but I could not find any sample code to see how it actually works, programmatically. As an example, I have (all in code) created a Form instance where I define the DataEnvironment class, and related library file, I intend to use:

Code:
DEFINE CLASS MyDEClass AS DataEnvironment
[indent]Name           = "MyDE_"[/indent]
ENDDEFINE

DEFINE CLASS MyFormClass AS Form
[indent]DEClass        = "MyDEClass"[/indent]
[indent]DEClassLibrary = "MyOwnClasses.prg"[/indent]
[indent]Name           = "MyForm_"[/indent]
ENDDEFINE

After creating an instance "MyForm_1" of the Form, I was able to intercept all its expected events, but only the Init of MyDEClass (with no Destroy). And I keep getting error 1734 whenever I try to reference MyForm_1.MyDE_1 (or .MyDE_, .MyDEClass, .MyDEClass1, .DataEnvironment) in MyFormClass.Load event, as a matter of fact I cannot see any object contained in MyForm_1!

Is there anything wrong that I am doing or something else that I need to do?

Thanks in advance,
Dario
 
Error 1734 is 'Member not found' (to save everyone else from looking it up).

Why not add this to your DE's Init method and make a quick test?

Messagebox(This.Name)

 
Thanks for your reply.

danfreeman said:
Error 1734 is 'Member not found' (to save everyone else from looking it up).
Yes, error 1734 is "Property not found", sorry if I forgot to mention.

Why not add this to your DE's Init method and make a quick test?
Messagebox(This.Name)
That returns "MyDEClass", though I would think it should rather be "MyDE_1". Whatever the name, I can only see this object in the MyDEClass.Init event. If I try to access This.MyDEClass in the form Load event, I get the "Property not found" error. I suspect there is something else to be set in order to keep the DE object alive after it Inits.
 
Well, I wouldn't expect to access a DE object from Form Load. Load happens before the contained objects are unfurled.

Wish I could help more, but fiddling with DE instantiation in VFP3 sort of cured me of the appetite for it. You can, of course, put SUSPEND in the form.init and drill down into the form object in the debugger. What does that show?

 
I always thought that Form.Load was the right place to deal with data, hence my try to scan for the DE object in there.

Anyway, I have already looked into both the Form.Load and Form.Init event and the Objects property is undefined (no objects contained).

Hang on, I had missed this sentence from the Help: "Visual FoxPro supports DEClass and DEClassLibrary for (...) program (.prg) files but not for FormSet objects (...)". As the form I am creating is within a FormSet, I should probably move it out first and see what happens...
 
That's interesting. I wonder why you are using form sets. I'm not saying it's wrong to do so. But it is very unusual. In 20 years with VFP, I've never seen a reason to use form sets, and I don't know anyone who does.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Well... Mike,

until today I did not have any good reason NOT to use them! I often wondered whether FormSets were useless, sometimes whether they could prevent any code from working properly. They never did any harm, really.

That is why I have launched the VFP Help and started reading back what FormSets are for. The three benefits listed on top of the page seem to be a good option, so why give up these possibilities right from the start? It also looks more natural to me have an extra "layer" between my global application object and the various Forms I may have. Also, I can add Toolbars to the FormSet and they will open along with the Forms (I cannot add a Toolbar directly to a Form). Or it is just my habit to use Containers for everything!

Now the answer is clear. The DEClass object cannot live within a Form contained in a FormSet, as the VFP Help clearly warns. Wish such a faulty instantiation would be signalled by an internal warning.

 
Formsets exist for one reason: backwards compatibility with FPW/FPD screen sets. They were added specifically to make the transformer work.

ISTR Lisa Nicholls once said she used them to procure a data session before we got the Session class, but other than that I've not seen anyone really use them. And that's why you're unlikely to find anyone inclined to have enough experience to spot an anomaly like this. [ponder]
 
That's all fine. You've clearly had success using form sets, so I won't discourage you from using them. I have to say that the first two of the three benefits don't especially appeal to me. It's not a big deal to show / hide multiple forms at one time, or to control their relative positions. But it's a matter of taste, and you must use whatever techniques you find most comfortable.

Regarding the issue of the data environment, I can see that, given the members of a form set share the same DE, you need tp instatiate the DE for the form set as a whole, not for the individual forms. Presumably it's possible to do that.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Besides the formset discussion: The DE should give you tables, view, cursors, in short: aliases you work on. It has it's own code area to work on these in some events. The only reason you'd need access to the instance of a DEClass is to get at cursoradapter objects, to call some method there. Even those will work without access to them, a they are adapters to the cursors they can create automatically at startup. As with views you REQUERY("alias") to refresh data, you TABLEUPDATE("alias") to save changes, etc.

If you need any objects references in general, the easiest is to create some manager (speaking in oop patterns a mediator is what you need here), to which all sibling or collegue objects register. You pass in THIS eg from the object init to the mediator and the mediator can be a form sub object you add at design time or in load via Addobject. Make it a derived collection to contain all the references, for example.

Then you are fress to get any access to things not easily to refer to natively, as the DE.

Bye, Olaf.
 
Thank you all for your feedback.

I did not mean to restart an old-running debate, unanimously settled against the use of FormSets, yet I can clearly see that each of you perceives a different level of "affection" for them. I may have been taken into the use of this obsolete class because I prefer old-fashioned, programmatic code rather than visual, but it's never too late to drop FormSets, and because VFP always offers multiple ways to accomplish things, I am sure it will not be difficult to reshape the "offending" code. I will carefully read through some code that I found in another precious Olaf's post yesterday.

I guess the only reason why this DEClass issue came out is that I did not get a run-time error similar to #2069 (Forms or Form classes that specify a DEClass and DEClassLibrary cannot be converted to or used with a FormSet.), while it should be signalled in such case.

Dario
 
OK,

now that I can create MyFormClass instances, completely free from FormSet containers, I still notice a difference in behaviour.

Creating a free instance of the Form (using CreateObject) gives me the expected DEClass object, while adding a new property to my global application object (using .AddObject) doesn't. This is what I get (at the same point in code):

Code:
LOCAL loForm AS Object
loForm = CreateObject( "MyFormClass" )
? loForm.MyDEClass.Name[indent]&& OK, MyDEClass[/indent]
Code:
.AddObject( "MyOtherForm", "MyFormClass" )
? This.MyOtherForm.MyDEClass.Name[indent]&& ERROR, Unknown member MyDEClass[/indent]

My global application object is derived from Custom (not from FormSet!), and examining the two Form objects only gives me a difference in the TabIndex and TabStyle (besides Name and Caption).

Why do you think the DEClass doesn't instantiate now?
 
You can't add a form object to a custom object. AddObject is restricted to adding contents to containers. I'm surprised that code even runs.

To put a reference to a form into your application object, use something like:

Code:
This.MyOtherForm = CREATEOBJECT("MyFormClass")

Tamar
 
You can't add a form object to a custom object. AddObject is restricted to adding contents to containers.

I would think that a Custom object is a container, as it lists AddObject amongst its methods. I haven't had problems adding a FormSet to my Custom-derived object either, and now that I have removed the FormSet in between the hierarchy, my Form seems to work fine as always, apart from the DEClass failure.

The reason why I prefer using .AddObject instead of CreateObject is that, starting from my TApp global object (Custom-derived), I can easily drill down all contained objects as far as single controls.

Dario
 
I presume a custom object container plays the role of the FormSet, and adding a form to it, is subdued to a similar restriction, regarding the data environment.
You can add a collection object to your global object, and add the forms to this collection :
Code:
PUBLIC goapp
goapp = CREATEOBJECT("Custom")
goapp.addobject("Forms","Collection")
goapp.Forms.Add(CREATEOBJECT("MyFormClass"),"MyOtherForm")
goapp.Forms("MyOtherForm").Show()
MESSAGEBOX(goapp.Forms("MyOtherForm").MyDE_.Name)

DEFINE CLASS MyDEClass AS DataEnvironment
Name           = "MyDE_"
ENDDEFINE

DEFINE CLASS MyFormClass AS Form
DEClassLibrary = "lulu.prg"
DEClass        = "MyDEClass"
Name           = "MyForm_"
ENDDEFINE

The _Screen or _vfp object, use a similar approach :)

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
Makes me wonder if you got the idea from me mentioning Addobject.
I was not referring to the DE class itself, but I said "the mediator can be a form sub object you add at design time or in load via Addobject."
The mediator - a manager class - could be based on a Collection class and would receive a call from the DEClass init in eg it's Add method to add "THIS" = the DE Class reference.

Tamar is right, that certain objects only add to certain parent container objects, but you can always store any reference passed by reference to a collection and work with it.

That has to be done with caution, because of VFPs way to only release and garbage collect objects, only if no reference remains. The Collection class is written in a way to play nice and easy with Form object references stored into it, I doubt that also is true for DE classes. Anyway, as the DE class can Add itself to the manager/mediator, it can also Remove itself from it.

It's a good idea to add this on the level of an application object, so in short what I wanted you to do is this:

goApp.AddObject("oDEmanager","DEmanager")

DE.Init()
goApp.oDEmanager.Add(This,key)

And somewhere in the form/formset you may reference goApp.oDEManager.Item(key) as your DE object.

Any class can live on its own without any parent, as you know yourself from creating an instance of your DEClass via CreateObject. The way the DEClass is meant you don't do this, but set up the Form.DEClass and DEClassLibrary so the DE is generated automatically for you, but that's not the only way to go.

I use a framework with business object (including data access objects and business rules) with DE objects as part of them and you can have several business objects you use per form, so you can combine several data environments, which is really helpful in a more complex application, where you need a bunch of these tables in form1, another bunch of tables in form2 and all of them in form3, you don't create DEs per form, but per use case. You reuse and combine them in complex forms covering overlaps of certain use cases.

Bye, Olaf.
 
Thank you Wilhelm and Olaf,

I'm afraid my curiosity towards the DEClass, as member of the Form class, went a bit too far. I was not actually looking for any special use of that member, and have eventually found out it does not behave as I first thought. It definitely deserves a much deeper attention that, so far, I never found necessary and will certainly be looking at in the future. My knowledge of DataEnvironments, Sessions and Cursors (as objects) is only marginal.

I believe Tamar is correct, and if she is surprised to see some code that even runs, you can imagine how I am surprised to see that my framework has worked so far. Eventually it will have to be remodelled, as soon as I have a better understanding of data environments.
 
I see that Help says you can use AddObject on Custom, but Custom is not a container class in the same sense that Container and Control are, so I'd take it with a grain of salt.

Tamar
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top