Don't Close that
Window
Clarion for Windows Tips 
March 1997
A common question on the TopSpeed forum and the
Clarion newsgroup is "How can I keep my window from
closing when the user presses the Escape key?" One
answer to this question lies in learning to control the
CloseWindow and CloseDown events. This tip looks at
methods for controlling the way that these events are
handled and how those choices affect the way that a
window closes.
Window Workings
A Clarion window is almost always associated with an
ACCEPT loop. The ACCEPT loop processes the Windows
messages destined for a particular window and handles
most of the tasks that make a window work correctly. The
basic code structure that supports this is:
OPEN(Window)
ACCEPT
END
CLOSE(Window)
This code opens a window, processes messages in an
ACCEPT loop, and then closes the window when the program
exits the loop. There are two ways to exit the ACCEPT
loop: the ACCEPT loop will automatically terminate after
a CloseWindow or CloseDown event or the program can
explicitly break out of the ACCEPT loop using a BREAK
statement.
Several user actions can generate a CloseWindow event,
including:
- pressing Ctrl-F4 on an MDI child window
- pressing Alt-F4 on a window that is not an MDI
child
- clicking the "X" button on a Windows 95
window
- choosing Close from the window's control menu
- pressing the Escape key when a window has focus
All of these actions generate a Windows message that
is received in the ACCEPT loop as EVENT:CloseWindow.
The CloseDown event only occurs after an application
frame receives a CloseWindow event. The CloseWindow event
is first posted to the application frame's thread and
then the CloseDown event is posted to each of the other
threads to indicate that the application will be closing
down. If any of the child window ACCEPT loops does not
terminate, the application frame will not close. Except
for this difference, the events are essentially the same,
so I will only refer to the CloseWindow event for the
rest of this tip. In most situations you will end up
using the same code for CloseWindow and CloseDown in a
structure similar to this:
OPEN(Window)
ACCEPT
CASE EVENT()
OF EVENT:CloseWindow
OROF EVENT:CloseDown
!Do your stuff here
END
END
CLOSE(Window)
The sample program
for this tip illustrates the techniques described in this
tip. The program opens an MDI frame and allows you to
open child windows that use the control structures
described below. Rather than including the code in this
tip, the sample program illustrates the techniques
discussed.
The first two items on the sample program menu, Basic
MDI Child and Basic Non-MDI Child demonstrate
the basic window support code shown above. Additional
code has been added to show when the CloseWindow and
CloseDown events occur, but other than that the code
structure is exactly the same.
Cycling the ACCEPT Loop
When the CloseWindow event is received, the default
action is to break out of the ACCEPT loop at the end of
the cycle. Additional actions can be added with embedded
code, but unless a CYCLE statement is executed, the
program will exit the ACCEPT loop when it reaches the
bottom of the loop.
This technique is illustrated with the Window That
Always CYCLEs choice from the menu. A CYCLE statement
is executed whenever a CloseWindow event is received.
This arbitrary cycle statement is not the best solution
because it requires some other way to break out of the
ACCEPT loop. A much cleaner solution is to use some kind
of conditional structure to determine if the CYCLE
statement should be executed or not. The next two menu
items illustrate this.
When Window with MESSAGE Box receives a
CloseWindow event, it uses the Clarion MESSAGE function
to display a dialog window asking if the window should
close. If the user does not press the Yes button then a
CYCLE statement is executed to keep the window from
closing. Window with Check Box has a check box to
determine if the window should be allowed to close. If
the check box is not checked then a CYCLE statement
executes to keep the window open.
Using a Close Button
Many windows provide a Close or Cancel button as an
additional way for a user to close the window. I provided
a Close button on the Window That Always CYCLEs so
that there would be some method to get out of the ACCEPT
loop and close the window. In order for a button to close
the window, it must either manually BREAK out of the
ACCEPT loop or post a CloseWindow event so that the
ACCEPT loop terminates on its own. I recommend posting a
CloseWindow event to accomplish this. Window With
CLOSE Button demonstrates this in action.
It is possible to use this technique in reverse - to
have the CloseWindow event post an Accepted event to the
Close button and have the Close button contain the logic
for closing the window. Window With Incorrect CLOSE
Button uses this method. A problem with this method
shows up when the CloseDown event is posted to the
window.
When the application frame gets a CloseWindow event
and a CloseDown event is posted to each of the child
windows. When the CloseDown event is received in a child
window using this technique, an Accepted event is posted
to the Close button but the ACCEPT loop must be CYCLEd in
order for the loop to stay active so that the Close
button can receive its event and close the window. When
the CloseDown event is CYCLEd, it keeps the application
frame from closing. Even if the logic in the Close button
code closes the window, the application frame will not
close.
The best way to avoid this problem is to always put
any logic that should happen when the user cancels a
window (Cancel button, Escape key, or close application)
in the CloseWindow/CloseDown event block and have the
Close or Cancel button post the CloseWindow event. Logic
for when a user completes a window (OK button or Save
button) should be placed in that button's code and the
code should explicitly BREAK out of the ACCEPT loop.
All I Wanted Was to Take Care of Escape!
If you only want to block the Escape key and don't
mind what else happens with the window, you can avoid
having to twiddle with events at all. If you ALERT the
Escape key for a window (or for a single control) then
the Escape key generates an AlertKey event instead of a
CloseWindow event when it is pressed. Except for this
change, the window's behavior is not affected at all.
Thanks to Tom
Foley for brining this to my attention..
Copyright © 1997-1999 - The Computer Guy - steve@compguy.com
Last updated Thursday, December 16, 1999
|