Version 1 (modified by hopscc, 15 years ago) |
---|
Events
An event is a message sent by an object to signal the occurrence of an action.
The object that raises (triggers) the event is called the event sender or event source.
The object that receives the event and responds to it is called the event receiver or Listener
An event is declared with a type corresponding to a method signature (sig)
Objects that have an interest in the event register to listen to the event
(more specifically provide to the event a reference to one of their methods matching the
event signature).
When the event is raised (or fires) any and all objects that registered an interest in
the event (listeners) get their (registered) method called with the arguments provided
when raising the event.
Objects may unregister a prior interest in an event by subsequently ignoring the event
specifying the same method reference they previously listened with.
On these constructs decoupled notification and handling can be built.
All that is required is that an objects events of interest are exposed and
the signature of the events are known to interested parties
(or a registration interface is available) .
Grammar
# specify the signature of an event sig SIG_TYPENAME(ARGS) as TYPE # declare an event event EVENT_NAME as SIG_TYPENAME #register handler/listener method for an event listen EVENT_NAME, ref METHODNAME #unregister handler/listener for an event ignore EVENT_NAME, ref METHODNAME # raise/fire an event raise EVENT_NAME, [sender,] arg [, arg ...]
Platform
Examples
This (large) example does it all.
Declare Event arguments, declare signature and events
Raise events in response to something happening, define receivers/listeners that are
interested in the event ('something happening'), bind event senders and listeners together.
(FWIW its the C# example at Event Sample converted to cobra.)
namespace EventSample # Data for the alarm event. Derives from System.EventArgs. class AlarmEventArgs inherits EventArgs var __snoozePressed as bool #is private #,readonly var _nrings as int is private #,readonly cue init(snoozePressed as bool, nrings as int) base.init __snoozePressed = snoozePressed _nrings = nrings # number of rings that the alarm clock has sounded when the alarm event is generated. get numRings from _nrings # indicates whether the snooze button is pressed on the alarm when the alarm event is generated. get snoozePressed from __snoozePressed # alarmText property that contains the wake-up message. get alarmText return if(__snoozePressed, 'Wake Up!!! Snooze time is over.', 'Wake Up!') # Delegate declaration. sig AlarmEventHandler(sender as Object, e as AlarmEventArgs ) # The Alarm class that raises the alarm event. class AlarmClock var _snoozePressed = false is private var _nrings = 0i32 # int32 is private var _stop = false is private # The Stop property indicates whether the alarm should be turned off. pro stop from _stop # The SnoozePressed property indicates whether the snooze # button is pressed on the alarm when the alarm event is generated. pro snoozePressed from var # The event member that is of type AlarmEventHandler. event alarm as AlarmEventHandler # The protected OnAlarm method raises the event by invoking the delegate. # The sender is always .this, the current instance of the class. def onAlarm(e as AlarmEventArgs) is protected # Invokes the delegate. raise .alarm, e # Alarm clock does not have a user interface. # To simulate the alarm mechanism it has a loop that raises the alarm event at every iteration # with a time delay of 300 milliseconds, if snooze is not pressed. # If snooze is pressed, the time delay is 1000 milliseconds. def start while true _nrings += 1 if _stop break else if _snoozePressed System.Threading.Thread.sleep(1000) e = AlarmEventArgs(_snoozePressed, _nrings) .onAlarm(e) else System.Threading.Thread.sleep(300) e = AlarmEventArgs(_snoozePressed, _nrings) .onAlarm(e) # The WakeMeUp class that has a method AlarmRang that handles the alarm event. class WakeMeUp def alarmRang(sender as Object, e as AlarmEventArgs) print e.alarmText if not e.snoozePressed if e.numRings % 10 == 0 print ' Let alarm ring? Enter Y' print ' Press Snooze? Enter N' print ' Stop Alarm? Enter Q' input = Console.readLine if input.equals('Y') or input.equals('y') return else if input.equals('N') or input.equals('n') (sender to AlarmClock).snoozePressed = true return else (sender to AlarmClock).stop = true return else print ' Let alarm ring? Enter Y' print ' Stop Alarm? Enter Q' input = Console.readLine if input.equals('y') or input.equals('y') return else (sender to AlarmClock).stop = true return # The driver class that hooks up the event handling method of # WakeMeUp to the alarm event of an Alarm object using a delegate. class AlarmDriver def main is shared # args = CobraCore.commandLineArgs w = WakeMeUp() # Instantiates the event receiver. clock = AlarmClock() # Instantiates the event source. # Wires the AlarmRang method to the Alarm event. listen clock.alarm, ref w.alarmRang # clock.alarm += new AlarmEventHandler(w.AlarmRang) clock.start
Perhaps more commonly the sigs, events and senders are already defined (in a library or framework)
and we are only interested in registering for an event and reacting when the event is raised.
Heres an example of that around some GUI components:
The buttons and form have Keypress and MouseClick events and associated machinery already defined for them.
The example just sets up binding to the listener methods and 'does something' when the events fire
(print some of the args fields in this case).
%% args -target:exe use System.Windows.Forms use System.Drawing class MyForm inherits Form cue init base.init b = Button() b.text="press me" .controls.add(b) listen b.mouseClick, ref .handleMouseClick listen b.keyPress, ref .handleKey listen .keyPress, ref .handleKey def handleClick(sender as Object, args as EventArgs) m = args to MouseEventArgs print 'btn=[m.button]' print "Locn=[m.location]" print m def handleMouseClick(sender as Object, m as MouseEventArgs) print 'btn =[m.button]' print 'mb=[Control.mouseButtons]' print 'delta =[m.delta]' print 'clicks =[m.clicks]' print "Locn =[m.location]" print m def handleKey(sender as Object, kp as KeyPressEventArgs) print 'KeyPressed', 'key=', kp.keyChar class Program def main is shared has STAThread Application.run(MyForm())
Notes
With reference to C# nomenclature
- a cobra sig is roughly comparable to a C# delegate
- An event is an event in both
- 'wiring method to event' or 'instantiating an event delegate' is done in cobra via a listen statement
- 'Invoking a delegate' is done in cobra via the raise statement.
Declaration/execution flow is
sig - event - listen - raise - (ignore)
See Also
Handling and raising events in .Net Framework Developers Guide