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

VFP 7.0: When a Form is not an Object?

Status
Not open for further replies.

Kimed

Programmer
May 25, 2005
104
LT
Hi,

In my app, I once needed to make a calling form disappear for the time of child form being active and reappear when that one was killed. So I wrote

IF TYPE("ParentForm")="O"
ParentForm.Hide
ENDIF

in the child form's Init, and then a similar one with "show" in its Destroy. And it worked like a charm.

Then, a couple of years later, I had to add another form, a "grandchild" one, being called from the child and running simultaneously. It could be closed manually or had to be closed automatically when its caller was closed (or it might not be called at all for some of sessions). So I updated child's Destroy with

IF TYPE("GrandChildForm")="O"
GrandChildForm.Release
ENDIF

...but this one refused to run. In the Debugger, when I'd type parent's name into the Watch window, it would open the list of form's property, but when I typed grandchild's (or child's as well, for that matter) name in a similar way, it'd answer "Expression could not be evaluated". I compared all forms's properties and DO FORM commands they are summoned by, but could not pinpoint a distinction between them that could explain the difference in behavior.

Now, the problem with my app I actually solved with a proper double-handshake procedure, where the caller and the recipient pass each other references to their own objects. It works, so I'm not asking for a solution. But curiosity does not leave me: why some forms can be called directly by name (I actually did the same thing in at least one other app without even being aware of possible problems), and other, existing and working perfectly in other regards, can't?

Thanks.
 
We've discussed this not long ago in thread184-1701409.

It's another aspect of the same reason, that the watch window will not drill down a form name. A Form name only is a reference to the form in some legacy commands like SHOW WINDOW or HIDE WINDOW, but not a reference you can drill down to properties via the Watch Window. This is a misconception. You can only see a form by a name in the watch window, if that is the name of a variable holding the form reference. Then either by chance or more probable by intention the variable has got the same name as the form, but it's never a form name you can put in Locals or the watch window.

Bye, Olaf.
 
I see. Would it be safe to assume that a form can be addressed straight by name (as an exception) if it was called from a main program, but needs a proper authentication if created elsewhere?
 
No, it doesn't have anything to do with where it's created. A mere DO FORM without the NAME clause does not even generate a variable. (And the NAME clause does not name the form, but a variable.)

It's true, that variables created in a main.prg without using LOCAL are PRIVATE and almost PUBLIC, as main is always on the execution stack, but if you merely DO FORM yourform.scx you have a form without a reference to it put into any variable.

Bye, Olaf.
 
That's weird because I have an app right here on my hands where I did "DO FORM form.scx" without NAME and then addressed it by .scx's name with no authentication at all. [shrug] I will be doing it properly in future projects... but the fact stays.
 
That's weird because I have an app right here on my hands where I did "DO FORM form.scx" without NAME and then addressed it by .scx's name

That is correct. From the VFP Help:

If you omit the NAME clause, Visual FoxPro creates an object type variable with the same name as the form or form set file.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
I don't know why you talk about authentication. This has nothing to do with priviliges or passwords.

I know this, it also works from command window, but it's not a reliable way to handle forms. Start a scx twice, now do formname.caption = "test". One caption changes, not both, right? You have no handle on the form created first. Actually, if you LIST MEMORY fo* you'll see a public variable is created. But forget about it, this is not the way it's intended to work always. You better use the NAME clause and if needed the LINKED clause to have reliable reproducable bahaviour.

Bye, Olaf.

 
Actually I have to admit there is one sentence ion the help on DO FORM stating the creation of such a variable is standard, especially if you omit using the NAME clause:

VFP help said:
If you omit the NAME clause, Visual FoxPro creates an object type variable with the same name as the form or form set file.

But this still does not make this variable the form, eg you can RELEASE form1 and it does just release the variable, and not the form. There can be many reasons the form still exists but it's variable is gone. By default variable and form are not LINKED (as can be done by that clause of DO FORM). Form and variable are two seperate things, two seperate addresses in memory.

Bye, Olaf.
 
Hello Mike,

I just see now you already posted the exact same quote from the help. Funny. This is really something I have learned now from the post.

Kimed,

so it works really reliable, but variable and form are unlinked (as a side not this differs, if you do oForm = CreateObject("form"), because then variable and form are in fact linked).

I don't know what scope the generated variable has. One thing is for sure, variables are overwritten, if a form is started multiple times. And if the variable is declared as private, it can be gone, while the form still runs, if the code creating the form is not on the stack anymore.

Ok, so this demonstrates this, how it happens the variable is already gone.
Code:
doform()
? "after doform()"
List memory Like form1

Procedure doform()
Do FORM p:\test\form1.scx
   Activate Screen
   ? "during doform()"
   List memory Like form1
EndProc

So if you're like me, working objectoriented, having a factory or form handler creating forms, you rather work with createobject, but even if you'd DO FORM, you'd never really see a form can be adressed by "it's name". And that's just how it seems, in fact you have a variable. And if the form is created in some prg or method, even just a click event doing a form, then the variable is gone after that has run, while the form still exists, because the variable is just declared private. The variable still exists inside form Init() for example, but after you come back to a click containing the do form and that click events ends, the variable is gone. If you'd change DO FORM to include the LINKED clause you'd see the variable releases, as also the form then would instantly vanish, maybe it would even not cause a flicker.

Another thing is, how you can cope with this during a dbebugging session. Besides chaging your ways, you can get a grip to a form in several ways, you're not lost, if no variable exists. Just write oForm = Sys(1270) into the command window, don't ENTER yet, then move your mouse to the form and hit ENTER, now you can put oForm into the watch window. SYS(1270) tool tip is "Object Location", it means the object at a Location, at the mouse location.

Another thing always having one entry for any form runninng, visible or invisible is _screen.forms, so eg _screen.Forms(1) can be put into the watch window, too. You have to find out, which index your form has in the _screen.forms array.

The most ideal way is to have a form handler, and the minimum would be to create a collection object, eg also add that to _Screen or goApp via _screen.Addproperty("allForms","Collection") and then in form init do _Screen.allForms.add(Thisform,Thisform.Name+":"+sys(2015)).

The sys(2015) makes the second a parameter unique, it's a key that needs to be unique. You may also omit it, but then the collection items can only be addressed by an index number, as you could also do with the _screen.forms array, so that wouldn't be an advantage.

That collections keeps references to form, while they are running, the collection items are linked with the forms. So releasing a form releases a collection item and removing a collection item releases a form.

You can also change the way you specify the key and then have an easy way to find a certain from or form type.

Bye, Olaf.
 
One warning about SYS(1270):

If you point to a control, that's the object under the mouse, so you get a reference to the control and not the form. You need to point to something really being the form. Some point on the canvas can easily also be a transparent part of a label or a container. If you point to the form titlebar you get a form reference. If you have a control you can at least also "drill up" via the Parent property.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top