[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
event other info meaning
EVENT_NONE none event queue is empty
EVENT_OTHER varies a Windows message which is not one of those
below, but which you might possibly wish to
process
EVENT_MENU _LastwParam() the menu id
EVENT_KEY inkey() the keystroke
EVENT_LCLICK MouseX(), MouseY() the x,y position
MouseRow(), MouseCol() the row,col position
EVENT_LDBLCLK \
EVENT_RCLICK \
EVENT_RDBLCLK >--- see EVENT_LCLICK
EVENT_MCLICK /
EVENT_MDBLCLK /
EVENT_REDRAW none re-draw the client area
EVENT_SETFOCUS none getting the input focus
EVENT_KILLFOCUS none losing the input focus
EVENT_WINMOVE _LastLolParam() the x position
_LastHilParam() the y position
EVENT_WINSIZE _LastLolParam() the new width in pixels
_LastHilParam() the new height in pixels
EVENT_DESTROY none the window is being destroyed
EVENT_QUIT none the application should exit
EVENT_CONTROL _LastwParam() the control's id
EVENT_HSCROLL _LastwParam() the scrollbar code
(one of the SB_* values)
EVENT_VSCROLL _LastwParam() the scrollbar code
(one of the SB_* values)
EVENT_ACCELKEY _LastwParam() the numeric id for the accelerator key
EVENT_TIMER none the time delay you set has elapsed
EVENT_LBTNUP \
EVENT_RBTNUP >--- the mouse button was released
EVENT_MBTNUP /
One event that you will not be used to in Clipper is the user
re-sizing a window (signalled by the ChkEvent() return value
EVENT_WINSIZE). You can get the new size as shown in the
table above. Additionally, MAXROW() and MAXCOL() return new
values. It is up to the application to decide how to re-draw
the window's client area, but note that Windows does NOT do
this for you.
You must also re-draw the window's client area when ChkEvent()
returns the code EVENT_REDRAW.
To be able to refresh each window, it's often best to set up
the information you'll need (for example, in an array or
arrays), and then send your own application an EVENT_REDRAW.
The InvalidateRect() function is an easy way to force such an
event.
Another way to set up the information you need to be able to
redraw the screen is to use Clipper local or static variables,
perhaps with a code block to transfer the handling of an event
to the appropriate piece of program code. For a simple
Windows program that has one window (or very few), you will
find this easy. Just structure your program like this:
static bEvent := {|nEvent| nil} // default event handler
.
. // set up the main window
. // and its menu
.
do while .T.
do while (nEvent := ChkEvent()) == EVENT_NONE
// some "background" processing could go here
enddo
eval(bEvent, nEvent) // handle the event
enddo
This is innocent enough, but how does it work? The menu for
the main window provides the answer: when your user chooses a
menu item, the ChkEvent() function runs the code block
associated with that menu item.
Don't worry about the details of the user making a menu
choice. Windows does it all for you: the highlighting,
dropping the menus down, allowing keyboard and/or mouse
activation, and so on. You end up with an EVENT_MENU, which
ChkEvent() handles automatically.
However, it is up to your menu code block to keep the above
event loop doing the right thing. You can do this by changing
the bEvent variable, if necessary, so that a new code block
handles events for as long as you want. Some time later the
user will make another menu choice, thus changing bEvent
again, and so on. (The sample program DEM4.PRG uses this
technique.)
This sort of program is easy to write and understand, but it's
not terribly easy to be modeless. It's also not too easy to
manage multiple windows. The major problem is the use of the
single variable bEvent.
To overcome this problem, you might like to use an array to
hold a code block for each of the separate output areas
(windows). Your event loop should use the window handle to
find the appropriate code block(s) in the array, and run it
(them). This way, to display something new you just add the
appropriate code block to the array. To stop displaying
something you remove the code block. (The sample program
DEM4M.PRG uses this technique.)
NOTE: An improved version of the code presented here is in
the file evhand.prg, and the functions are included in
clip4win.lib.
The skeletal code for this is:
static aWnd := { } // the windows now existing
static aAction := { } // the action code blocks
.
. // set up the main window
. // and its menu
.
do while .T.
do while (nEvent := ChkEvent()) == EVENT_NONE
// some "background" processing could go here
enddo
HandleEvent(nEvent)
enddo
As before, your menus determine what happens. But, this time
you can add a new handler with code like this:
// arrange to send events for window hWnd to the handler bAction
function AddHandler(hWnd, bAction)
aadd(aWnd, hWnd)
aadd(aAction, bAction)
return len(aWnd) // an id suitable for DelHandler()
The mysterious HandleEvent() function is actually very
simple: it can use ASCAN() to find the right handler and then
give the handler the event. You can use the window handle to
find the handler. To allow multiple handlers per window, the
following code works its way all along the aWnd array:
procedure HandleEvent(nEvent)
local hWnd := _LasthWnd(), i := 0
do while (i := ascan(aWnd, hWnd, ++i)) != 0
eval(aAction[i], nEvent)
enddo
return
Although the above is enough, it's convenient in practice to
have HandleEvent() do some special processing for the
destruction of a window: it can make sure the handlers are
removed. Of course, you want your handlers to be passed the
event first so that they can tidy up (e.g. by closing files).
The event is EVENT_DESTROY, as shown here:
procedure HandleEvent(nEvent)
local hWnd := _LasthWnd(), i := 0
do while (i := ascan(aWnd, hWnd, ++i)) != 0
eval(aAction[i], nEvent)
enddo
if nEvent == EVENT_DESTROY
// clean up, so that the event handler needn't bother
do while (i := ascan(aWnd, hWnd)) != 0
DelHandler(i)
enddo
endif
return
In passing, it's worth noticing just how easy ASCAN() makes
things.
For completeness, even though you could no doubt write it
yourself, here's DelHandler():
procedure DelHandler(nId)
adel(aWnd, nId)
asize(aWnd, len(aWnd) - 1)
adel(aAction, nId)
asize(aAction, len(aAction) - 1)
return
Exactly which events you handle is a matter for you, but the
following are the commonest (EVENT_MENU is omitted on
purpose):
EVENT_KEY
EVENT_LCLICK
EVENT_REDRAW
EVENT_DESTROY
EVENT_QUIT
You have an opportunity to do some special processing when
ChkEvent() returns the values EVENT_SETFOCUS and
EVENT_KILLFOCUS, which indicate that your window is receiving
and losing the input focus. (EVENT_SETFOCUS means user input
is sent to your application's window, whereas EVENT_KILLFOCUS
means another window/application will receive any input.)
Often you will not do anything special with these events.
You might like to know how Clip-4-Win converts the messages
from Windows into these values:
event Windows message
EVENT_KEY WM_KEYDOWN / WM_SYSKEYDOWN
EVENT_MENU WM_COMMAND
EVENT_LCLICK WM_LBUTTONDOWN
EVENT_LDBLCLK WM_LBUTTONDBLCLK
EVENT_RCLICK \
EVENT_RDBLCLK >--- see EVENT_LCLICK / EVENT_LDBLCLK
EVENT_MCLICK /
EVENT_MDBLCLK /
EVENT_LBTNUP \
EVENT_RBTNUP >--- WM_xBUTTONUP
EVENT_MBTNUP /
EVENT_REDRAW WM_PAINT
EVENT_SETFOCUS WM_SETFOCUS
EVENT_KILLFOCUS WM_KILLFOCUS
EVENT_WINMOVE WM_MOVE
EVENT_WINSIZE WM_SIZE
EVENT_DESTROY WM_DESTROY
EVENT_QUIT WM_QUIT
EVENT_CONTROL WM_COMMAND
EVENT_HSCROLL WM_HSCROLL
EVENT_VSCROLL WM_VSCROLL
EVENT_ACCELKEY WM_COMMAND
EVENT_TIMER WM_TIMER
Online resources provided by: http://www.ClipX.Net --- NG 2 HTML conversion by Dave Pearson