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!

Allowed do nesting level exceeded

Status
Not open for further replies.

Ris1

Programmer
Dec 8, 2017
26
IN
In a master entry form , I have given up arrow and down arrow so that user could scroll down/up to next/previous record. I am releasing current form and opening new form for that master. On pressing up arrow around 15 times , this error appears and then user is not able to perform any operations further. I am unable to track why this problem is coming as 1 possibility might be due to recursive calls, but I am releasing parent form before calling child form.
 
Well, it might be do with recursive calls, but it's much more likely caused by your form calling another form, which in turn calls another form, which in turn calls another form, ...., (or another instance of itself) and so on until the stack is exhausted.

A short-term fix is to increase the value of the STACKSIZE parameter in the Config.FPW file, but what you really need to do is to review your logic so that you avoid the situation in the first place.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Note when you program Thisform.Release and in the next line DO FORM, then this doesn't occur the way you think.

Calling Release() triggers the form to be ready for releasing. That DO FORM still is done shows, this doesn't quit the form immediately.

In very short you couldn't have any code in a form releasing itself and then doing something else, if that releasing would happen immedately.

You need non modal forms for your code doing the release to finish and only that will really release the form.

Besides, it's a bad idea to start a new form just to display another record. Simply skip +1(-1 and refresh your current form to display the other record.

Bye, Olaf.
 
Mike ,
On observing stack, for each call 4 entries are appended in stack and when number reaches 128, it starts giving problem. Is there any way to pop up some elements of stack(Pointing to the element where stack was before calling form)
 
Olaf,
I have so many private variables and cursors which I will have to reset before opening the next records. So I thought going that way so that fresh environment is created .
 
Is there any way to pop up some elements of stack

You can't do that explicitly in VFP (as you can in certain other languages). But when you come out of the form, that automatically pops the stack. Your problem is (as Oaf pointed out) that releasing the form does not immediately close the form (it does not remove the form from the call stack). It's only on completion of the the procedure that calls the Release that the form closes.

I don't know why you have "many private variables and cursors which I will have to reset before opening the next records", but that does point to some fundamental flaw in your design. You are opening and closing forms every time the user hits certain keys, which doesn't sound like a good way of showing the details for the current row in the grid.

I assume you basically want to use the grid as a sort of index or table of contents, to give an overview of the data, and you want to let the user point to a row in the grid, and then you drill down into the details of that row. If that is correct, then I would consider doing away with the detail form. Instead, display the details on the main form. Then you only have to refresh the main form when the user moves the highlight.

Alternatively, do what you are doing now, but open the detail form on a double-click, or having the user click a button, rather than simply by highlighting the next or previous row. And make the detail form modal, so that the user is forced to close it before going back to the main form.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi,

Ris said:
In a master entry form , I have given up arrow and down arrow so that user could scroll down/up to next/previous record. I am releasing current form and opening new form for that master. On pressing up arrow around 15 times , this error appears and then user is not able to perform any operations further. I am unable to track why this problem is coming as 1 possibility might be due to recursive calls, but I am releasing parent form before calling child form.

Maybe before you continue it is a good idea to study the wizards, I agree with everybody there are many problems with the use of wizards however the wizbtns.vcx have some fundamental good classes. I can recommend everybody to make use of the txtbtns or better the picbtns classes. Just drop them on your form and you / your user can advance or reverse up/down just how you call it in your table. Even a search and print facility. A MUST HAVE.

RIS said:
I have so many private variables and cursors which I will have to reset before
Mike is correct there is a flaw in your design. And also dont use private variables use locals, biggest advantage you dont have to take care about cleaning, VFP will do for you. And about cursors also no need at all to clear them, VFP will do for you. There is only one exception, as far as I know why you should clean your cursors: when dealing with high sensitive data in a surrounding where you can have power failures. VFP stores your cursor in your temp file, and releases them when quiting the appliction correctly. However if you are abrupt shutting down (power failure) the temp file = your cursors remain in your temp directory. Piece of Cake for Malusers when they get hold of your pc to open the temp directory and poke around in those tmp files which are ordinary dbf's
So only if, than, otherwise no need to get disposed of your cursors.
Make a habit to select blah blah into cursor blah READWRITE NOFILTER.
nofilter ensures that a new cursor will be created and not the one alreade constructed before with the same name.

Regards,

Koen
 
>I have so many private variables and cursors which I will have to reset before opening the next records

Well, you can't have private variables in forms anyway. Or let me put it this way: Whatever you do in Load or Init, eg creating private variables, goes on the stack and back, so private variables you have during these events are released and not available in the rest of the form life. The only way to have private variables is by defining them before a DO FORM or CREATEOBJECT("formclass") and only, when the code making that call does not finish, for example via a modal form or a READ after starting a nonmodal form. Still you have a modal state, as that's the only way private variables stay in scope.

A way to quit your form and start it again for another record would involve releasing the form and starting it from the level of the initial call, so eg you do

Code:
ShowRecord=1
Do While ShowRecord<>0
   * private variable assignments
   Do Form yourform
Enddo
Yourform needs to be modal to stop execution of the While loop before releasing. Yourform then has access to ShowRecord variable, as it's really private and still on the stack, when the form runs. Now when some button on the form sets ShowRecord=0 and releses the form quits overall, if it sets ShowRecord to another number, eg the recno you want to display next, the form is restarted after it has finished.

You can't do that inside the form itself, you have to step back one level from the stack, so that calling loop has to be outside.

It's a hack and not recommended, just like not needing public or private variables overall.
Information needed throughout the form should be turned into form properties. Using OOP and form classes you could do oForm=CreateObject("yourform") and before making that new form visible set predefined user properties, you can also pass in parameters via oForm=CreateObject("yourform", param1, param2) and receive them in form init via LPARAMETERS tcParam1, tcParam2. The calling can also be DO FORM yourform WITH param1,param2.

Besides that you could in a first step also simply try to reuse already existing variable, put your initalisation into a separate userinit() method of your form and call that from the init event and also when you want to change record, so you have a form initialisation for your own needs not redoing the form overall. That will then also make the outer loop unnecessary, as it hinders you to use the menu it's really ugly.

The ideal application design will use non-modal forms, self contained, only with simple initialization parameterization, you mainly ill need the ID, primary key of one specific record, if your form is a single record form. A private datasession is recommended, especially when you don't want to show one record only, but let a user start forms from list clicks and by that show many records in parallel each in its own satellite form. It should get clear, that private variables then are also deadly, same form runs multiple times with same variable names => not working. Properties are really private to each form => works.

You can't get a legacy design running with the new VFP, what once worked is now obsolete with new techniques.

Bye, Olaf.
 
Don't cut down the context. You can use private variables in forms, but a form can't create them for itself, they have to be declared outside, and you know private variables are declared by assigning a value.

Whenever you create a private variable inside a form event or method, the end of that releases the variable.

I showed a while loop making use of private variables, but try to put this into a form method in any way, I'm listeening.

Here's my proof whatever you do in Load or init is gone in Activate or any further method, like button.click

Code:
RELEASE ALL extended
o = CREATEOBJECT("myForm")
o.Show()
READ events

DEFINE CLASS myForm as Form

   PROCEDURE Load()
      loadvariable = "load"
      MESSAGEBOX("Message from Load:"+CHR(13)+CHR(10)+;
                 "load:"+TYPE("loadvariable")+CHR(13)+CHR(10)+;
                 "init:"+TYPE("initvariable"))
   ENDPROC 
   PROCEDURE Init()      
      initvariable = "init"
      MESSAGEBOX("Message from Init:"+CHR(13)+CHR(10)+;
                 "load:"+TYPE("loadvariable")+CHR(13)+CHR(10)+;
                 "init:"+TYPE("initvariable"))
   ENDPROC 
      
   PROCEDURE Activate()      
      MESSAGEBOX("Message from Activate:"+CHR(13)+CHR(10)+;
                 "load:"+TYPE("loadvariable")+CHR(13)+CHR(10)+;
                 "init:"+TYPE("initvariable"))
   ENDPROC 
   
   PROCEDURE Click()      
      MESSAGEBOX("Message from Formclick:"+CHR(13)+CHR(10)+;
                 "load:"+TYPE("loadvariable")+CHR(13)+CHR(10)+;
                 "init:"+TYPE("initvariable"))
   ENDPROC 
   
   PROCEDURE Unload()      
      CLEAR Events
   ENDPROC 
ENDDEFINE
In Load only the loadvariable has type "C" (char), initvariable has type "U" (undefined). In Init the loadvariable already was released again and is type U=undefined. Only initvariable exists and is type "C". In Activate both private variables are gone again. And click on the form,of course variables are still gone.

There is no real problem about that, because form properties are a solution, that even is more private and attached to the form you want it to be attached to, so just throw out private variables. The only place they have in my code is used as acceleration of recursion, as you don't need to pass on a value to the next recursion level. Whether that is fine also depends on whether you actually want all levels of recursion to access and modify a variable or each level should have their private variable level. At this stage notice, that's covered by local variables. Private variables should only be used if you want a bigger scope than local variables.

If you think about the encapsulation you don't want forms which need some private variables prepared before they can run. Depending on Init parameters is a whole different story, as that is one single place any later developer (or yourself) can inspect to see what the form needs to be passed to.

Bye, Olaf.
 
Or better use this demo, making use of the nature of private variables:

Code:
RELEASE ALL extended
o = CREATEOBJECT("myForm")
o.Show()
READ events

DEFINE CLASS myForm as Form

   PROCEDURE Load()
      loadvariable = "load"
      This.ShowVariableTypes("Load")
   ENDPROC 
   PROCEDURE Init()      
      initvariable = "init"
      This.ShowVariableTypes("Init")
   ENDPROC 
      
   PROCEDURE Activate()      
      This.ShowVariableTypes("Activate")
   ENDPROC
   
   PROCEDURE Click()      
      This.ShowVariableTypes("Formclick")
   ENDPROC 
   
   PROCEDURE Unload()      
      CLEAR Events
   ENDPROC 

   PROCEDURE ShowVariableTypes()
      LPARAMETERS tcMethod
      MESSAGEBOX("Message from "+tcMethod+":"+CHR(13)+CHR(10)+;
                 "load:"+TYPE("loadvariable")+CHR(13)+CHR(10)+;
                 "init:"+TYPE("initvariable"))
   ENDPROC 
      
ENDDEFINE

The ShowVariableTypes() method can always see all private variables declared at a stack level before it's call.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top