Event handlers
Event handlers are another mechanism used to inform the application of input actions by the user. While callbacks notify the application of high level interactions such as the selection of items in a list widget, event handlers notify the application of low level interactions, including the following:
Mouse pointer motion
Mouse button presses and releases
Individual key presses and releases
There are two common uses of event handlers. The first is for handling input in a drawing area widget. For example, in a graphical drawing application a drawing area widget would be used to display the drawing under construction. Event handlers would be registered to notify the application of pointer motion, mouse button, and key press events, allowing text strings to be edited and graphical objects to be positioned and changed using the mouse.
The second common use is for handling pop-up menus. An event handler is added for the ButtonMenuMask event. When the event handler is called, the application pops the menu up.
Mouse button 3 is used as the menu button. However, some platforms trigger the button menu event when the button is pressed, and others when the button is released. The ButtonMenuMask event hides this difference. It should be used, rather than the other button events, to support pop-up menus in a platform-independent manner.
*On some platforms it is possible for a button release event to be delivered without a corresponding button press event. Applications should be prepared to ignore such spurious button release events by only processing a button release event that is received after a matching button press event.
Registering an Event
Register event handlers using the addEventHandler:receiver:selector:clientData: method.
*The argBlock argument of a widget-creation message can only be used to set widget resources. The addEventHandler: message cannot be used within the create argBlock. Event handlers are usually registered immediately after the widget has been created, and before it is realized.
The addEventHandler:receiver:selector:clientData: method takes four parameters:
A bit mask specifying which events to notify the receiver of
The object that receives the event handler message
The 3-parameter event handler message selector
Optional data that is passed to the event handler when it is run
The eventMask is specified as the bitwise-OR of one or more of the bit masks described in the following table.
Table 34. Common widgets event masks
Event masks
Keyboard key down events
Keyboard key up events
Mouse button down events
Mouse button up events
All pointer motion events
Pointer motion events while button 1 is down
Pointer motion events while button 2 is down
Pointer motion events while button 3 is down
Pointer motion events while any button is down
Button menu request events
Running an Event
When an event handler method is run, it is passed three arguments:
The widget to which the handler was added and in which the event occurred
The client data specified when the event handler was registered
An object describing the event, called the event
The following table describes the class hierarchy for event objects. Classes in italics are abstract classes.
Table 35. Event class hierarchy
Class hierarchy
Defines common behavior for event data in event handlers.
Provides event data for expose events in expose callbacks (see Note below).
Defines common behavior for button, key, and motion event objects.
Provides event data for mouse button-press/release events.
Provides event data for key-press/release events.
Provides event data for mouse motion events.
*An expose event handler cannot be explicitly added to a widget. A CwExposeEvent object is passed to an application as part of the call data for an exposeCallback.
The following messages can be sent to the event object to retrieve information about the event. The methods for all events (CwEvent) include the following:
The type of event that occurred. This has one of the following values: ButtonPress, ButtonRelease, Expose, KeyPress, KeyRelease, and MotionNotify.
The CgWindow associated with the widget for which the event was generated.
The CgDisplay associated with the event.
For expose events (CwExposeEvent), the method include the following:
The number of expose events which remain for the affected CgWindow. A simple application might want to ignore all expose events with a nonzero count, and perform a full redisplay if the count is zero.
A rectangle describing the damaged area, in the coordinate system of the affected CgWindow.
The x-coordinate of the origin of the damaged rectangle.
The y-coordinate of the origin of the damaged rectangle.
The height, in pixels, of the damaged rectangle.
The width, in pixels, of the damaged rectangle.
For input events (CwButtonEvent, CwKeyEvent, and CwMotionEvent), the methods are as follows:
A bit mask representing the logical state of modifier keys and pointer buttons just prior to the event. Possible bit masks include: ControlMask, ShiftMask, LockMask, Mod1Mask to Mod5Mask, and Button1Mask to Button3Mask.
The x-coordinate of the pointer, relative to the widget in which the event occurred.
The y-coordinate of the pointer, relative to the widget in which the event occurred.
x @ y
A coordinate of the pointer, relative to the screen.
A coordinate of the pointer, relative to the screen.
xRoot @ yRoot
The time, in milliseconds, at which the event occurred.
For mouse button events (CwButtonEvent), the methods are as follows:
The number of the button that was pressed or released (1, 2 or 3).
For key events (CwKeyEvent), the methods are as follows:
A constant describing the keyboard key that was pressed or released. These constants are found in the e CwConstants pool dictionary, and are prefixed with 'XK.'
The Character describing the keyboard key that was pressed or released, or nil if it does not represent a valid character.
In the following example, a drawing area is created, and an event handler is added to notify the application of mouse button presses, key presses, and pointer motion. Label widgets are used to display information about the events. The variable labels would be implemented as an instance variable for the class.
| shell rowColumn label labels drawing |
shell := CwTopLevelShell
createApplicationShell: 'shell'
argBlock: [:w | w title: 'Event Handler Example'].
rowColumn := shell
createRowColumn: 'rowColumn'
argBlock: nil.
rowColumn manageChild.
labels := Array new: 3.
1 to: 3 do: [:i |
label := rowColumn
createLabel: 'label'
argBlock: nil.
label manageChild.
labels at: i put: label].
(labels at: 1) labelString: 'Position: '.
(labels at: 2) labelString: 'Button pressed at position: '.
(labels at: 3) labelString: 'Keysym of last pressed key: '.
drawing := rowColumn
createDrawingArea: 'drawing'
argBlock: [:w |
borderWidth: 1;
width: 300;
height: 300].
addEventHandler: ButtonPressMask | KeyPressMask | PointerMotionMask
receiver: self
selector: #eventHandler:clientData:event:
clientData: labels.
drawing manageChild.
shell realizeWidget
When an event occurs, the following method is run. Information about the event is determined from the event argument and is displayed in the label widgets.
eventHandler: widget clientData: clientData event: event
"Handle an input event."
| labels |
labels := clientData.
event type = MotionNotify
ifTrue: [(labels at: 1) labelString: 'Position: ',
event point printString].
event type = ButtonPress
ifTrue: [(labels at: 2) labelString: 'Button ', event
button printString, ' pressed at position: ',
event point printString].
event type = KeyPress
ifTrue: [(labels at: 3) labelString: 'Keysym of last pressed key: ',
event keysym printString].
Last modified date: 04/20/2020