Preventing form deactivation in Delphi 6

We have a Delphi 6 application that uses a modeless form with editing in the grid. As part of the FormClose event, we verify that the records are square and prevent closure if they are not.

However, if the user clicks on the main form behind, then the original form disappears behind (as expected), but this allows the user to switch to a new entry on the main screen without changing them in the grid, were confirmed.

I tried the FormDeactivate event, which fires, but doesn't seem to have a mechanism to prevent deactivation (as opposed to the ActionClose parameter of the FormClose event). I tried OnExit from the grid, but it does not work when deactivated. I tried to capture the WM_ACTIVATE message and set Msg.Result = 1, but this has no effect (perhaps because another WM_ACTIVATE message is being sent to the main form?).

So, I'm looking for ideas on how to (conditionally) prevent a form from being deactivated when the user clicks on another form. (PS I do not want to change the form style to fsStayOnTop)

thanks

+2
source share
6 answers

Thank you all for your help and suggestions.

Here is the solution I went with: In the "Grid Form" (like Form2) ...

public PricesNotSquare: boolean; 

In the FormDeactivate event, set the PriceNotSquare parameter to true if they do not match.

In the OnActivate event of the main form, ...

  if Assigned(Form2) and (Form2.PricesNotSquare) then begin ShowMessage( 'Please ensure the total Prices match before leaving the form' ); Form2.Show; exit; end; // other form activate stuff here 

It turned out that this is a simple solution, it just took some time to get it.

Everything seems to be fine, but if he has problems, I will include the idea of ​​sending a message.

0
source

When you call ShowModal , all forms except the one shown will be disabled. They turn on again immediately before ShowModal returns.

Display the editing form modelessly, and when the data starts to be edited, create the form yourself, disconnecting another form. Include another form when editing is complete. Disabling windows is not always as easy as setting the Enabled property. I would suggest using DisableTaskWindows , but it would disable all windows, including the edit form. However, see how this is implemented in Forms.pas. It stores a list of all disabled windows, so after that they turn on again.

+1
source

The classic rule in Windows is that you cannot change focus during the focus change event. The OnDeactivate event occurs during a focus change event. Your form says that it is deactivated - the OS does not request permission - and at the same time, it tells the other form that it is being activated. No window has the right to speak on this issue, and an attempt to change focus during these events will lead to confusion of all windows. Symptoms include the presence of two windows that draw themselves, as if they have focus, and messages with the keyboard go nowhere, despite the fact that the input cursor blinks. MSDN is even more terrible, although I have never seen anything wrong:

When processing this message [ WM_KILLFOCUS ], do not make any function calls that display or activate the window. This causes the thread to take control and may cause the application to stop responding to messages. See Message Alerts for more information.

Since you cannot deny a change in focus after it has begun, you need to do so to postpone the processing of the event until everything goes down. When your editing form is deactivated and the data on it is still invalid, publish the message form. Posting puts the message at the end of the message queue, so it will not be processed until all previous messages, in particular notifications of focus changes, are processed. When the message arrives, indicate that the data is invalid and set the focus back to the editing form:

 const efm_InvalidData = wm_User + 1; type TEditForm = class(TForm) ... private procedure EFMInvalidData(var Msg: TMessage); message efm_InvalidData; end; procedure TEditForm.FormDeactivate(Sender: TObject); begin if DataNotValid then PostMessage(Handle, efm_InvalidData, 0, 0); end; procedure TEditForm.EFMInvalidData(var Msg: TMessage); begin Self.SetFocus; ShowMessage('Invalid data'); end; 

I must point out that this answer does not technically answer your question, since it does nothing to prevent the decontamination of the form, but you rejected my other answer , which really prevents decontamination.

+1
source

You can also enter a state in your model that tracks if the window needs focus, as you describe it here, and use onFocus handlers on other forms that programmatically set the focus back to the grid window.

[Edit] Copy of my comment:

You can register for the onShow event of the grid forms. (If you implement it, be sure to make it somehow configured to minimize the grid’s dependence on the existing application layout. Perhaps by providing a method that is invoked by forms, which in turn trigger the registration of grid events in the invoking form for the onShow event)

More about event registration:

You can attach event handlers programmatically. There is a lot about this in the network. I do not have Delphi available here, so I cannot copy working code now.

Pseudocode for programmatically joining an event!

 myform.onShow=myGrid.formOnShowHandler; 

formOnShowHandler has the same signature as the functions that the IDE generates for onShow events. It has a parameter that you can use to find out which form the handler called so that you can reuse this function and just put the form in the background and show your grid shape again (which will be, for example, the parent of the grid).

0
source

Delphi 2006 introduced OnMouseActivate events. The main OnMouseActivate form allows you to prevent the activation of the main form if another form is visible.

This, of course, does not work with D6.

0
source

This is not a very helpful answer to David, but I think I will have to agree with other respondents that this is the wrong approach. There are so many ways that things can go wrong, that stopping and looking at another way to solve your problem may be better.

Even if you manage to find an event / method / message that does what you want, you still have to deal with the scenario when the electricity goes out.

In a slightly more useful note, did you try disabling your main form until ready? You can put all the controls in a panel, and then just

 panel1.enabled := false; 
0
source

All Articles