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!

Forms: Parent & Child 1

Status
Not open for further replies.

SitesMasstec

Programmer
Sep 26, 2010
508
Brasil
Hello colleagues:

When I run my parent form, it calls a child form.

In the child form, if it got an error (please see '1') it returns to the parent form, but then, child form is active again, because it continues (please see '2'):
FormParentChild_pxdn2x.jpg


How to stop parent form from returning to child form after error show in '1'?

Well, I could not find an explanation in books, video, etc about the differences in
Code:
thisform.Release
thisform.Deactivate
thisform.Hide
etc


Thank you,
SitesMasstec
 
It's a common misconception that doing Thisform.release() will end a form AND also not continue executing further code.

Well, the latter is not the case, so if you want to endd after the first IF casae becomes true, make the overall code a DO CASE..ENDCASE steemtne instead of a series of IFs.

You're kiddding that you find no explanation or differences in Release, Deactivate Gid, and you go tot be more specific about what else you mean with "etc."

All these methods and events are described and have their help topics. Be more concrete about what you don't understand. I won't and I aswsume noone would just describe those methods and events provided they already are described and all we could do is repeat what'S already been written about all of them. So what's somehitng you don't see explained about these?

I think you look for something to end a form. Well, then the major advice is already given. Release is the right method to call. But you think there is anxything the immediately ends a form, that's your only faulty assumption.

So what you need to change here is the IF statement series, that's the bad idea. Instead do
Code:
 LOCAL llReleaseForm
DO CASE
    CASE LEN(...) && error case 1
        MESSAGEBOX()...
        ...
        llReleaseForm = .T
    CASE LEN(...) && error case 2
        MESSAGEBOX()
        ...
        llReleaseForm = .T.
    OTHERWISE && no error
       llReleaseForm = .F.
ENDDO

If llReleaseForm
   Thisform.Release()
Else
   ...
Endif

Chriss
 
Notice, there also is a single command to use for ending a method and not doing all the rest. It's RETURN.

Chriss
 
Oh, sorry, the old RETURN command.

But I used it some days ago, but what happens is that the parent form appears blank. But when I rerun it,it appears with data.

I will try orher commands, thanks, Chriss.



Thank you,
SitesMasstec
 
Chriss, I mean, I will use RETURN, of course, and other command to have the parent form show data after returning to it.

Thank you,
SitesMasstec
 
There's a section of code you in the child form hve under the 2nd IF statement, did you remove that?

How is the child form called? And if it's used to specify a filter for data, how is that turned into effect for the parent form? Is it returned at all? Do you pt the child form in the same data session as the parent and influence it's workareas or did you not think any of this through?

Chriss
 
And please, SitesMasstec

Two things:

1. Don't ever post screenshots of code, post the code as text. It helps much more, if we'd want to answr with mended code.

2. stete what's the intentiopn of your code. Experts can usually read code and know what it does, but we can only assume what it's intention is, esepcially if it's not right. And that's why you post, usually. So please, nobody is in your mind, you have to tell what's the intent.

Chriss
 
If this construct is what I assume it is, I see a common misconception and misarchitecture in this.

You list data and allow the user (optionally), to filter it.

When your application ages and the data grows, that'll mean your list very likely grows that large and long, that the first few rows are oldest and not of interest for the user, so the user will take the option to filter.

Then the older the application becomes, the most often the user will enter a filter, and so it is better architecture to first start the filter form, not the main form, define the filter condition there and only fetch the necessary data to list afterwards.

That's the better logical construction.

I know it is very convenient to list a whole table and apply a SET FILTER on it, but that's no good service to the users in the long run.

They might even order it that way, as in the first phase the whole list of data i managable and it's an annoyance to be asked for a filter, if all data is a few records only. But it's easily done, if your filter form will result and allow no filtering, if no input is made and the users just press ENTER or click a filter button to then start the main form.

Chriss
 
Dear Chriss:
Sorry for the incovenience with my images and thanks fot your patience. English is not my native language.

Now, with your valuable help, the program is working fine, thank you very much. Bellow are parts of the code used in it.

My parent form has the following code to call a child form:

1) Parent form, Click event:
Code:
THISFORM.LostFocus
DO FORM CADASPOR     && CADASPOR is the child form
THISFORM.GotFocus    && See item 3 bellow
THISFORM.Refresh()


2) Child form, button to add a new record to table (which is shown in the parent form), procedure Click:
Code:
IF EntradaValida="Sim"
SELECT PORTOS 
GOTO TOP
SET ORDER TO SIGLAPOR   && SIGLAPOR
SEEK thisform.txtSiglaPorto.Value
IF FOUND()
	MESSAGEBOX("Sigla de Porto já cadastrado",0, "Erro") 
ELSE
	APPEND BLANK
	REPLACE SIGLAPOR WITH thisform.txtSiglaPorto.Value
	REPLACE NOMEPOR  WITH thisform.txtNomePorto.Value
	SET ORDER TO NOMEPOR   && NOMEPOR
ENDIF
thisform.Release
RETURN    && Go back to parent form
ENDIF

3) Parent form, Procedure GotFocus:
Code:
THISFORM.Grid1.Refresh


Thank you,
SitesMasstec
 
Not sure whether your first code section is the actual code - and if so where it is located - or you meant to say that you programmed into the main forms Lostfocus event and into the mainforms GotFocus event.

Anyway, the DO FROM does the child form, I guess. That is what makes thaqt nbew child form get the focus and the main form lose the focus. There are further events going on, but one thing you should know for all time: You don't call events. Events are always caused by he events they are named after, so the form.LostFocus event happens, when any control of any other (VFP) form (of the same VFP process) gets focus. In short that means when you DO FORM (I assume you do that in a button or you may do it in the form init event) Then this new for4m gets the focus, or precisely said one control of that childform. Thus all controls of the main form lose focus which finally also means the form Lostfocus event runs.

If you run an event, you don't cause the event. So if you call form.lsotfocus or also for example call form.deactivate() that's not letting the form lose the focus or get deactivates, an event is not caused by calling the event method, the event method is executed because the event happens. If you call an event method, you just cause the code in this event to run, even though the event didn't yet happen.

And therefore that's wrong usage of events.

Next topic: RETURN.

While things work now, you get wrong why I recommended RETURN to you.

You initially said:
SitesMasstec said:
...but then, child form is active again, because it continues (please see '2'):


To prevent that I gave two alternative solutions, one was reaqrranging code into a DO CASE statement where each case is handled separately so you only get one messagebox and not both, the alternative solution I suggested was ending the method with a RETURN that would be put into the IF branch after.

I had and likely still have the wrong idea about what Thisform.Release() does, because the help say it releases and thereby ends a form. Well, it does, but it can only release the form, when all current code is done, so what is not happening is that all code and the form is unloaded. The current block of code has to firswt finish, that's why you see the second message, too. What you said is telling you think the child form is activated again, no it is not, it just is still active.

So things like Thisform.Release() or also other commands like QUIT, for example, have no immediate effect. That's what's wrong in your assumptions.

The way you programmed it now does not need that RETURN, as that's now in the last line of code (the ENDIF isn't really code executing it's just syntax to and the IFD statement).

Well, a method, an event, a procedure or a function, even a PRG, all of which you can think of as the currently executing block of code on the callstack, all of these have one thing in common: They end only in 3 concrete ways:

1. There is no next line, the code ends, VFP will automatically do RETURN .T. in such a case
2. There is a RETURN progrmmed by you, that can also return .t. or any other value, but also a simple pure RETURN on its own works that way.
3. The CANCEL command. It's a bit more drastic than RETURN and may usually not be what you want to use, because it could end more.

Even though that last remark sounds it could help end the child form, no it's not what you'd use here.

Well, for completenesss sake an error happening can also cause an interruption, but that's not an exception I forgot, it's still possible the error handling code returns to the codeblock, which had the error, so even an exception like an error is not ending the current code.

That's what not only you don't have in mind.

RETURNs main usage is to retrun some value to a caller, it's the most significant line of a function returning its result to the caller.

Well, let's think about the caller. In your mind the caller of the childform is the mainfo. But that doesn't matter here at all. The "caller" of the click code is the button click event. So it's the OS provcessing an event. And the OS isn't receiving what you return. So the only reason to use RETURN from a click event of a button ius, that your code is structured in a way that you need to stop all further code from executing, so you RETURN. You don't return to the main form with that, not directly. You return to the idle state the application has before the mouse click triggered the button click code. That's what you return to.

And what happens next is that the current code block is done, no further events may be queued to also be executed next, so the release finally can cause its effect.

So in very short, if you don't understand and maybe don't even want to understand what I explained, when you want a call of THISFORM.RELEASE() to act immediately, end the current code block by also doing RETURN in the next line. Unless it's in the last line of code (except any ENDIF, ENDCASE, ENDDO, etc. syntax structure).

What activates the main form after the child form eventually releases is that the main form was the previously focused form, no more, no less. Not the RETURN.

And what you programmed into the main form GotFocus is okay, that could also be in the Activatge event, but does not matter that much.

All in all the click code in the main form can be reduced to just do the child form:

Code:
DO FORM CADASPOR     && CADASPOR is the child form

The click code of the "save" button of the child form creating a new record could then just be:
Code:
IF EntradaValida="Sim"
SELECT PORTOS 
GOTO TOP
SET ORDER TO SIGLAPOR   && SIGLAPOR
SEEK thisform.txtSiglaPorto.Value
IF FOUND()
	MESSAGEBOX("Sigla de Porto já cadastrado",0, "Erro") 
ELSE
	APPEND BLANK
	REPLACE SIGLAPOR WITH thisform.txtSiglaPorto.Value
	REPLACE NOMEPOR  WITH thisform.txtNomePorto.Value
	SET ORDER TO NOMEPOR   && NOMEPOR
ENDIF
thisform.Release

&& no RETURN here, unless there's further code in the click you don't want to run anymore.
ENDIF

Last not least I made the error to offfer you two alternative solutions without pointing out one of them is enough, sory for that.

Applying both solutions wasn't getting you into trouble, but doing unnecessary things, besides some things that had nothing to do with my previous answer.

Chriss
 
I think I see another problem in your code, as you don't think throughh all cases.

When you finally always want to end up using the order by index tag NOMEPOR, then only restting it in the ELSE case means you end up with order by the index SIGLAPOR in case the entered txtSiglaPorto Value is found.

There's a simple way out: not changing the set order at all.

You can search an index without moving the record pointer and without changing the SET ORDER, simply use the INDEXSEEK() function:
Also:
-No need to GO TOP before a SEEK, seek always searches all records
-Do an INSERT-SQL statement instead of APPEND and a series of REPLACEs

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top