Event Property
Description
This property defines how an object responds to user actions.
Unlike other properties which only have a single value, this property has a value corresponding to each of the different types of event that may be generated by a particular object. Consequently the syntax for setting the Event property differs from the general syntax that applies to other properties.
Two syntactic forms are allowed:
- A 3 or 4-item vector containing the property name
'Event'
, followed by the Event Type(s), a value which determines the action to be taken, and an optional array that will be supplied as a left argument to the callback function - A composite vector whose first element contains the property name
'Event'
, followed by a series of 2 or 3-element vectors, each defining the action to be taken for a different Event Type (or types).
Examples
'Event' 'MouseUp' 'foo' 88
'Event' ('MouseUp' 'MouseDown') 'foo' 88
'Event' ('MouseUp' 'foo' 88)('MouseDown' 'goo')
Like any other property, the Event property can be set using assignment. However, certain special considerations apply which are discussed later.
When you specify the Event property using ⎕WC
or ⎕WS
, the action to be taken for an event type or types is specified by a 2 or 3-element vector containing:
Element | Item | Description |
---|---|---|
[1] |
Type(s) | see below |
[2] |
Action | numeric scalar or character vector¯1 inhibit (ignore) event0 handle event, do not report to APL1 handle event, then report to APLfn name of callback functionfn& name of callback function to be executed asynchronously⍎expr expression to be executed |
[3] |
Arg | any array (optional) |
Event Types
The first element, Type(s) may be one of the following:
- A character vector containing an event name (for example
'MouseUp'
) - A numeric scalar containing an event number (for example
2
). If the number is not one of the built-in event numbers generated by the object, it is assumed to be a user-defined event which can (only) be generated anagrammatically using⎕NQ
- A vector of character vectors containing a list of event names, for example
('MouseDown' 'MouseUp')
. This may be used as a shortcut to associate several different types of events with the same action - An Event name preceded by the string
'on'
(for example'onMouseUp'
) - An event number preceded by the string
'on'
(for example'on99'
). This syntax is intended for user-defined events although it can be used with regular events too.
The onEvent syntax causes all objects reported in the event message (see below) to be identified by a ref. Otherwise, objects reported in the event message are identified by name.
Action
Inhibit (¯1
)
If Action is set to ¯1
, the event is inhibited (if possible) by APL. If, for example, you set the action on a KeyPress event
to ¯1
, all keystrokes for the object in question will be ignored. Similarly, if you set the action on a Close
event for a Form to ¯1
, the user will be unable to close the Form. This is possible because APL intercepts most events before Windows itself takes any action. However, certain events (for example, focus change events) are not notified to APL until after the event has occurred
and after Windows has itself responded in some way. In these circumstances it is not always practical for APL to undo what Windows has
already done, and an action code of ¯1
is treated as if it were 0. For further details, see the individual entries for each event type in this chapter.
Default Processing (0)
If Action is set to 0
(the default), the event is processed by APL and Windows in the normal way (this is referred to herein as the default
processing) but your program is not notified in any way that the event has occurred. For example, the default processing for a keystroke is to action it and either echo a character in the object or perform some other appropriate function.
Terminate ⎕DQ
(1)
If Action is set to 1, the event is first processed by APL (and Windows) in the normal way, then ⎕DQ
terminates, returning an event message as its result. The format of the event message is given under the description of each event type.
Callback (function name)
If Action is set to a character vector that specifies the name of a function, this function (termed a callback) will be executed
automatically by ⎕DQ
every time the event occurs. The function may be a traditional defined function or a dfn.
A traditional defined function may be monadic, dyadic, or niladic. If dyadic, the left argument may be optional. A niladic callback may be appropriate if the function can perform its task without needing to interrogate the event message.
Unless the callback function is niladic, it will be supplied a right argument (⍵
for a dfn) containing the event message and a left argument (⍺
for a dfn) of the value of the array Arg (if specified).
The function may be defined to return no result, a result, or a shy result. The result determines how the event is handled.
The default processing of the event is deferred until after the callback has been run, and may be inhibited or modified by its result. If the callback function returns no result, or returns a scalar 1, normal processing of the event is allowed to continue as soon as the callback completes. If the callback returns a scalar 0, normal processing of the event is inhibited and the effect
is identical to setting Action to ¯1
. A callback function may also return an event message as its result. If so, ⎕DQ
will action this event rather than the original one that fired the callback.
If a callback function does not exist at the instant it is invoked, ⎕DQ
terminates with a VALUE ERROR
. However, the name of the missing function is reported in the Status Window.
Asynchronous Callback (function name followed by &)
If Action is set to a character vector that specifies the name of a
callback function, followed by the character &
, the
callback function will be executed asynchronously in a new thread when the event
occurs.
For example, the event specification:
'Event' 'onSelect' 'DoIt&'
tells ⎕DQ
to execute the callback function DoIt
asynchronously as a thread when a Select event occurs on the object. Note that a callback function executed in this way should not return a result (because ⎕DQ
does not wait for it) and any result will be displayed in the Session window.
Execute
If action code is set to a character vector whose first element is the execute symbol (⍎
) the remaining string will be executed automatically whenever the event occurs. The default processing for the event is performed first and may not be changed or inhibited in any way.
Notice that when you specify the action to be taken on the occurrence of an event there is a great difference between 'FOO'
and '⍎FOO'
. The former causes APL to invoke the function FOO
as a callback function. If the function takes an argument, APL will supply it with the event message. Secondly, the result (if any) of the function FOO
will be used by APL and may cause the event to be disabled or changed in some way. In the second case, APL will perform the default processing for the event and then execute FOO
without supplying an argument. If the function returns a result, it will be displayed in the Session.
Optional Left Argument (Arg)
If specified, Arg is an array whose value will be passed as the left argument to a callback function when that particular event (or events) is generated. Note that this is a constant defined when the value is assigned to the Event property.
If the callback function is defined to take an explicit left argument and Arg was not specified, the call will fail with the error message:
SYNTAX ERROR: The function requires a left argument
⍺
for a dfn) will generate VALUE ERROR
.
Event Message
When a callback function is invoked by ⎕DQ
, the corresponding event message is supplied as its right argument. The event message is a vector whose first 2 elements identify the object that generated the event and the type of the event. Additional elements may be provided, depending upon the type of the event.
The same event message is returned as a (shy) result by ⎕DQ
when it is terminated by an event whose Action is set to 1.
Object(s)
The first element of the event message always identifies the object that generated the event. Other elements may identify other objects associated with the event. For example, a DragDrop event reports both the object being dropped, and the object on which it is being dropped.
Objects are identified by names or refs. If the Event property was set using the onEvent syntax (whereby the event name or number is prefixed by the string 'on'
), for example, 'onSelect'
or 'on99'
, objects are identified by refs. This is also true if the object which generated the event has no name (that is, was created by ⎕NEW
). Otherwise, objects are identified by their names.
Event Type
If, when the event type was specified it was identified by its name, the second element of the event message will be a character vector containing that name. If it was identified by its number, the second element of the event message will be an integer containing that number. If the event type was identified using the onEvent syntax, the second element of the event message will be a character vector containing the prefix 'on'
followed by the event name, even if it had been specified by number. The exception is that if the event is a user-defined event, the second element of the event message will be a character vector containing the prefix 'on'
followed by the character representation of the user-defined event number.
Specifying the Event property using Assignment
There are two ways to specify the Event property using assignment; you can specify the entire set of events, or you can set events one by one (see below).
To specify the entire set of events, you assign an array to the Event property. The array must contain one or more nested vectors, each containing 2 or 3 elements (Type, Action and optionally Arg) as described above.
Examples (F1
is a Form)
F1.Event ← 'onMouseDown' 'FOO'
Means: invoke callback function FOO
on MouseDown, the first element of the right argument to FOO
will contain a namespace reference to F1
. All other events perform their default actions.
F1.Event ← 'MouseDown' 'FOO'
Means: invoke callback function FOO
on MouseDown, the first element of the right argument to FOO
will contain the character vector'F1'
.
All other events perform their default actions.
F1.Event ← ('onMouseDown' 'FOO')('onMouseUp' 'FOO')
Means: invoke callback function FOO
on MouseDown and MouseUp. All other events perform their default actions.
F1.Event, ← ⊂ 'onMouseMove' 'FOO' ('THIS' 1)
Means: add a callback function FOO
on the MouseMove event. The function will receive the array ('THIS'1)
as its left argument. All other events
perform their default actions.
Specifying Individual Event types using Assignment
To define the action to be taken for individual events, one by one, you use the onEvent syntax and make the assignment to the event
name prefixed by the string 'on'
.
Examples
F1.onMouseDown ← 'FOO'
Means: invoke callback function FOO
on MouseDown.
F1.onMouseUp ← 'FOO'
Means: add the same callback for MouseUp.
F1.onMouseMove ← 'FOO' ('THIS' 1)
Means: add the same callback function FOO
for the MouseMove event. The function will receive the array ('THIS' 1)
as its left-argument.
Notice that you must use the 'on'
prefix; you cannot assign to the Event name itself. This would cause an error:
F1.MouseUp←'foo'
SYNTAX ERROR: Invalid modified assignment, or an attempt was made to change nameclass on assignment
F1.MouseUp←'foo'
∧
Specifying the Event property using ⎕WC
and ⎕WS
When you set the Event property using ⎕WC
and ⎕WS
you define the actions for the event types that you specify in the argument, leaving the actions for all other event types unchanged. When you create an object with ⎕WC
, all unspecified event types will be unhandled; that is, those events will perform the default processing. However, when you specify the action for a new event type using ⎕WS
, any actions previously defined for other event types will remain as they were.
Examples using Event Names
Ignore MouseDown (1) event (APL will perform the default processing for you)
'F1' ⎕WS 'Event' 'MouseDown' 0
Terminate ⎕DQ
on MouseDown
'F1' ⎕WS 'Event' 'MouseDown' 1
Invoke callback function FOO
on MouseDown, the first element of the right argument to FOO
will contain a namespace reference to F1
'F1' ⎕WS 'Event' 'onMouseDown' 'FOO'
Invoke callback function FOO
on MouseDown, the first element of the right argument to FOO
will contain the character vector 'F1'
'F1' ⎕WS 'Event' 'MouseDown' 'FOO'
Invoke callback function FOO
on MouseDown and MouseUp
'F1' ⎕WS 'Event' ('onMouseDown' 'onMouseUp') 'FOO'
Invoke callback function FOO
with ('THIS' 1)
as its left-argument on MouseDown
'F1' ⎕WS 'Event' 'onMouseDown' 'FOO' ('THIS' 1)
Invoke callback function FOO
with ('THIS' 1)
as its left-argument on MouseDown, MouseUp and MouseMove
EV ← 'onMouseDown' 'onMouseUp' 'onMouseMove'
'F1' ⎕WS 'Event' EV 'FOO' ('THIS' 1)
Execute the expression COUNT+←1
on MouseDown
'F1' ⎕WS 'Event' 'MouseDown' '⍎COUNT+←1'
Execute the expression COUNT+←1
on MouseDown, MouseUp and MouseMove
EV ← 'MouseDown' 'MouseUp' 'MouseMove'
'F1' ⎕WS 'Event' EV '⍎COUNT+←1'
Examples using Event Numbers
Ignore MouseDown (1) event (APL will perform the default processing for you)
'F1' ⎕WS 'Event' (1 0)
'F1' ⎕WS 'Event' 1 0 ⍝ Ditto
Terminate ⎕DQ
on MouseDown
'F1' ⎕WS 'Event' (1 1)
'F1' ⎕WS 'Event' 1 1 ⍝ Ditto
Call function FOO
on MouseDown
'F1' ⎕WS 'Event' (1 'FOO')
'F1' ⎕WS 'Event' 1 'FOO' ⍝ Ditto
Call function FOO
on MouseDown and MouseUp
'F1' ⎕WS 'Event' ((1 2) 'FOO')
'F1' ⎕WS 'Event' (1 2) 'FOO' ⍝ Ditto
'F1' ⎕WS 'Event' 1 2 'FOO' ⍝ Ditto
'F1' ⎕WS 'Event' (1 'FOO')(2 'FOO') ⍝ Ditto
Call function FOO
with ('THIS' 1)
as its left-argument on MouseDown
'F1' ⎕WS 'Event' (1 'FOO' ('THIS' 1))
'F1' ⎕WS 'Event' 1 'FOO' ('THIS' 1) ⍝ Ditto
Call function FOO
with ('THIS' 1)
as its left-argument on MouseDown and MouseUp
'F1' ⎕WS 'Event' ((1 2) 'FOO' ('THIS' 1))
'F1' ⎕WS 'Event' (1 2) 'FOO' ('THIS' 1) ⍝ Ditto
'F1' ⎕WS 'Event' 1 2 'FOO' ('THIS' 1) ⍝ Ditto
'F1' ⎕WS 'Event' 1 2 'FOO' ('THIS' 1) ⍝ Ditto
Execute the expression COUNT+←1
on MouseDown
'F1' ⎕WS 'Event' 1 '⍎COUNT+←1'
Execute the expression COUNT+←1
on MouseDown, MouseUp and MouseMove
'F1' ⎕WS 'Event' (1 2 3) '⍎COUNT+←1'
'F1' ⎕WS 'Event' 1 2 3 '⍎COUNT+←1' ⍝ Ditto
User defined Events
In addition to the standard events supported directly by Dyalog APL, you may specify your own events. For these, you must use event numbers; user-defined event names are not allowed.
You may use any numbers not already defined, but it is strongly recommended that you choose numbers greater than 1000 to avoid potential conflict with future releases of Dyalog APL.
You can only generate user-defined events under program control with ⎕NQ
.
Examples
∇ foo m
[1] ⎕SE.UCMD'display m'
∇
'f'⎕WC'Form' ('Event' 1001 'foo')
f.Event
1001 #.foo
⎕NQ 'f' 1001
┌→─────────┐
│ ┌→┐ │
│ │f│ 1001 │
│ └─┘ │
└∊─────────┘
'f' ⎕WS 'Event' 1002 'foo'
f.Event
1001 #.foo 1002 #.foo
⎕NQ 'f' 1002
┌→─────────┐
│ ┌→┐ │
│ │f│ 1002 │
│ └─┘ │
└∊─────────┘
Notice that if you use the onEvent syntax, the event property reports the event type as you specified, but the callback function receives just the number as before.
f.on1003←'foo'
f.Event
1001 #.foo 1002 #.foo on1003 #.foo
⎕NQ 'f' 1003
┌→─────────┐
│ #.f 1003│
└+─────────┘
Notes
Resetting (clearing) the Event Property
If no events are set, the result obtained by ⎕WG
and the result obtained by referencing Event directly are different:
'F'⎕WC'Form'
DISPLAY 'F'⎕WG'Event'
┌→──┐
│0 0│
└~──┘
DISPLAY F.Event
┌⊖────────────┐
│ ┌→────────┐ │
│ │ ┌⊖┐ ┌⊖┐ │ │
│ │ │ │ │ │ │ │
│ │ └─┘ └─┘ │ │
│ └∊────────┘ │
└∊────────────
To reset the Event property, the same (different) values must be used accordingly:
f.Event←0⍴⊂'' ''
or
'f'⎕ws'Event' 0 0
onEvent Syntax with Event Numbers
If you use the onEvent syntax with built-in event numbers, the effect is the same as if you had used the event name. This does not apply to user-defined events.
Example
'f'⎕WC'Form'
f.on2←'foo'
f.Event
onMouseUp #.foo
∇foo∇
∇ foo m
[1] ⎕SE.UCMD'display m'
∇
┌→──────────────────────────────────────────┐
│ ┌→──────┐ │
│ #.f │MouseUp│ 24.81481552 73.33333588 1 0 │
│ └───────┘ │
└∊──────────────────────────────────────────┘
This differs from the behaviour when you use event number normally:
'f'⎕WC'Form'
'f' ⎕ws 'Event' 2 'foo'
f.Event
2 #.foo
┌→──────────────────────────────────┐
│ ┌→┐ │
│ │f│ 2 52.77777863 13.22916698 1 0 │
│ └─┘ │
└∊──────────────────────────────────┘
Callback Names
When you query the Event property using ⎕WG
, names of callbacks associated with events are reported exactly as they were set. When you reference the Event property, the names are reported as absolute pathnames.
)ns x
#.x
)cs x
#.x
'f'⎕WC'form'
f.onMouseUp←'foo'
f.Event
┌───────────────────┐
│┌─────────┬───────┐│
││onMouseUp│#.x.foo││
│└─────────┴───────┘│
└───────────────────┘
'f'⎕wg'event'
┌───────────────┐
│┌─────────┬───┐│
││onMouseUp│foo││
│└─────────┴───┘│
└───────────────┘
)cs
#
#.x.f.Event
┌───────────────────┐
│┌─────────┬───────┐│
││onMouseUp│#.x.foo││
│└─────────┴───────┘│
└───────────────────┘
'#.x.f'⎕wg'Event'
┌─────────────────┐
│┌─────────┬─────┐│
││onMouseUp│x.foo││
│└─────────┴─────┘│
└─────────────────┘
Spelling Event Names
When using regular event names, case is unimportant. For example, the system will accept 'MouseUp'
, 'MOUSEUP'
or even 'mOuSeUp'
. When using the onEvent syntax, case is critical. The 'on'
must be in lower-case and the case of the event name must be spelled exactly as documented. In all cases, the event name will be reported using the documented spelling.
Special Case for All events
The event number 0 and the event name 'All'
,
are convenient shorthands to associate a particular action (such as a callback) with all the built-in events supported by an object.
Example
'f'⎕WC'Form' ('Event' 'All' 1)
f.Event
All 1
⎕←⎕DQ 'f'
f Create 1