Close_Panel - MdiDialog
Closes the panel or component currently open
Type: Procedure
Syntax
Procedure Close_Panel
Call Example
Send Close_Panel
Description
Closes the panel or component currently open. If the control Close_Panel is sent to is not a panel, the call will be delegated to its parent.
For example, if a cDbRichEdit control is in a dbView, sending Close_Panel to the cDbRichEdit control will close the dbView.
Deactivation
Deactivation is the process of closing an active dialog. From a user's perspective, the view or dialog is closed and no longer visible or usable. Internally, the dialog and all of its children are removed from the DataFlex focus tree, all Windows objects in the dialog are destroyed and the focus is moved to some other part of the application.
Unlike the activation process, where views and modal dialogs have slightly different behaviors, the deactivation process for these two types of dialogs are the same. However, there are significant differences between DEO (dbView, dbModalPanel) and non-DEO (View, ModalPanel) dialogs.
Deactivation and DEO Dialogs
We will start with DEO dialogs, because these are what you will use most often.
Close_Panel
Exit_Function
Request_Cancel
Verify_Exit
Execute message in Verify_Exit_Msg. If non-zero is returned, cancel
Deactivate (sent to the dialog object)
Send Activate to another dialog (focus-change)
Release_Focus
Broadcast Release_Focus to focus children
Remove_Object (remove object from focus tree)
Deactivating
Page_Delete (destroy Windows control)
As you can see, this process is a bit complicated and in reality, it is far more complicated. Therefore, we will start with the simple part. Here is what you need to know to control deactivation.
- Send Close_Panel to close a dialog. You can send this to the dialog or any object in the dialog
- Create your own "can-close" function which returns non-zero to stop the deactivation. Set its message ID in the Verify_Exit_Msg property in the dialog object.
- Use the Deactivating event to handle any "is closing" logic. Deactivating is sent to every active object in the dialog.
- Do not augment or send any of the other messages.
If you follow these steps, you don't have to worry about the complications I am about to describe. The main complication is that DEO objects try to do too much. You might think that all of these messages (Close_Panel, Exit_Function, Request_Cancel, etc.) are all defined and handled by the dialog object via delegation. With DEO child objects, this is not the case. Each individual DEO's class understands and handles these messages directly. To make matters worse, these objects might send different messages to close the dialog (Close_Panel, Exit_Function, or Request_Cancel). To add one more complication, non-DEO objects (such as buttons) don't understand any of these messages and they do delegate. This makes it rather difficult to know which messages should be augmented. Depending on where the focus is, different close messages are being sent to different objects. The good news is if you don't augment any of these messages, this will all work out. As long as you place your can-close function and its Verify_Exit_Msg in the dialog, you will get consistent behaviors. The Verify_Exit message searches through parent DEOs looking for a non-zero Verify_Exit_Msg. If you set Verify_Exit_Msg in the outer dialog, all objects will find it and use the same can-close function.
As an example, adding the following code to a dbView or a dbModalPanel would only allow you to close a dialog when the current time has an odd seconds value (a nice technique that will drive anyone crazy).
Object oDbAwareModalDialog is a dbModalPanel
Set Label to "Label..."
Set Size to 89 211
Set Border_Style to Border_Thick
Function CancelClose Returns Boolean
DateTime dDT
Integer iSec
Boolean bStopIt
// silly test that returns true to stop deactivation
// if the current seconds value is even.
Move (CurrentDateTime()) to dDT
Move (DateGetSecond(dDT)) to iSec
Move (Integer(iSec/2) = (iSec/2.0)) to bStopIt
Function_Return bStopIt
End_Function
Set Verify_Exit_Msg to (RefFunc(CancelClose))
Deactivation and Non-DEO Dialogs
The deactivation of a non-DEO dialog is much simpler. Since you are not allowed to nest DEO objects inside of a non-DEO container, we know that none of the objects are DEOS. Deactivation looks like this:
Close_Panel
Deactivate
Send Activate to another dialog (focus-change)
Release_Focus
Broadcast Release_Focus to focus children
Remove_Object (remove object from focus tree)
Deactivating
Page_Delete (destroy Windows control)
Just like in DEO dialogs, you send Close_Panel to deactivate the object. In this case, sending Close_Panel to any object in the dialog will result in the message delegating to the dialog object. If you wish to stop the deactivation, augment Close_Panel and don't forward send.
Here is an example of how you could control whether a non-DEO dialog can be closed.
Object oNonDbAwareModalDialog is a ModalPanel
Set Label to "Label..."
Set Size to 89 211
Set Border_Style to Border_Thick
Function CancelClose Returns Boolean
DateTime dDT
Integer iSec
Boolean bStopIt
// silly test that returns true to stop deactivation
// if the current seconds value is even.
Move (CurrentDateTime()) to dDT
Move (DateGetSecond(dDT)) to iSec
Move (Integer(iSec/2) = (iSec/2.0)) to bStopIt
Function_Return bStopIt
End_Function
Procedure Close_Panel
Boolean bStop
Get CancelClose to bStop
If not bStop Begin
Forward Send Close_Panel
End
End_Procedure
The Deactivation Process
Once deactivation has begun (once the Deactivate message is sent), the process is the same for all dialogs. Once deactivation has started, it cannot be stopped and if it is stopped, this is a programming error and your application will not be stable.
The Deactivate message works in two modes. It is used to find the outer "area" object to deactivate and it is then used to actually deactivate an object. You have to know how to send this message with the right parameters and you have to know how to augment it properly. Leave it alone! Don't send or augment it.
When you close a dialog, you want to make sure there is somewhere else for the focus to move to. With views, this is rarely an issue. With modal dialogs, the system will attempt to give the focus back to the object that had the focus when the modal dialog was invoked. If, for some reason, this object cannot retake the focus, it is a programming error and your program will not be stable.
Child objects are deactivated before the parent object is deactivated.
The Deactivating event is sent to every active object in the dialog in a bottom up fashion. You cannot use this event to cancel deactivation. When Deactivating is called, the object is already removed from the focus tree (Active_State is zero), but the Windows control still exists (Window_Handle is non-zero). In addition, all child objects are already deactivated (removed from the focus tree and the Windows control destroyed). The Page_Delete event actually destroys the Windows control.
If you augment Deactivating, you are most likely to augment it only in the dialog object.
Working with Modal Dialogs
Modal dialogs are modal for a reason. You want to invoke them at a particular moment and suspend the rest of your application until this modal dialog process provides you with the information you need to continue. While you could use some of the messages we've discussed here, such as Popup and Deactivating, to handle pre- and post-processing needs, that is usually not the best strategy.