Jump to content

Close or Free on a form calls CallBack - on hidden forms


vbdavie

Recommended Posts

Farshad;

 

In reference to what I posted about the CLOSE method.

 

procedure TMainForm.Exit1Click(Sender: TObject);
begin
  Close;
end;

 

 

I moved this to a new topic to please this forum.

 

Basically, I have a testform...

   1. I show it

   2. I close it

   3. It calls my CallBack - as expected

 

Now it's hidden. Now if I close my MainModule OR Close or Free the TestForm, the system calls my CallBack function again.

 

Okay, so I looked at the close method in the TuniBaseJSForm unit, it calls the InternalClose method. It should be near the end of the source code. It makes a few "IF" statements and then calls "ExecuteCallBack". This method of course ends up calling my Test form's callback, but the Test form has long since closed. It's closed because I either clicked the "Login" button or the "X" button in the upper right to close the window.

 

Somehow it's not taking into consideration that the callback had already been called, or testing that the window is NOT showing<hidden>.

 

It does the same thing whether I use Show or ShowModal. Also, if I do a uniLoginForm.Free, it does the same thing. The "Free" method causes it to call the ExecuteCallBack procedure as well.

 

I can't help but feel that "I" am the one at fault in not understanding how these web forms are supposed to work.

 

A real simple test is to put a TestForm.Close or TestForm.Free statement inside of the callback for when the form closes :)  It should produce an endless loop.

 

Davie

Link to comment
Share on other sites

Yes, the "Form.FreeOnClose" is set to FALSE.

 

I always check ModalResult, however, it still WILL cause problems, because the InternalClose calls the ExecuteCallBack function which in turn calls my original CallBack function. This function POINTS into my Main.dfm form. And at the time this call is made, the Main form is already destroying itself, so it blows up.

 

Even if it didn't blow up, checking ModalResult won't work, because my callback function will NOT know (based on the ModalResult) that the main form is already gone<freed>. Besides, the ModalResult returns the SAME modal result as it had when you closed the form. IE: mrOk, mrNone, mrCancel, mrWhatEver. It's not like you get some sort of invalid modal result.

 

Make sense?

 

I have attached a "tiny" test project for you.

 

Davie

P.S. Do you find it annoying that in web apps, that you can click on a button several times and the server side logic gets called many times? IE: Client:Click, Client:Click, Client:Click, Server:Event, Server:Event, Server:Event.... INSTEAD OF....  Client:Click, Server:Event, Client:Click, Server:Event, Client:Click, ServerEvent. Too bad they can't be synchronized.

CloseCallsCallBack.zip

Link to comment
Share on other sites

Calling a function from another form is not a good design. It is good to place common methods in mainmodule.

If you are referring to the CallBack function pointing to my main form, then Yeah, normally I don't do that, but there were two options that I could see. 1) I could have the callback inside the login form and refer to controls that were on the main form, OR   2) I could have the callback on the main form and refer to controls on the main form.

 

Since, I have had issues in the past when referring to controls on ANOTHER form, I decided to take the policy of having the callback on the main form. Also, if I decided to have a 3rd orm also show the login form, I would have the callback in that 3rd form. I guess it was just a preference to pick between the two non-perfect choices. See, if I had the code in the login form, then I might have to have a BUNCH of different callbacks sitting in there, if I wanted to be able to use the login form from many other forms. ALSO, if I decided to utilize some other better login form, I could keep most of my code INTACT, while only replacing the call to the NEW login form. So, for maintenence, it was sitting in the back of my mind.

 

Much appreciated that you took a look at it and are taking steps to solve the issue. You are the man!!!!!

 

Davie

Link to comment
Share on other sites

It shouldn't be the case because ModalResult is cleared after each callback.

I agree. BUT, if you run the test program in the IDE and click to "Open Form", and then click the "Login" button, it will have a modal result of "1".

 

NOTE: Make sure to place a break-point inside the callback event where it does the showmessage of the value of the modal result. And make sure you are running in debug configuration and not the release configuration.

 

THEN, click the "Close App" button and then after about a couple seconds, you will see the IDE stop in the callback event, AND if you check the value of modalresult in the callback event, it will be "1". The same value as before when the callback was called the first time.

 

Tell me if you get those results, because I do on my end.

 

And for fun, when you click the login button on the login form, it should enter debug mode at the breakpoint that you set. WHILE the IDE is sitting there in a paused execution, go back to the web page and click on the "X" on the login form. Click it many many times. Of course the server side execution is still halted in the IDE. Now go back to the IDE and tell it to continue, it will then STOP again on the callback, in fact you can tell it to run (F9) several times. It will enter the callback function about as many times as you had clicked on the "X". SO, even though I have the form using "Mask", somehow these events are still comming through. Interesting.

 

Davie

Link to comment
Share on other sites

  • Administrators

I will prevent Callback from being called several times, but you should follow regular guidelines we have demonstrated in our demos.

 

For example:

-You have designed your own login mechanism while we have one built-in which is correct and secure way of doing it.

-Setting FreeOnClose->False should not be used unless it is necessary for a reason. As a general uniGUI rule a form must be freed when user closes it.

Link to comment
Share on other sites

I will prevent Callback from being called several times, but you should follow regular guidelines we have demonstrated in our demos.

 

For example:

-You have designed your own login mechanism while we have one built-in which is correct and secure way of doing it.

-Setting FreeOnClose->False should not be used unless it is necessary for a reason. As a general uniGUI rule a form must be freed when user closes it.

 

I understand your point, if it relates to using system resources to keep stateful data. It's true that keeping forms in memory will consume for ram per user. My app will only need to handle from 100 to 500 users. Our system has 48GB of RAM and the ram utilization would be able to handle many more times my requiement. So, I'm more interested in getting app finished faster and easier, and keeping user settings in form data is simpler than saving/retrieving from a database. So, in my situation, I want to keep the settings screen hanging around in memory. My test app showed a login screen, but my usage is really for settings and such.

 

It's like GDI resources, keep them low and use them for the shortest amount of time. Makes sense.

Or, it's like the "NO GOTO" rule. I agree from a visual statndpoint, it's a good rule and keeps you out of spahgetti code. But from a MASM/TASM/ASM point of view a lot of constructs like "Case", "If Then", "Break", :Continue", 'Exit" all have implied "goto" built in, and in my 500,000 line app, I have about 12 actual GOTO statements.

 

Thanks for taking the time to make it work.

 

Davie

Link to comment
Share on other sites

Farshad;

 

I couldn't tell from your response, if you were also fixing the issue of the callback being called "many" times IF YOU CLICK ON THE "X" many tijmes quickly.

And for fun, when you click the login button on the login form, it should enter........

 

To make things easier to test, put in a sleep(3000) in my callback to test this out. I clicked the "X" to close the form, I clicked it about 6 times in a row and then waited and sure enough, my callback was called 6 times.

 

On my form properies, I set the ScreenMask.enabled to true, but it still allowed my to click on that button multiple times. Seems like some synchonization could be done to fix that. Otherwise, I might have to be relagated to using the following scheme.

 

procedure TMainForm.LoginCallBack(Sender:TComponent;ModalResult:TModalResult;HomeLink,ThemeSkin:Integer);
begin

If FBusyLoginCallBack<>0 Then Exit;

Inc(FBusyLoginCallBack);
Sleep(3000);  // Give user time to click the "X" on the form many times.
ShowMessage('Form is now closed: ModalResult = '+IntToStr(ModalResult));
Dec(FBusyLoginCallBack);
end;
 

 

What are your thoughts? Don't know what else to do. BUt I am new to this way of thinking, so maybe you have magic bullet?

 

Thanks in advance

 

Davie

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...